Merge "Send add/removeDownstream info to offload HAL" into oc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
568cd41216
@@ -49,6 +49,7 @@ import android.net.ConnectivityManager;
|
||||
import android.net.INetworkPolicyManager;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
@@ -1196,6 +1197,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
// to tear itself down.
|
||||
private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
|
||||
private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
|
||||
private final OffloadWrapper mOffload;
|
||||
|
||||
private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
|
||||
|
||||
@@ -1220,33 +1222,11 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
mNotifyList = new ArrayList<>();
|
||||
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
|
||||
mOffload = new OffloadWrapper();
|
||||
|
||||
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) {
|
||||
@@ -1404,7 +1384,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
protected void handleNewUpstreamNetworkState(NetworkState ns) {
|
||||
mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
|
||||
mOffloadController.setUpstreamLinkProperties((ns != null) ? ns.linkProperties : null);
|
||||
mOffload.updateUpstreamNetworkState(ns);
|
||||
}
|
||||
|
||||
private void handleInterfaceServingStateActive(int mode, TetherInterfaceStateMachine who) {
|
||||
@@ -1414,9 +1394,12 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
|
||||
if (mode == IControlsTethering.STATE_TETHERED) {
|
||||
// No need to notify OffloadController just yet as there are no
|
||||
// "offload-able" prefixes to pass along. This will handled
|
||||
// when the TISM informs Tethering of its LinkProperties.
|
||||
mForwardedDownstreams.add(who);
|
||||
} else {
|
||||
mOffloadController.removeDownstreamInterface(who.interfaceName());
|
||||
mOffload.excludeDownstreamInterface(who.interfaceName());
|
||||
mForwardedDownstreams.remove(who);
|
||||
}
|
||||
|
||||
@@ -1441,7 +1424,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
|
||||
mNotifyList.remove(who);
|
||||
mIPv6TetheringCoordinator.removeActiveDownstream(who);
|
||||
mOffloadController.removeDownstreamInterface(who.interfaceName());
|
||||
mOffload.excludeDownstreamInterface(who.interfaceName());
|
||||
mForwardedDownstreams.remove(who);
|
||||
|
||||
// If this is a Wi-Fi interface, tell WifiManager of any errors.
|
||||
@@ -1455,7 +1438,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
|
||||
if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
|
||||
sendOffloadExemptPrefixes((Set<IpPrefix>) o);
|
||||
mOffload.sendOffloadExemptPrefixes((Set<IpPrefix>) o);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1525,7 +1508,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
// TODO: De-duplicate with updateUpstreamWanted() below.
|
||||
if (upstreamWanted()) {
|
||||
mUpstreamWanted = true;
|
||||
startOffloadController();
|
||||
mOffload.start();
|
||||
chooseUpstreamType(true);
|
||||
mTryCell = false;
|
||||
}
|
||||
@@ -1533,7 +1516,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
@Override
|
||||
public void exit() {
|
||||
mOffloadController.stop();
|
||||
mOffload.stop();
|
||||
mUpstreamNetworkMonitor.stop();
|
||||
mSimChange.stopListening();
|
||||
notifyDownstreamsOfNewUpstreamIface(null);
|
||||
@@ -1545,9 +1528,9 @@ public class Tethering extends BaseNetworkObserver {
|
||||
mUpstreamWanted = upstreamWanted();
|
||||
if (mUpstreamWanted != previousUpstreamWanted) {
|
||||
if (mUpstreamWanted) {
|
||||
startOffloadController();
|
||||
mOffload.start();
|
||||
} else {
|
||||
mOffloadController.stop();
|
||||
mOffload.stop();
|
||||
}
|
||||
}
|
||||
return previousUpstreamWanted;
|
||||
@@ -1602,12 +1585,9 @@ public class Tethering extends BaseNetworkObserver {
|
||||
case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
|
||||
final LinkProperties newLp = (LinkProperties) message.obj;
|
||||
if (message.arg1 == IControlsTethering.STATE_TETHERED) {
|
||||
mOffloadController.notifyDownstreamLinkProperties(newLp);
|
||||
mOffload.updateDownstreamLinkProperties(newLp);
|
||||
} else {
|
||||
mOffloadController.removeDownstreamInterface(newLp.getInterfaceName());
|
||||
// Another interface might be in local-only hotspot mode;
|
||||
// resend all local prefixes to the OffloadController.
|
||||
sendOffloadExemptPrefixes();
|
||||
mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1722,6 +1702,82 @@ public class Tethering extends BaseNetworkObserver {
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper class to handle multiple situations where several calls to
|
||||
// the OffloadController need to happen together.
|
||||
//
|
||||
// TODO: This suggests that the interface between OffloadController and
|
||||
// Tethering is in need of improvement. Refactor these calls into the
|
||||
// OffloadController implementation.
|
||||
class OffloadWrapper {
|
||||
public void start() {
|
||||
mOffloadController.start();
|
||||
sendOffloadExemptPrefixes();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
mOffloadController.stop();
|
||||
}
|
||||
|
||||
public void updateUpstreamNetworkState(NetworkState ns) {
|
||||
mOffloadController.setUpstreamLinkProperties(
|
||||
(ns != null) ? ns.linkProperties : null);
|
||||
}
|
||||
|
||||
public void updateDownstreamLinkProperties(LinkProperties newLp) {
|
||||
// Update the list of offload-exempt prefixes before adding
|
||||
// new prefixes on downstream interfaces to the offload HAL.
|
||||
sendOffloadExemptPrefixes();
|
||||
mOffloadController.notifyDownstreamLinkProperties(newLp);
|
||||
}
|
||||
|
||||
public void excludeDownstreamInterface(String ifname) {
|
||||
// This and other interfaces may be in local-only hotspot mode;
|
||||
// resend all local prefixes to the OffloadController.
|
||||
sendOffloadExemptPrefixes();
|
||||
mOffloadController.removeDownstreamInterface(ifname);
|
||||
}
|
||||
|
||||
public void sendOffloadExemptPrefixes() {
|
||||
sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes());
|
||||
}
|
||||
|
||||
public void sendOffloadExemptPrefixes(final Set<IpPrefix> localPrefixes) {
|
||||
// Add in well-known minimum set.
|
||||
PrefixUtils.addNonForwardablePrefixes(localPrefixes);
|
||||
// Add tragically hardcoded prefixes.
|
||||
localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX);
|
||||
|
||||
// Maybe add prefixes or addresses for downstreams, depending on
|
||||
// the IP serving mode of each.
|
||||
for (TetherInterfaceStateMachine tism : mNotifyList) {
|
||||
final LinkProperties lp = tism.linkProperties();
|
||||
|
||||
switch (tism.servingMode()) {
|
||||
case IControlsTethering.STATE_UNAVAILABLE:
|
||||
case IControlsTethering.STATE_AVAILABLE:
|
||||
// No usable LinkProperties in these states.
|
||||
continue;
|
||||
case IControlsTethering.STATE_TETHERED:
|
||||
// Only add IPv4 /32 and IPv6 /128 prefixes. The
|
||||
// directly-connected prefixes will be sent as
|
||||
// downstream "offload-able" prefixes.
|
||||
for (LinkAddress addr : lp.getAllLinkAddresses()) {
|
||||
final InetAddress ip = addr.getAddress();
|
||||
if (ip.isLinkLocalAddress()) continue;
|
||||
localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
|
||||
}
|
||||
break;
|
||||
case IControlsTethering.STATE_LOCAL_ONLY:
|
||||
// Add prefixes covering all local IPs.
|
||||
localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mOffloadController.setLocalPrefixes(localPrefixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,6 +48,7 @@ import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -69,6 +70,7 @@ public class OffloadController {
|
||||
private final INetworkManagementService mNms;
|
||||
private final ITetheringStatsProvider mStatsProvider;
|
||||
private final SharedLog mLog;
|
||||
private final HashMap<String, LinkProperties> mDownstreams;
|
||||
private boolean mConfigInitialized;
|
||||
private boolean mControlInitialized;
|
||||
private LinkProperties mUpstreamLinkProperties;
|
||||
@@ -100,6 +102,7 @@ public class OffloadController {
|
||||
mNms = nms;
|
||||
mStatsProvider = new OffloadTetheringStatsProvider();
|
||||
mLog = log.forSubComponent(TAG);
|
||||
mDownstreams = new HashMap<>();
|
||||
mExemptPrefixes = new HashSet<>();
|
||||
mLastLocalPrefixStrs = new HashSet<>();
|
||||
|
||||
@@ -257,6 +260,11 @@ public class OffloadController {
|
||||
}
|
||||
}
|
||||
|
||||
private String currentUpstreamInterface() {
|
||||
return (mUpstreamLinkProperties != null)
|
||||
? mUpstreamLinkProperties.getInterfaceName() : null;
|
||||
}
|
||||
|
||||
private void maybeUpdateStats(String iface) {
|
||||
if (TextUtils.isEmpty(iface)) {
|
||||
return;
|
||||
@@ -281,9 +289,7 @@ public class OffloadController {
|
||||
|
||||
private boolean maybeUpdateDataLimit(String iface) {
|
||||
// setDataLimit may only be called while offload is occuring on this upstream.
|
||||
if (!started() ||
|
||||
mUpstreamLinkProperties == null ||
|
||||
!TextUtils.equals(iface, mUpstreamLinkProperties.getInterfaceName())) {
|
||||
if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -296,9 +302,7 @@ public class OffloadController {
|
||||
}
|
||||
|
||||
private void updateStatsForCurrentUpstream() {
|
||||
if (mUpstreamLinkProperties != null) {
|
||||
maybeUpdateStats(mUpstreamLinkProperties.getInterfaceName());
|
||||
}
|
||||
maybeUpdateStats(currentUpstreamInterface());
|
||||
}
|
||||
|
||||
public void setUpstreamLinkProperties(LinkProperties lp) {
|
||||
@@ -325,17 +329,42 @@ public class OffloadController {
|
||||
}
|
||||
|
||||
public void notifyDownstreamLinkProperties(LinkProperties lp) {
|
||||
final String ifname = lp.getInterfaceName();
|
||||
final LinkProperties oldLp = mDownstreams.put(ifname, new LinkProperties(lp));
|
||||
if (Objects.equals(oldLp, lp)) return;
|
||||
|
||||
if (!started()) return;
|
||||
|
||||
// TODO: Cache LinkProperties on a per-ifname basis and compute the
|
||||
// deltas, calling addDownstream()/removeDownstream() accordingly.
|
||||
final List<RouteInfo> oldRoutes = (oldLp != null) ? oldLp.getRoutes() : new ArrayList<>();
|
||||
final List<RouteInfo> newRoutes = lp.getRoutes();
|
||||
|
||||
// For each old route, if not in new routes: remove.
|
||||
for (RouteInfo oldRoute : oldRoutes) {
|
||||
if (shouldIgnoreDownstreamRoute(oldRoute)) continue;
|
||||
if (!newRoutes.contains(oldRoute)) {
|
||||
mHwInterface.removeDownstreamPrefix(ifname, oldRoute.getDestination().toString());
|
||||
}
|
||||
}
|
||||
|
||||
// For each new route, if not in old routes: add.
|
||||
for (RouteInfo newRoute : newRoutes) {
|
||||
if (shouldIgnoreDownstreamRoute(newRoute)) continue;
|
||||
if (!oldRoutes.contains(newRoute)) {
|
||||
mHwInterface.addDownstreamPrefix(ifname, newRoute.getDestination().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDownstreamInterface(String ifname) {
|
||||
final LinkProperties lp = mDownstreams.remove(ifname);
|
||||
if (lp == null) return;
|
||||
|
||||
if (!started()) return;
|
||||
|
||||
// TODO: Check cache for LinkProperties of ifname and, if present,
|
||||
// call removeDownstream() accordingly.
|
||||
for (RouteInfo route : lp.getRoutes()) {
|
||||
if (shouldIgnoreDownstreamRoute(route)) continue;
|
||||
mHwInterface.removeDownstreamPrefix(ifname, route.getDestination().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOffloadDisabled() {
|
||||
@@ -442,6 +471,13 @@ public class OffloadController {
|
||||
return localPrefixStrs;
|
||||
}
|
||||
|
||||
private static boolean shouldIgnoreDownstreamRoute(RouteInfo route) {
|
||||
// Ignore any link-local routes.
|
||||
if (!route.getDestinationLinkAddress().isGlobalPreferred()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void dump(IndentingPrintWriter pw) {
|
||||
if (isOffloadDisabled()) {
|
||||
pw.println("Offload disabled");
|
||||
|
||||
@@ -236,6 +236,44 @@ public class OffloadHardwareInterface {
|
||||
return results.success;
|
||||
}
|
||||
|
||||
public boolean addDownstreamPrefix(String ifname, String prefix) {
|
||||
final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
|
||||
|
||||
final CbResults results = new CbResults();
|
||||
try {
|
||||
mOffloadControl.addDownstream(ifname, prefix,
|
||||
(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 removeDownstreamPrefix(String ifname, String prefix) {
|
||||
final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
|
||||
|
||||
final CbResults results = new CbResults();
|
||||
try {
|
||||
mOffloadControl.removeDownstream(ifname, prefix,
|
||||
(boolean success, String errMsg) -> {
|
||||
results.success = success;
|
||||
results.errMsg = errMsg;
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
record(logmsg, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
record(logmsg, results);
|
||||
return results.success;
|
||||
}
|
||||
|
||||
private void record(String msg, Throwable t) {
|
||||
mLog.e(msg + YIELDS + "exception: " + t);
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
private final LinkProperties mLinkProperties;
|
||||
|
||||
private int mLastError;
|
||||
private int mServingMode;
|
||||
private String mMyUpstreamIfaceName; // may change over time
|
||||
private NetworkInterface mNetworkInterface;
|
||||
private byte[] mHwAddr;
|
||||
@@ -142,6 +143,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
mLinkProperties = new LinkProperties();
|
||||
resetLinkProperties();
|
||||
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
||||
mServingMode = IControlsTethering.STATE_AVAILABLE;
|
||||
|
||||
mInitialState = new InitialState();
|
||||
mLocalHotspotState = new LocalHotspotState();
|
||||
@@ -161,6 +163,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
|
||||
public int lastError() { return mLastError; }
|
||||
|
||||
public int servingMode() { return mServingMode; }
|
||||
|
||||
public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
|
||||
|
||||
public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
|
||||
@@ -448,6 +452,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
}
|
||||
|
||||
private void sendInterfaceState(int newInterfaceState) {
|
||||
mServingMode = newInterfaceState;
|
||||
mTetherController.updateInterfaceState(
|
||||
TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
|
||||
sendLinkProperties();
|
||||
|
||||
@@ -87,6 +87,7 @@ public final class NetworkConstants {
|
||||
public static final int IPV4_PROTOCOL_OFFSET = 9;
|
||||
public static final int IPV4_SRC_ADDR_OFFSET = 12;
|
||||
public static final int IPV4_DST_ADDR_OFFSET = 16;
|
||||
public static final int IPV4_ADDR_BITS = 32;
|
||||
public static final int IPV4_ADDR_LEN = 4;
|
||||
|
||||
/**
|
||||
@@ -99,6 +100,7 @@ public final class NetworkConstants {
|
||||
public static final int IPV6_PROTOCOL_OFFSET = 6;
|
||||
public static final int IPV6_SRC_ADDR_OFFSET = 8;
|
||||
public static final int IPV6_DST_ADDR_OFFSET = 24;
|
||||
public static final int IPV6_ADDR_BITS = 128;
|
||||
public static final int IPV6_ADDR_LEN = 16;
|
||||
public static final int IPV6_MIN_MTU = 1280;
|
||||
public static final int RFC7421_PREFIX_LENGTH = 64;
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -68,6 +70,13 @@ public class PrefixUtils {
|
||||
return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
|
||||
}
|
||||
|
||||
public static IpPrefix ipAddressAsPrefix(InetAddress ip) {
|
||||
final int bitLength = (ip instanceof Inet4Address)
|
||||
? NetworkConstants.IPV4_ADDR_BITS
|
||||
: NetworkConstants.IPV6_ADDR_BITS;
|
||||
return new IpPrefix(ip, bitLength);
|
||||
}
|
||||
|
||||
private static IpPrefix pfx(String prefixStr) {
|
||||
return new IpPrefix(prefixStr);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,15 @@ import org.mockito.MockitoAnnotations;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class OffloadControllerTest {
|
||||
private static final String RNDIS0 = "test_rndis0";
|
||||
private static final String RMNET0 = "test_rmnet_data0";
|
||||
private static final String WLAN0 = "test_wlan0";
|
||||
|
||||
private static final String IPV6_LINKLOCAL = "fe80::/64";
|
||||
private static final String IPV6_DOC_PREFIX = "2001:db8::/64";
|
||||
private static final String IPV6_DISCARD_PREFIX = "100::/64";
|
||||
private static final String USB_PREFIX = "192.168.42.0/24";
|
||||
private static final String WIFI_PREFIX = "192.168.43.0/24";
|
||||
|
||||
@Mock private OffloadHardwareInterface mHardware;
|
||||
@Mock private ApplicationInfo mApplicationInfo;
|
||||
@@ -234,10 +243,8 @@ public class OffloadControllerTest {
|
||||
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"));
|
||||
assertArrayListContains(localPrefixes,
|
||||
"127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64");
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
offload.setUpstreamLinkProperties(null);
|
||||
@@ -352,12 +359,9 @@ public class OffloadControllerTest {
|
||||
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"));
|
||||
assertArrayListContains(localPrefixes,
|
||||
"127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64",
|
||||
"2001:db8::6173:7369:676e:6564/128", "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(
|
||||
@@ -441,6 +445,8 @@ public class OffloadControllerTest {
|
||||
waitForIdle();
|
||||
// There is no current upstream, so no stats are fetched.
|
||||
inOrder.verify(mHardware, never()).getForwardedStats(eq(ethernetIface));
|
||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||
eq(null), eq(null), eq(null), eq(null));
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
assertEquals(2, stats.size());
|
||||
@@ -545,4 +551,79 @@ public class OffloadControllerTest {
|
||||
callback.onStoppedLimitReached();
|
||||
verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveDownstreams() throws Exception {
|
||||
setupFunctioningHardwareInterface();
|
||||
enableOffload();
|
||||
|
||||
final OffloadController offload = makeOffloadController();
|
||||
offload.start();
|
||||
|
||||
final InOrder inOrder = inOrder(mHardware);
|
||||
inOrder.verify(mHardware, times(1)).initOffloadConfig();
|
||||
inOrder.verify(mHardware, times(1)).initOffloadControl(
|
||||
any(OffloadHardwareInterface.ControlCallback.class));
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// Tethering makes several calls to setLocalPrefixes() before add/remove
|
||||
// downstream calls are made. This is not tested here; only the behavior
|
||||
// of notifyDownstreamLinkProperties() and removeDownstreamInterface()
|
||||
// are tested.
|
||||
|
||||
// [1] USB tethering is started.
|
||||
final LinkProperties usbLinkProperties = new LinkProperties();
|
||||
usbLinkProperties.setInterfaceName(RNDIS0);
|
||||
usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24"));
|
||||
usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX)));
|
||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||
inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, USB_PREFIX);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [2] Routes for IPv6 link-local prefixes should never be added.
|
||||
usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL)));
|
||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||
inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString());
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [3] Add an IPv6 prefix for good measure. Only new offload-able
|
||||
// prefixes should be passed to the HAL.
|
||||
usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
|
||||
usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX)));
|
||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||
inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [4] Adding addresses doesn't affect notifyDownstreamLinkProperties().
|
||||
// The address is passed in by a separate setLocalPrefixes() invocation.
|
||||
usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::2/64"));
|
||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||
inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString());
|
||||
|
||||
// [5] Differences in local routes are converted into addDownstream()
|
||||
// and removeDownstream() invocations accordingly.
|
||||
usbLinkProperties.removeRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0));
|
||||
usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX)));
|
||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||
inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX);
|
||||
inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [6] Removing a downstream interface which was never added causes no
|
||||
// interactions with the HAL.
|
||||
offload.removeDownstreamInterface(WLAN0);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [7] Removing an active downstream removes all remaining prefixes.
|
||||
offload.removeDownstreamInterface(RNDIS0);
|
||||
inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, USB_PREFIX);
|
||||
inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
private static void assertArrayListContains(ArrayList<String> list, String... elems) {
|
||||
for (String element : elems) {
|
||||
assertTrue(list.contains(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user