summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java49
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java21
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java95
3 files changed, 163 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index c64e70516abc..cb50e9fdbfed 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -20,10 +20,15 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import android.content.ContentResolver;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.net.util.SharedLog;
import android.os.Handler;
import android.provider.Settings;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+
/**
* A class to encapsulate the business logic of programming the tethering
* hardware offload interface.
@@ -92,8 +97,12 @@ public class OffloadController {
public void setUpstreamLinkProperties(LinkProperties lp) {
if (!started()) return;
- // TODO: setUpstreamParameters().
- mUpstreamLinkProperties = lp;
+ 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).
+ pushUpstreamParameters();
}
// TODO: public void addDownStream(...)
@@ -106,4 +115,40 @@ public class OffloadController {
private boolean started() {
return mConfigInitialized && mControlInitialized;
}
+
+ private boolean pushUpstreamParameters() {
+ if (mUpstreamLinkProperties == null) {
+ return mHwInterface.setUpstreamParameters(null, null, null, null);
+ }
+
+ // A stacked interface cannot be an upstream for hardware offload.
+ // Consequently, we examine only the primary interface name, look at
+ // getAddresses() rather than getAllAddresses(), and check getRoutes()
+ // rather than getAllRoutes().
+ final String iface = mUpstreamLinkProperties.getInterfaceName();
+ final ArrayList<String> v6gateways = new ArrayList<>();
+ String v4addr = null;
+ String v4gateway = null;
+
+ for (InetAddress ip : mUpstreamLinkProperties.getAddresses()) {
+ if (ip instanceof Inet4Address) {
+ v4addr = ip.getHostAddress();
+ break;
+ }
+ }
+
+ // Find the gateway addresses of all default routes of either address family.
+ for (RouteInfo ri : mUpstreamLinkProperties.getRoutes()) {
+ if (!ri.hasGateway()) continue;
+
+ final String gateway = ri.getGateway().getHostAddress();
+ if (ri.isIPv4Default()) {
+ v4gateway = gateway;
+ } else if (ri.isIPv6Default()) {
+ v6gateways.add(gateway);
+ }
+ }
+
+ return mHwInterface.setUpstreamParameters(iface, v4addr, v4gateway, v6gateways);
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 0429ab3dca92..3ecf0d1d0c71 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -23,6 +23,8 @@ import android.os.Handler;
import android.os.RemoteException;
import android.net.util.SharedLog;
+import java.util.ArrayList;
+
/**
* Capture tethering dependencies, for injection.
@@ -103,6 +105,25 @@ public class OffloadHardwareInterface {
mControlCallback = null;
}
+ public boolean setUpstreamParameters(
+ String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
+ final CbResults results = new CbResults();
+ try {
+ mOffloadControl.setUpstreamParameters(
+ iface, v4addr, v4gateway, v6gws,
+ (boolean success, String errMsg) -> {
+ results.success = success;
+ results.errMsg = errMsg;
+ });
+ } catch (RemoteException e) {
+ mLog.e("failed to setUpstreamParameters: " + e);
+ return false;
+ }
+
+ if (!results.success) mLog.e("setUpstreamParameters failed: " + results.errMsg);
+ return results.success;
+ }
+
private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
public final Handler handler;
public final ControlCallback controlCb;
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index fb7971e1e104..c535c455e7a8 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -17,15 +17,22 @@
package com.android.server.connectivity.tethering;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.net.util.SharedLog;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -35,9 +42,13 @@ import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
import com.android.internal.util.test.FakeSettingsProvider;
+import java.net.InetAddress;
+import java.util.ArrayList;
+
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -49,6 +60,7 @@ public class OffloadControllerTest {
@Mock private OffloadHardwareInterface mHardware;
@Mock private Context mContext;
+ final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class);
private MockContentResolver mContentResolver;
@Before public void setUp() throws Exception {
@@ -114,4 +126,87 @@ public class OffloadControllerTest {
inOrder.verify(mHardware, never()).initOffloadControl(anyObject());
inOrder.verifyNoMoreInteractions();
}
+
+ @Test
+ public void testSetUpstreamLinkPropertiesWorking() throws Exception {
+ setupFunctioningHardwareInterface();
+ final OffloadController offload =
+ new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ 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();
+
+ offload.setUpstreamLinkProperties(null);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(null), eq(null), eq(null), eq(null));
+ inOrder.verifyNoMoreInteractions();
+ reset(mHardware);
+
+ final LinkProperties lp = new LinkProperties();
+
+ final String testIfName = "rmnet_data17";
+ lp.setInterfaceName(testIfName);
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(null), eq(null), mStringArrayCaptor.capture());
+ assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv4Addr = "192.0.2.5";
+ final String linkAddr = ipv4Addr + "/24";
+ lp.addLinkAddress(new LinkAddress(linkAddr));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(null), mStringArrayCaptor.capture());
+ assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv4Gateway = "192.0.2.1";
+ lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv6Gw1 = "fe80::cafe";
+ lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ ArrayList<String> v6gws = mStringArrayCaptor.getValue();
+ assertEquals(1, v6gws.size());
+ assertTrue(v6gws.contains(ipv6Gw1));
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv6Gw2 = "fe80::d00d";
+ lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
+ offload.setUpstreamLinkProperties(lp);
+ 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();
+
+ final LinkProperties stacked = new LinkProperties();
+ stacked.setInterfaceName("stacked");
+ stacked.addLinkAddress(new LinkAddress("192.0.2.129/25"));
+ stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
+ stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
+ assertTrue(lp.addStackedLink(stacked));
+ offload.setUpstreamLinkProperties(lp);
+ 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();
+ }
}