Merge "Program offload-exempt local prefixes into the HAL" into oc-dr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
aa7b8b5322
@@ -57,6 +57,7 @@ import android.net.NetworkRequest;
|
||||
import android.net.NetworkState;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.util.PrefixUtils;
|
||||
import android.net.util.SharedLog;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Binder;
|
||||
@@ -216,10 +217,10 @@ public class Tethering extends BaseNetworkObserver {
|
||||
mContext.getContentResolver(),
|
||||
mLog);
|
||||
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
|
||||
mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK );
|
||||
mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
|
||||
mForwardedDownstreams = new HashSet<>();
|
||||
mSimChange = new SimChangeListener(
|
||||
mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning());
|
||||
mContext, smHandler, () -> reevaluateSimCardProvisioning());
|
||||
|
||||
mStateReceiver = new StateReceiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
@@ -227,13 +228,13 @@ public class Tethering extends BaseNetworkObserver {
|
||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
||||
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
|
||||
mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
|
||||
|
||||
filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_MEDIA_SHARED);
|
||||
filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
|
||||
filter.addDataScheme("file");
|
||||
mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
|
||||
mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
|
||||
|
||||
// load device config info
|
||||
updateConfiguration();
|
||||
@@ -1142,12 +1143,6 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
}
|
||||
|
||||
private void startOffloadController() {
|
||||
mOffloadController.start();
|
||||
mOffloadController.updateExemptPrefixes(
|
||||
mUpstreamNetworkMonitor.getOffloadExemptPrefixes());
|
||||
}
|
||||
|
||||
class TetherMasterSM extends StateMachine {
|
||||
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
|
||||
// an interface SM has requested Tethering/Local Hotspot
|
||||
@@ -1165,14 +1160,14 @@ public class Tethering extends BaseNetworkObserver {
|
||||
static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
|
||||
static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7;
|
||||
|
||||
private State mInitialState;
|
||||
private State mTetherModeAliveState;
|
||||
private final State mInitialState;
|
||||
private final State mTetherModeAliveState;
|
||||
|
||||
private State mSetIpForwardingEnabledErrorState;
|
||||
private State mSetIpForwardingDisabledErrorState;
|
||||
private State mStartTetheringErrorState;
|
||||
private State mStopTetheringErrorState;
|
||||
private State mSetDnsForwardersErrorState;
|
||||
private final State mSetIpForwardingEnabledErrorState;
|
||||
private final State mSetIpForwardingDisabledErrorState;
|
||||
private final State mStartTetheringErrorState;
|
||||
private final State mStopTetheringErrorState;
|
||||
private final State mSetDnsForwardersErrorState;
|
||||
|
||||
// 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
|
||||
@@ -1212,22 +1207,46 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
mNotifyList = new ArrayList<>();
|
||||
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
|
||||
|
||||
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 {
|
||||
@Override
|
||||
public boolean processMessage(Message message) {
|
||||
logMessage(this, message.what);
|
||||
switch (message.what) {
|
||||
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);
|
||||
handleInterfaceServingStateActive(message.arg1, who);
|
||||
transitionTo(mTetherModeAliveState);
|
||||
break;
|
||||
case EVENT_IFACE_SERVING_STATE_INACTIVE:
|
||||
who = (TetherInterfaceStateMachine)message.obj;
|
||||
who = (TetherInterfaceStateMachine) message.obj;
|
||||
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
|
||||
handleInterfaceServingStateInactive(who);
|
||||
break;
|
||||
@@ -1422,8 +1441,8 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
|
||||
private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
|
||||
if (arg1 == UpstreamNetworkMonitor.NOTIFY_EXEMPT_PREFIXES) {
|
||||
mOffloadController.updateExemptPrefixes((Set<IpPrefix>) o);
|
||||
if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
|
||||
sendOffloadExemptPrefixes((Set<IpPrefix>) o);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1527,7 +1546,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
boolean retValue = true;
|
||||
switch (message.what) {
|
||||
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);
|
||||
handleInterfaceServingStateActive(message.arg1, who);
|
||||
who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
|
||||
@@ -1541,7 +1560,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
break;
|
||||
}
|
||||
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);
|
||||
handleInterfaceServingStateInactive(who);
|
||||
|
||||
@@ -1573,6 +1592,9 @@ public class Tethering extends BaseNetworkObserver {
|
||||
mOffloadController.notifyDownstreamLinkProperties(newLp);
|
||||
} else {
|
||||
mOffloadController.removeDownstreamInterface(newLp.getInterfaceName());
|
||||
// Another interface might be in local-only hotspot mode;
|
||||
// resend all local prefixes to the OffloadController.
|
||||
sendOffloadExemptPrefixes();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1614,7 +1636,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
boolean retValue = true;
|
||||
switch (message.what) {
|
||||
case EVENT_IFACE_SERVING_STATE_ACTIVE:
|
||||
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
|
||||
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
|
||||
who.sendMessage(mErrorNotification);
|
||||
break;
|
||||
case CMD_CLEAR_ERROR:
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.util.SharedLog;
|
||||
@@ -27,8 +28,11 @@ import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -47,7 +51,13 @@ public class OffloadController {
|
||||
private boolean mConfigInitialized;
|
||||
private boolean mControlInitialized;
|
||||
private LinkProperties mUpstreamLinkProperties;
|
||||
// The complete set of offload-exempt prefixes passed in via Tethering from
|
||||
// all upstream and downstream sources.
|
||||
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,
|
||||
ContentResolver contentResolver, SharedLog log) {
|
||||
@@ -55,6 +65,8 @@ public class OffloadController {
|
||||
mHwInterface = hwi;
|
||||
mContentResolver = contentResolver;
|
||||
mLog = log.forSubComponent(TAG);
|
||||
mExemptPrefixes = new HashSet<>();
|
||||
mLastLocalPrefixStrs = new HashSet<>();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
@@ -134,25 +146,22 @@ public class OffloadController {
|
||||
}
|
||||
|
||||
public void setUpstreamLinkProperties(LinkProperties lp) {
|
||||
if (!started()) return;
|
||||
if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
|
||||
|
||||
mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
|
||||
// TODO: examine return code and decide what to do if programming
|
||||
// upstream parameters fails (probably just wait for a subsequent
|
||||
// onOffloadEvent() callback to tell us offload is available again and
|
||||
// then reapply all state).
|
||||
computeAndPushLocalPrefixes();
|
||||
pushUpstreamParameters();
|
||||
}
|
||||
|
||||
public void updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) {
|
||||
public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
|
||||
if (!started()) return;
|
||||
|
||||
mExemptPrefixes = exemptPrefixes;
|
||||
// TODO:
|
||||
// - 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
|
||||
mExemptPrefixes = localPrefixes;
|
||||
computeAndPushLocalPrefixes();
|
||||
}
|
||||
|
||||
public void notifyDownstreamLinkProperties(LinkProperties lp) {
|
||||
@@ -215,4 +224,42 @@ public class OffloadController {
|
||||
return mHwInterface.setUpstreamParameters(
|
||||
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;
|
||||
}
|
||||
|
||||
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(
|
||||
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
|
||||
iface = (iface != null) ? iface : NO_INTERFACE_NAME;
|
||||
|
||||
@@ -161,6 +161,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
|
||||
public int lastError() { return mLastError; }
|
||||
|
||||
public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
|
||||
|
||||
public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
|
||||
|
||||
public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.NetworkState;
|
||||
import android.net.util.NetworkConstants;
|
||||
import android.net.util.PrefixUtils;
|
||||
import android.net.util.SharedLog;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -72,16 +73,11 @@ public class UpstreamNetworkMonitor {
|
||||
private static final boolean DBG = 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_CAPABILITIES = 2;
|
||||
public static final int EVENT_ON_LINKPROPERTIES = 3;
|
||||
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_TRACK_DEFAULT = 2;
|
||||
@@ -93,7 +89,7 @@ public class UpstreamNetworkMonitor {
|
||||
private final Handler mHandler;
|
||||
private final int mWhat;
|
||||
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
|
||||
private HashSet<IpPrefix> mOffloadExemptPrefixes;
|
||||
private HashSet<IpPrefix> mLocalPrefixes;
|
||||
private ConnectivityManager mCM;
|
||||
private NetworkCallback mListenAllCallback;
|
||||
private NetworkCallback mDefaultNetworkCallback;
|
||||
@@ -107,7 +103,7 @@ public class UpstreamNetworkMonitor {
|
||||
mHandler = mTarget.getHandler();
|
||||
mLog = log.forSubComponent(TAG);
|
||||
mWhat = what;
|
||||
mOffloadExemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
|
||||
mLocalPrefixes = new HashSet<>();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -223,8 +219,8 @@ public class UpstreamNetworkMonitor {
|
||||
return typeStatePair.ns;
|
||||
}
|
||||
|
||||
public Set<IpPrefix> getOffloadExemptPrefixes() {
|
||||
return (Set<IpPrefix>) mOffloadExemptPrefixes.clone();
|
||||
public Set<IpPrefix> getLocalPrefixes() {
|
||||
return (Set<IpPrefix>) mLocalPrefixes.clone();
|
||||
}
|
||||
|
||||
private void handleAvailable(int callbackType, Network network) {
|
||||
@@ -360,11 +356,11 @@ public class UpstreamNetworkMonitor {
|
||||
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
|
||||
}
|
||||
|
||||
private void recomputeOffloadExemptPrefixes() {
|
||||
final HashSet<IpPrefix> exemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
|
||||
if (!mOffloadExemptPrefixes.equals(exemptPrefixes)) {
|
||||
mOffloadExemptPrefixes = exemptPrefixes;
|
||||
notifyTarget(NOTIFY_EXEMPT_PREFIXES, exemptPrefixes.clone());
|
||||
private void recomputeLocalPrefixes() {
|
||||
final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
|
||||
if (!mLocalPrefixes.equals(localPrefixes)) {
|
||||
mLocalPrefixes = localPrefixes;
|
||||
notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +398,7 @@ public class UpstreamNetworkMonitor {
|
||||
@Override
|
||||
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
|
||||
handleLinkProp(network, newLp);
|
||||
recomputeOffloadExemptPrefixes();
|
||||
recomputeLocalPrefixes();
|
||||
}
|
||||
|
||||
// TODO: Handle onNetworkSuspended();
|
||||
@@ -411,7 +407,7 @@ public class UpstreamNetworkMonitor {
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
handleLost(mCallbackType, network);
|
||||
recomputeOffloadExemptPrefixes();
|
||||
recomputeLocalPrefixes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,35 +456,15 @@ public class UpstreamNetworkMonitor {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static HashSet<IpPrefix> allOffloadExemptPrefixes(Iterable<NetworkState> netStates) {
|
||||
private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) {
|
||||
final HashSet<IpPrefix> prefixSet = new HashSet<>();
|
||||
|
||||
addDefaultLocalPrefixes(prefixSet);
|
||||
|
||||
for (NetworkState ns : netStates) {
|
||||
addOffloadExemptPrefixes(prefixSet, ns.linkProperties);
|
||||
final LinkProperties lp = ns.linkProperties;
|
||||
if (lp == null) continue;
|
||||
prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
|
||||
}
|
||||
|
||||
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.pm.ApplicationInfo;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.RouteInfo;
|
||||
@@ -45,6 +46,8 @@ import com.android.internal.util.test.FakeSettingsProvider;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -182,17 +185,43 @@ public class OffloadControllerTest {
|
||||
any(OffloadHardwareInterface.ControlCallback.class));
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
offload.setUpstreamLinkProperties(null);
|
||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||
eq(null), eq(null), eq(null), eq(null));
|
||||
// In reality, the UpstreamNetworkMonitor would have passed down to us
|
||||
// a covering set of local prefixes representing a minimum essential
|
||||
// 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();
|
||||
reset(mHardware);
|
||||
|
||||
final LinkProperties lp = new LinkProperties();
|
||||
|
||||
final String testIfName = "rmnet_data17";
|
||||
lp.setInterfaceName(testIfName);
|
||||
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(
|
||||
eq(testIfName), eq(null), eq(null), eq(null));
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
@@ -200,7 +229,15 @@ public class OffloadControllerTest {
|
||||
final String ipv4Addr = "192.0.2.5";
|
||||
final String linkAddr = ipv4Addr + "/24";
|
||||
lp.addLinkAddress(new LinkAddress(linkAddr));
|
||||
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24")));
|
||||
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(
|
||||
eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
@@ -208,6 +245,8 @@ public class OffloadControllerTest {
|
||||
final String ipv4Gateway = "192.0.2.1";
|
||||
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
|
||||
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(
|
||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
@@ -215,6 +254,8 @@ public class OffloadControllerTest {
|
||||
final String ipv6Gw1 = "fe80::cafe";
|
||||
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
|
||||
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(
|
||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
||||
ArrayList<String> v6gws = mStringArrayCaptor.getValue();
|
||||
@@ -225,6 +266,8 @@ public class OffloadControllerTest {
|
||||
final String ipv6Gw2 = "fe80::d00d";
|
||||
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
|
||||
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(
|
||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
||||
v6gws = mStringArrayCaptor.getValue();
|
||||
@@ -240,6 +283,8 @@ public class OffloadControllerTest {
|
||||
stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
|
||||
assertTrue(lp.addStackedLink(stacked));
|
||||
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(
|
||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
||||
v6gws = mStringArrayCaptor.getValue();
|
||||
@@ -247,5 +292,43 @@ public class OffloadControllerTest {
|
||||
assertTrue(v6gws.contains(ipv6Gw1));
|
||||
assertTrue(v6gws.contains(ipv6Gw2));
|
||||
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
|
||||
public void testOffloadExemptPrefixes() throws Exception {
|
||||
public void testLocalPrefixes() throws Exception {
|
||||
mUNM.start();
|
||||
|
||||
// [0] Test minimum set of exempt prefixes.
|
||||
Set<IpPrefix> exempt = mUNM.getOffloadExemptPrefixes();
|
||||
final String[] MINSET = {
|
||||
"127.0.0.0/8", "169.254.0.0/16",
|
||||
"::/3", "fe80::/64", "fc00::/7", "ff00::/8",
|
||||
};
|
||||
assertPrefixSet(exempt, INCLUDES, MINSET);
|
||||
// [0] Test minimum set of local prefixes.
|
||||
Set<IpPrefix> local = mUNM.getLocalPrefixes();
|
||||
assertTrue(local.isEmpty());
|
||||
|
||||
final Set<String> alreadySeen = new HashSet<>();
|
||||
Collections.addAll(alreadySeen, MINSET);
|
||||
assertEquals(alreadySeen.size(), exempt.size());
|
||||
|
||||
// [1] Pretend Wi-Fi connects.
|
||||
final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
|
||||
@@ -355,15 +350,15 @@ public class UpstreamNetworkMonitorTest {
|
||||
wifiAgent.fakeConnect();
|
||||
wifiAgent.sendLinkProperties(wifiLp);
|
||||
|
||||
exempt = mUNM.getOffloadExemptPrefixes();
|
||||
assertPrefixSet(exempt, INCLUDES, alreadySeen);
|
||||
local = mUNM.getLocalPrefixes();
|
||||
assertPrefixSet(local, INCLUDES, alreadySeen);
|
||||
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",
|
||||
};
|
||||
assertPrefixSet(exempt, INCLUDES, wifiLinkPrefixes);
|
||||
assertPrefixSet(local, INCLUDES, wifiLinkPrefixes);
|
||||
Collections.addAll(alreadySeen, wifiLinkPrefixes);
|
||||
assertEquals(alreadySeen.size(), exempt.size());
|
||||
assertEquals(alreadySeen.size(), local.size());
|
||||
|
||||
// [2] Pretend mobile connects.
|
||||
final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
|
||||
@@ -379,12 +374,12 @@ public class UpstreamNetworkMonitorTest {
|
||||
cellAgent.fakeConnect();
|
||||
cellAgent.sendLinkProperties(cellLp);
|
||||
|
||||
exempt = mUNM.getOffloadExemptPrefixes();
|
||||
assertPrefixSet(exempt, INCLUDES, alreadySeen);
|
||||
local = mUNM.getLocalPrefixes();
|
||||
assertPrefixSet(local, INCLUDES, alreadySeen);
|
||||
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);
|
||||
assertEquals(alreadySeen.size(), exempt.size());
|
||||
assertEquals(alreadySeen.size(), local.size());
|
||||
|
||||
// [3] Pretend DUN connects.
|
||||
final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
|
||||
@@ -401,21 +396,20 @@ public class UpstreamNetworkMonitorTest {
|
||||
dunAgent.fakeConnect();
|
||||
dunAgent.sendLinkProperties(dunLp);
|
||||
|
||||
exempt = mUNM.getOffloadExemptPrefixes();
|
||||
assertPrefixSet(exempt, INCLUDES, alreadySeen);
|
||||
local = mUNM.getLocalPrefixes();
|
||||
assertPrefixSet(local, INCLUDES, alreadySeen);
|
||||
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);
|
||||
assertEquals(alreadySeen.size(), exempt.size());
|
||||
assertEquals(alreadySeen.size(), local.size());
|
||||
|
||||
// [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no
|
||||
// longer be included (should be properly removed).
|
||||
wifiAgent.fakeDisconnect();
|
||||
exempt = mUNM.getOffloadExemptPrefixes();
|
||||
assertPrefixSet(exempt, INCLUDES, MINSET);
|
||||
assertPrefixSet(exempt, EXCLUDES, wifiLinkPrefixes);
|
||||
assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
|
||||
assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
|
||||
local = mUNM.getLocalPrefixes();
|
||||
assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes);
|
||||
assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
|
||||
assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
|
||||
}
|
||||
|
||||
private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {
|
||||
|
||||
Reference in New Issue
Block a user