Merge "Rename IDhcpLeaseCallbacks to IDhcpEventCallbacks for more generic."
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 9db6a35..1dac5b7 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -34,6 +34,7 @@
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
+import android.net.TetherOffloadRuleParcel;
import android.net.TetheredClient;
import android.net.TetheringManager;
import android.net.TetheringRequestParcel;
@@ -280,6 +281,19 @@
return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
dstMac);
}
+
+ // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
+ // would be error-prone due to generated stable AIDL classes not having a copy constructor.
+ public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
+ final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
+ parcel.inputInterfaceIndex = upstreamIfindex;
+ parcel.outputInterfaceIndex = downstreamIfindex;
+ parcel.destination = address.getAddress();
+ parcel.prefixLength = 128;
+ parcel.srcL2Address = srcMac.toByteArray();
+ parcel.dstL2Address = dstMac.toByteArray();
+ return parcel;
+ }
}
private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules =
new LinkedHashMap<>();
@@ -829,9 +843,7 @@
private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) {
try {
- mNetd.tetherRuleAddDownstreamIpv6(mInterfaceParams.index, rule.upstreamIfindex,
- rule.address.getAddress(), mInterfaceParams.macAddr.toByteArray(),
- rule.dstMac.toByteArray());
+ mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
mIpv6ForwardingRules.put(rule.address, rule);
} catch (RemoteException | ServiceSpecificException e) {
mLog.e("Could not add IPv6 downstream rule: ", e);
@@ -840,7 +852,7 @@
private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
try {
- mNetd.tetherRuleRemoveDownstreamIpv6(rule.upstreamIfindex, rule.address.getAddress());
+ mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
if (removeFromMap) {
mIpv6ForwardingRules.remove(rule.address);
}
diff --git a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index bd60594..639cf65 100644
--- a/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -20,6 +20,7 @@
import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_INVALID;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
@@ -537,6 +538,7 @@
private static boolean isValidDownstreamType(int type) {
switch (type) {
case TETHERING_BLUETOOTH:
+ case TETHERING_ETHERNET:
case TETHERING_USB:
case TETHERING_WIFI:
return true;
@@ -650,6 +652,11 @@
private void handleRequestLatestTetheringEntitlementValue(int downstream,
ResultReceiver receiver, boolean showEntitlementUi) {
+ if (!isValidDownstreamType(downstream)) {
+ receiver.send(TETHER_ERROR_ENTITLEMENT_UNKNOWN, null);
+ return;
+ }
+
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
if (!isTetherProvisioningRequired(config)) {
receiver.send(TETHER_ERROR_NO_ERROR, null);
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 492ce3d..dbd68ef 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -57,6 +58,7 @@
import java.io.FileDescriptor;
import java.net.Inet4Address;
+import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.ByteBuffer;
@@ -66,6 +68,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
@RunWith(AndroidJUnit4.class)
@MediumTest
@@ -110,7 +113,7 @@
}
private void cleanUp() throws Exception {
- mTm.stopTethering(TetheringManager.TETHERING_ETHERNET);
+ mTm.stopTethering(TETHERING_ETHERNET);
if (mTetheringEventCallback != null) {
mTetheringEventCallback.awaitInterfaceUntethered();
mTetheringEventCallback.unregister();
@@ -177,6 +180,49 @@
}
@Test
+ public void testStaticIpv4() throws Exception {
+ assumeFalse(mEm.isAvailable());
+
+ mEm.setIncludeTestInterfaces(true);
+
+ mTestIface = createTestInterface();
+
+ final String iface = mTetheredInterfaceRequester.getInterface();
+ assertEquals("TetheredInterfaceCallback for unexpected interface",
+ mTestIface.getInterfaceName(), iface);
+
+ assertInvalidStaticIpv4Request(iface, null, null);
+ assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28");
+ assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null);
+ assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28");
+
+ final String localAddr = "192.0.2.3/28";
+ final String clientAddr = "192.0.2.2/28";
+ mTetheringEventCallback = enableEthernetTethering(iface,
+ requestWithStaticIpv4(localAddr, clientAddr));
+
+ mTetheringEventCallback.awaitInterfaceTethered();
+ assertInterfaceHasIpAddress(iface, clientAddr);
+
+ byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
+ byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
+
+ FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
+ mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
+ DhcpResults dhcpResults = runDhcp(fd, client1);
+ assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
+
+ try {
+ runDhcp(fd, client2);
+ fail("Only one client should get an IP address");
+ } catch (TimeoutException expected) { }
+
+ }
+
+ @Test
public void testPhysicalEthernet() throws Exception {
assumeTrue(mEm.isAvailable());
@@ -271,7 +317,8 @@
}
}
- private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
+ private MyTetheringEventCallback enableEthernetTethering(String iface,
+ TetheringRequest request) throws Exception {
MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface);
mTm.registerTetheringEventCallback(mHandler::post, callback);
@@ -282,34 +329,37 @@
}
};
Log.d(TAG, "Starting Ethernet tethering");
- mTm.startTethering(
- new TetheringRequest.Builder(TetheringManager.TETHERING_ETHERNET).build(),
- mHandler::post /* executor */, startTetheringCallback);
+ mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback);
callback.awaitInterfaceTethered();
return callback;
}
+ private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
+ return enableEthernetTethering(iface,
+ new TetheringRequest.Builder(TETHERING_ETHERNET).build());
+ }
+
private int getMTU(TestNetworkInterface iface) throws SocketException {
NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName());
assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif);
return nif.getMTU();
}
+ private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
+ final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
+ mHandler.post(() -> reader.start());
+ HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
+ return reader;
+ }
+
private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
- mTapPacketReader = new TapPacketReader(mHandler, fd, mtu);
- mHandler.post(() -> mTapPacketReader.start());
- HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
-
+ mTapPacketReader = makePacketReader(fd, mtu);
mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName());
checkTetheredClientCallbacks(fd);
}
- private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
- // Create a fake client.
- byte[] clientMacAddr = new byte[6];
- new Random().nextBytes(clientMacAddr);
-
+ private DhcpResults runDhcp(FileDescriptor fd, byte[] clientMacAddr) throws Exception {
// We have to retransmit DHCP requests because IpServer declares itself to be ready before
// its DhcpServer is actually started. TODO: fix this race and remove this loop.
DhcpPacket offerPacket = null;
@@ -319,13 +369,25 @@
offerPacket = getNextDhcpPacket();
if (offerPacket instanceof DhcpOfferPacket) break;
}
- assertTrue("No DHCPOFFER received on interface within timeout",
- offerPacket instanceof DhcpOfferPacket);
+ if (!(offerPacket instanceof DhcpOfferPacket)) {
+ throw new TimeoutException("No DHCPOFFER received on interface within timeout");
+ }
sendDhcpRequest(fd, offerPacket, clientMacAddr);
DhcpPacket ackPacket = getNextDhcpPacket();
- assertTrue("No DHCPACK received on interface within timeout",
- ackPacket instanceof DhcpAckPacket);
+ if (!(ackPacket instanceof DhcpAckPacket)) {
+ throw new TimeoutException("No DHCPACK received on interface within timeout");
+ }
+
+ return ackPacket.toDhcpResults();
+ }
+
+ private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
+ // Create a fake client.
+ byte[] clientMacAddr = new byte[6];
+ new Random().nextBytes(clientMacAddr);
+
+ DhcpResults dhcpResults = runDhcp(fd, clientMacAddr);
final Collection<TetheredClient> clients = mTetheringEventCallback.awaitClientConnected();
assertEquals(1, clients.size());
@@ -333,7 +395,7 @@
// Check the MAC address.
assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
- assertEquals(TetheringManager.TETHERING_ETHERNET, client.getTetheringType());
+ assertEquals(TETHERING_ETHERNET, client.getTetheringType());
// Check the hostname.
assertEquals(1, client.getAddresses().size());
@@ -341,7 +403,6 @@
assertEquals(DHCP_HOSTNAME, info.getHostname());
// Check the address is the one that was handed out in the DHCP ACK.
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
// Check that the lifetime is correct +/- 10s.
@@ -441,6 +502,34 @@
assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
}
+ private TetheringRequest requestWithStaticIpv4(String local, String client) {
+ LinkAddress localAddr = local == null ? null : new LinkAddress(local);
+ LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
+ return new TetheringRequest.Builder(TETHERING_ETHERNET)
+ .setStaticIpv4Addresses(localAddr, clientAddr).build();
+ }
+
+ private void assertInvalidStaticIpv4Request(String iface, String local, String client)
+ throws Exception {
+ try {
+ enableEthernetTethering(iface, requestWithStaticIpv4(local, client));
+ fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
+ } catch (IllegalArgumentException | NullPointerException expected) { }
+ }
+
+ private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
+ LinkAddress expectedAddr = new LinkAddress(expected);
+ NetworkInterface nif = NetworkInterface.getByName(iface);
+ for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
+ final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
+ if (expectedAddr.equals(addr)) {
+ return;
+ }
+ }
+ fail("Expected " + iface + " to have IP address " + expected + ", found "
+ + nif.getInterfaceAddresses());
+ }
+
private TestNetworkInterface createTestInterface() throws Exception {
TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
TestNetworkInterface iface = tnm.createTapInterface();
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 3106e0e..fdfdae8 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -43,7 +43,6 @@
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -66,6 +65,7 @@
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
+import android.net.TetherOffloadRuleParcel;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
import android.net.dhcp.IDhcpServerCallbacks;
@@ -85,6 +85,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -92,6 +93,7 @@
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -514,6 +516,65 @@
mLooper.dispatchAll();
}
+ /**
+ * Custom ArgumentMatcher for TetherOffloadRuleParcel. This is needed because generated stable
+ * AIDL classes don't have equals(), so we cannot just use eq(). A custom assert, such as:
+ *
+ * private void checkFooCalled(StableParcelable p, ...) {
+ * ArgumentCaptor<FooParam> captor = ArgumentCaptor.forClass(FooParam.class);
+ * verify(mMock).foo(captor.capture());
+ * Foo foo = captor.getValue();
+ * assertFooMatchesExpectations(foo);
+ * }
+ *
+ * almost works, but not quite. This is because if the code under test calls foo() twice, the
+ * first call to checkFooCalled() matches both the calls, putting both calls into the captor,
+ * and then fails with TooManyActualInvocations. It also makes it harder to use other mockito
+ * features such as never(), inOrder(), etc.
+ *
+ * This approach isn't great because if the match fails, the error message is unhelpful
+ * (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does
+ * work.
+ *
+ * See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the
+ * TooManyActualInvocations problem described above by forcing the caller of the custom assert
+ * method to specify all expected invocations in one call. This is useful when the stable
+ * parcelable class being asserted on has a corresponding Java object (eg., RouteInfo and
+ * RouteInfoParcelable), and the caller can just pass in a list of them. It not useful here
+ * because there is no such object.
+ */
+ private static class TetherOffloadRuleParcelMatcher implements
+ ArgumentMatcher<TetherOffloadRuleParcel> {
+ public final int upstreamIfindex;
+ public final InetAddress dst;
+ public final MacAddress dstMac;
+
+ TetherOffloadRuleParcelMatcher(int upstreamIfindex, InetAddress dst, MacAddress dstMac) {
+ this.upstreamIfindex = upstreamIfindex;
+ this.dst = dst;
+ this.dstMac = dstMac;
+ }
+
+ public boolean matches(TetherOffloadRuleParcel parcel) {
+ return upstreamIfindex == parcel.inputInterfaceIndex
+ && (TEST_IFACE_PARAMS.index == parcel.outputInterfaceIndex)
+ && Arrays.equals(dst.getAddress(), parcel.destination)
+ && (128 == parcel.prefixLength)
+ && Arrays.equals(TEST_IFACE_PARAMS.macAddr.toByteArray(), parcel.srcL2Address)
+ && Arrays.equals(dstMac.toByteArray(), parcel.dstL2Address);
+ }
+
+ public String toString() {
+ return String.format("TetherOffloadRuleParcelMatcher(%d, %s, %s",
+ upstreamIfindex, dst.getHostAddress(), dstMac);
+ }
+ }
+
+ private TetherOffloadRuleParcel matches(
+ int upstreamIfindex, InetAddress dst, MacAddress dstMac) {
+ return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac));
+ }
+
@Test
public void addRemoveipv6ForwardingRules() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */);
@@ -537,13 +598,11 @@
// Events on this interface are received and sent to netd.
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
reset(mNetd);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// Link-local and multicast neighbors are ignored.
@@ -554,12 +613,12 @@
// A neighbor that is no longer valid causes the rule to be removed.
recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
reset(mNetd);
// A neighbor that is deleted causes the rule to be removed.
recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// Upstream changes result in deleting and re-adding the rules.
@@ -571,22 +630,16 @@
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp);
- inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
- inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()));
- inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
- inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()));
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
+ inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
+ inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// When the upstream is lost, rules are removed.
dispatchTetherConnectionChanged(null, null);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
- eq(neighA.getAddress()));
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
- eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB));
reset(mNetd);
// If the upstream is IPv4-only, no rules are added.
@@ -599,31 +652,27 @@
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
- verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(),
- eq(neighA.getAddress()), any(), any());
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
+ verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
// If upstream IPv6 connectivity is lost, rules are removed.
reset(mNetd);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
// When the interface goes down, rules are removed.
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
mIpServer.stop();
mLooper.dispatchAll();
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
}
diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 0a7850b..b3a30ab 100644
--- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -17,8 +17,10 @@
package com.android.server.connectivity.tethering;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
@@ -353,6 +355,20 @@
callbackTimeoutHelper(mCallbacklatch);
assertEquals(0, mEnMgr.uiProvisionCount);
mEnMgr.reset();
+ // 8. Test get value for invalid downstream type.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI_P2P, receiver, true);
+ mLooper.dispatchAll();
+ callbackTimeoutHelper(mCallbacklatch);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
}
void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
@@ -471,6 +487,22 @@
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(3, mEnMgr.silentProvisionCount);
+ assertFalse(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.reset();
+ // 7. start ui provisioning, upstream is mobile, downstream is ethernet
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true);
+ mLooper.dispatchAll();
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.reset();
+ // 8. downstream is invalid
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true);
+ mLooper.dispatchAll();
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
mEnMgr.reset();
}