summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Chien <markchien@google.com>2020-10-12 10:03:26 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-10-12 10:03:26 +0000
commit4c4f42a7f50450d798a606dbce0cafdb2efc1e7d (patch)
treed75f11ed7442434a5af3aae1df296da5f88002f6
parent824bb62751bce03267bc1ad86149f35a8d73ad85 (diff)
parentce9b47e54230a19c84ecd434d9ad7473f5a4dc63 (diff)
downloadbase-4c4f42a7f50450d798a606dbce0cafdb2efc1e7d.tar.gz
Merge changes I60ed5465,I70b49d0a into mainline-prod
* changes: Make the IP subnet persistent till reboot Make PrivateAddressCoordinator ignore vpn network
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java8
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java94
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/Tethering.java12
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java18
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java276
5 files changed, 240 insertions, 168 deletions
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 673cbf09d259..66f216b160dc 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -605,7 +605,7 @@ public class IpServer extends StateMachine {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
if (enabled) {
- mIpv4Address = requestIpv4Address();
+ mIpv4Address = requestIpv4Address(true /* useLastAddress */);
}
if (mIpv4Address == null) {
@@ -650,14 +650,14 @@ public class IpServer extends StateMachine {
return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
}
- private LinkAddress requestIpv4Address() {
+ private LinkAddress requestIpv4Address(final boolean useLastAddress) {
if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr;
if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
return new LinkAddress(BLUETOOTH_IFACE_ADDR);
}
- return mPrivateAddressCoordinator.requestDownstreamAddress(this);
+ return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress);
}
private boolean startIPv6() {
@@ -928,7 +928,7 @@ public class IpServer extends StateMachine {
}
final LinkAddress deprecatedLinkAddress = mIpv4Address;
- mIpv4Address = requestIpv4Address();
+ mIpv4Address = requestIpv4Address(false);
if (mIpv4Address == null) {
mLog.e("Fail to request a new downstream prefix");
return;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index fd9e36080c80..6276c4e2aa7d 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,7 +15,10 @@
*/
package com.android.networkstack.tethering;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.util.PrefixUtils.asIpPrefix;
import static java.util.Arrays.asList;
@@ -23,12 +26,11 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.IpPrefix;
import android.net.LinkAddress;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.ip.IpServer;
-import android.net.util.PrefixUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.SparseArray;
import androidx.annotation.Nullable;
@@ -58,9 +60,6 @@ public class PrivateAddressCoordinator {
private static final int MAX_UBYTE = 256;
private static final int BYTE_MASK = 0xff;
- // reserved for bluetooth tethering.
- private static final int BLUETOOTH_RESERVED = 44;
- private static final int WIFI_P2P_RESERVED = 49;
private static final byte DEFAULT_ID = (byte) 42;
// Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
@@ -75,9 +74,12 @@ public class PrivateAddressCoordinator {
// Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
+ private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24";
private final IpPrefix mTetheringPrefix;
private final ConnectivityManager mConnectivityMgr;
private final TetheringConfiguration mConfig;
+ // keyed by downstream type(TetheringManager.TETHERING_*).
+ private final SparseArray<LinkAddress> mCachedAddresses;
public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
mDownstreams = new ArraySet<>();
@@ -86,20 +88,33 @@ public class PrivateAddressCoordinator {
mConnectivityMgr = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
mConfig = config;
+ mCachedAddresses = new SparseArray<>();
+ // Reserved static addresses for bluetooth and wifi p2p.
+ mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS));
+ mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS));
}
/**
* Record a new upstream IpPrefix which may conflict with tethering downstreams.
- * The downstreams will be notified if a conflict is found.
+ * The downstreams will be notified if a conflict is found. When updateUpstreamPrefix is called,
+ * UpstreamNetworkState must have an already populated LinkProperties.
*/
- public void updateUpstreamPrefix(final Network network, final LinkProperties lp) {
- final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(lp.getAllLinkAddresses());
+ public void updateUpstreamPrefix(final UpstreamNetworkState ns) {
+ // Do not support VPN as upstream. Normally, networkCapabilities is not expected to be null,
+ // but just checking to be sure.
+ if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+ removeUpstreamPrefix(ns.network);
+ return;
+ }
+
+ final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(
+ ns.linkProperties.getAllLinkAddresses());
if (ipv4Prefixes.isEmpty()) {
- removeUpstreamPrefix(network);
+ removeUpstreamPrefix(ns.network);
return;
}
- mUpstreamPrefixMap.put(network, ipv4Prefixes);
+ mUpstreamPrefixMap.put(ns.network, ipv4Prefixes);
handleMaybePrefixConflict(ipv4Prefixes);
}
@@ -108,7 +123,7 @@ public class PrivateAddressCoordinator {
for (LinkAddress address : linkAddresses) {
if (!address.isIpv4()) continue;
- list.add(PrefixUtils.asIpPrefix(address));
+ list.add(asIpPrefix(address));
}
return list;
@@ -147,21 +162,23 @@ public class PrivateAddressCoordinator {
mUpstreamPrefixMap.removeAll(toBeRemoved);
}
- private boolean isReservedSubnet(final int subnet) {
- return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED;
- }
-
/**
* Pick a random available address and mark its prefix as in use for the provided IpServer,
* returns null if there is no available address.
*/
@Nullable
- public LinkAddress requestDownstreamAddress(final IpServer ipServer) {
+ public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) {
if (mConfig.shouldEnableWifiP2pDedicatedIp()
&& ipServer.interfaceType() == TETHERING_WIFI_P2P) {
return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
}
+ final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType());
+ if (useLastAddress && cachedAddress != null
+ && !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
+ return cachedAddress;
+ }
+
// Address would be 192.168.[subAddress]/24.
final byte[] bytes = mTetheringPrefix.getRawAddress();
final int subAddress = getRandomSubAddr();
@@ -169,9 +186,8 @@ public class PrivateAddressCoordinator {
bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
for (int i = 0; i < MAX_UBYTE; i++) {
final int newSubNet = (subNet + i) & BYTE_MASK;
- if (isReservedSubnet(newSubNet)) continue;
-
bytes[2] = (byte) newSubNet;
+
final InetAddress addr;
try {
addr = InetAddress.getByAddress(bytes);
@@ -179,20 +195,23 @@ public class PrivateAddressCoordinator {
throw new IllegalStateException("Invalid address, shouldn't happen.", e);
}
- final IpPrefix prefix = new IpPrefix(addr, PREFIX_LENGTH);
- // Check whether this prefix is in use.
- if (isDownstreamPrefixInUse(prefix)) continue;
- // Check whether this prefix is conflict with any current upstream network.
- if (isConflictWithUpstream(prefix)) continue;
+ if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue;
mDownstreams.add(ipServer);
- return new LinkAddress(addr, PREFIX_LENGTH);
+ final LinkAddress newAddress = new LinkAddress(addr, PREFIX_LENGTH);
+ mCachedAddresses.put(ipServer.interfaceType(), newAddress);
+ return newAddress;
}
// No available address.
return null;
}
+ private boolean isConflict(final IpPrefix prefix) {
+ // Check whether this prefix is in use or conflict with any current upstream network.
+ return isDownstreamPrefixInUse(prefix) || isConflictWithUpstream(prefix);
+ }
+
/** Get random sub address value. Return value is in 0 ~ 0xffff. */
@VisibleForTesting
public int getRandomSubAddr() {
@@ -236,13 +255,24 @@ public class PrivateAddressCoordinator {
return prefix1.contains(prefix2.getAddress());
}
- private boolean isDownstreamPrefixInUse(final IpPrefix source) {
+ // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last
+ // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p).
+ private boolean isDownstreamPrefixInUse(final IpPrefix prefix) {
// This class always generates downstream prefixes with the same prefix length, so
// prefixes cannot be contained in each other. They can only be equal to each other.
+ for (int i = 0; i < mCachedAddresses.size(); i++) {
+ if (prefix.equals(asIpPrefix(mCachedAddresses.valueAt(i)))) return true;
+ }
+
+ // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include
+ // in mCachedAddresses.
for (IpServer downstream : mDownstreams) {
- final IpPrefix prefix = getDownstreamPrefix(downstream);
- if (source.equals(prefix)) return true;
+ final IpPrefix target = getDownstreamPrefix(downstream);
+ if (target == null) continue;
+
+ if (isConflictPrefix(prefix, target)) return true;
}
+
return false;
}
@@ -250,7 +280,7 @@ public class PrivateAddressCoordinator {
final LinkAddress address = downstream.getAddress();
if (address == null) return null;
- return PrefixUtils.asIpPrefix(address);
+ return asIpPrefix(address);
}
void dump(final IndentingPrintWriter pw) {
@@ -260,11 +290,19 @@ public class PrivateAddressCoordinator {
pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i));
}
pw.decreaseIndent();
+
pw.println("mDownstreams:");
pw.increaseIndent();
for (IpServer ipServer : mDownstreams) {
pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress());
}
pw.decreaseIndent();
+
+ pw.println("mCachedAddresses:");
+ pw.increaseIndent();
+ for (int i = 0; i < mCachedAddresses.size(); i++) {
+ pw.println(mCachedAddresses.keyAt(i) + " - " + mCachedAddresses.valueAt(i));
+ }
+ pw.decreaseIndent();
}
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 64d5025807e7..474f4e8b603a 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -1678,14 +1678,6 @@ public class Tethering {
}
}
- private void addUpstreamPrefixes(final UpstreamNetworkState ns) {
- mPrivateAddressCoordinator.updateUpstreamPrefix(ns.network, ns.linkProperties);
- }
-
- private void removeUpstreamPrefixes(final UpstreamNetworkState ns) {
- mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
- }
-
@VisibleForTesting
void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
@@ -1696,10 +1688,10 @@ public class Tethering {
final UpstreamNetworkState ns = (UpstreamNetworkState) o;
switch (arg1) {
case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
- addUpstreamPrefixes(ns);
+ mPrivateAddressCoordinator.updateUpstreamPrefix(ns);
break;
case UpstreamNetworkMonitor.EVENT_ON_LOST:
- removeUpstreamPrefixes(ns);
+ mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
break;
}
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 3b72b5b47191..2d9f8ed117c2 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -47,6 +47,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -213,7 +214,8 @@ public class IpServerTest {
dispatchTetherConnectionChanged(upstreamIface, lp, 0);
}
reset(mNetd, mCallback, mAddressCoordinator);
- when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
+ mTestAddress);
}
private void setUpDhcpServer() throws Exception {
@@ -233,7 +235,8 @@ public class IpServerTest {
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
- when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
+ mTestAddress);
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */);
mBpfCoordinator = spy(new BpfCoordinator(
@@ -355,7 +358,7 @@ public class IpServerTest {
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -376,7 +379,7 @@ public class IpServerTest {
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -590,7 +593,7 @@ public class IpServerTest {
final ArgumentCaptor<LinkProperties> lpCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
// One for ipv4 route, one for ipv6 link local route.
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
@@ -603,11 +606,12 @@ public class IpServerTest {
// Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals
// onNewPrefixRequest callback.
final LinkAddress newAddress = new LinkAddress("192.168.100.125/24");
- when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(newAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
+ newAddress);
eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24"));
mLooper.dispatchAll();
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false));
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
verifyNoMoreInteractions(mCallback);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 8e93c2e447b3..191eb6e71149 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,10 +15,15 @@
*/
package com.android.networkstack.tethering;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
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.util.PrefixUtils.asIpPrefix;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -30,14 +35,12 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.ConnectivityManager;
-import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.ip.IpServer;
-import android.net.util.NetworkConstants;
-import android.net.util.PrefixUtils;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -48,13 +51,10 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public final class PrivateAddressCoordinatorTest {
- private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
- private static final String TEST_WIFI_IFNAME = "test_wlan0";
+ private static final String TEST_IFNAME = "test0";
@Mock private IpServer mHotspotIpServer;
@Mock private IpServer mUsbIpServer;
@@ -65,11 +65,12 @@ public final class PrivateAddressCoordinatorTest {
@Mock private TetheringConfiguration mConfig;
private PrivateAddressCoordinator mPrivateAddressCoordinator;
- private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24");
+ private final LinkAddress mBluetoothAddress = new LinkAddress("192.168.44.1/24");
private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
private final Network mWifiNetwork = new Network(1);
private final Network mMobileNetwork = new Network(2);
- private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
+ private final Network mVpnNetwork = new Network(3);
+ private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork};
private void setUpIpServers() throws Exception {
when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
@@ -90,127 +91,140 @@ public final class PrivateAddressCoordinatorTest {
}
@Test
- public void testDownstreamPrefixRequest() throws Exception {
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals(hotspotPrefix, mBluetoothPrefix);
+ public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception {
+ final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress);
+ final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, false /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(address);
+ assertNotEquals(hotspotPrefix, bluetoothPrefix);
+ when(mHotspotIpServer.getAddress()).thenReturn(address);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix testDupRequest = PrefixUtils.asIpPrefix(address);
+ final LinkAddress newAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, false /* useLastAddress */);
+ final IpPrefix testDupRequest = asIpPrefix(newAddress);
assertNotEquals(hotspotPrefix, testDupRequest);
- assertNotEquals(mBluetoothPrefix, testDupRequest);
+ assertNotEquals(bluetoothPrefix, testDupRequest);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals(usbPrefix, mBluetoothPrefix);
+ final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, false /* useLastAddress */);
+ final IpPrefix usbPrefix = asIpPrefix(usbAddress);
+ assertNotEquals(usbPrefix, bluetoothPrefix);
assertNotEquals(usbPrefix, hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
}
@Test
- public void testRequestDownstreamAddress() throws Exception {
- LinkAddress expectedAddress = new LinkAddress("192.168.43.42/24");
- int fakeSubAddr = 0x2b00;
+ public void testSanitizedAddress() throws Exception {
+ int fakeSubAddr = 0x2b00; // 43.0.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.43.42/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- fakeSubAddr = 0x2b01;
+ fakeSubAddr = 0x2d01; // 45.1.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.45.42/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- fakeSubAddr = 0x2bff;
+ fakeSubAddr = 0x2eff; // 46.255.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.46.42/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- expectedAddress = new LinkAddress("192.168.43.5/24");
- fakeSubAddr = 0x2b05;
+ fakeSubAddr = 0x2f05; // 47.5.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
}
- private int getBluetoothSubAddress() {
- final byte[] rawAddress = mBluetoothPrefix.getRawAddress();
- int bluetoothSubNet = rawAddress[2] & 0xff;
- return (bluetoothSubNet << 8) + 0x5;
- }
-
@Test
- public void testReserveBluetoothPrefix() throws Exception {
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(getBluetoothSubAddress());
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals("Should not get reserved prefix: ", mBluetoothPrefix, hotspotPrefix);
+ public void testReservedPrefix() throws Exception {
+ // - Test bluetooth prefix is reserved.
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(mBluetoothAddress.getAddress().getAddress()));
+ final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, false /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress);
+ assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+
+ // - Test previous enabled hotspot prefix(cached prefix) is reserved.
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(hotspotAddress.getAddress().getAddress()));
+ final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, false /* useLastAddress */);
+ final IpPrefix usbPrefix = asIpPrefix(usbAddress);
+ assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix);
+ assertNotEquals(hotspotPrefix, usbPrefix);
+ mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
+
+ // - Test wifi p2p prefix is reserved.
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
+ final LinkAddress etherAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mEthernetIpServer, false /* useLastAddress */);
+ final IpPrefix etherPrefix = asIpPrefix(etherAddress);
+ assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix);
+ assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix);
+ assertNotEquals(hotspotPrefix, etherPrefix);
+ mPrivateAddressCoordinator.releaseDownstream(mEthernetIpServer);
}
@Test
- public void testNoConflictDownstreamPrefix() throws Exception {
+ public void testRequestLastDownstreamAddress() throws Exception {
final int fakeHotspotSubAddr = 0x2b05;
final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
- when(mHotspotIpServer.getAddress()).thenReturn(address);
+ final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, true /* useLastAddress */);
+ assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress));
+ when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddress);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals(predefinedPrefix, usbPrefix);
+ final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, true /* useLastAddress */);
+ assertNotEquals(predefinedPrefix, asIpPrefix(usbAddress));
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address);
- assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix);
- }
- private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6,
- boolean isMobile) {
- final String testIface;
- final String testIpv4Address;
- if (isMobile) {
- testIface = TEST_MOBILE_IFNAME;
- testIpv4Address = "10.0.0.1";
- } else {
- testIface = TEST_WIFI_IFNAME;
- testIpv4Address = "192.168.43.5";
- }
+ final int newFakeSubAddr = 0x3c05;
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
+
+ final LinkAddress newHotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, true /* useLastAddress */);
+ assertEquals(hotspotAddress, newHotspotAddress);
+ final LinkAddress newUsbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, true /* useLastAddress */);
+ assertEquals(usbAddress, newUsbAddress);
+ }
+ private UpstreamNetworkState buildUpstreamNetworkState(final Network network,
+ final LinkAddress v4Addr, final LinkAddress v6Addr, final NetworkCapabilities cap) {
final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(testIface);
+ prop.setInterfaceName(TEST_IFNAME);
+ if (v4Addr != null) prop.addLinkAddress(v4Addr);
- if (withIPv4) {
- prop.addLinkAddress(
- new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address),
- NetworkConstants.IPV4_ADDR_BITS));
- }
+ if (v6Addr != null) prop.addLinkAddress(v6Addr);
+
+ return new UpstreamNetworkState(prop, cap, network);
+ }
- if (withIPv6) {
- prop.addLinkAddress(
- new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"),
- NetworkConstants.RFC7421_PREFIX_LENGTH));
+ private NetworkCapabilities makeNetworkCapabilities(final int transportType) {
+ final NetworkCapabilities cap = new NetworkCapabilities();
+ cap.addTransportType(transportType);
+ if (transportType == TRANSPORT_VPN) {
+ cap.removeCapability(NET_CAPABILITY_NOT_VPN);
}
- return prop;
+
+ return cap;
}
@Test
@@ -220,57 +234,81 @@ public final class PrivateAddressCoordinatorTest {
final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
// Force always get subAddress "43.5" for conflict testing.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
- // 1. Enable hotspot with prefix 192.168.43.0/24
+ // - Enable hotspot with prefix 192.168.43.0/24
final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr);
+ mHotspotIpServer, true /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr);
assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr);
- // 2. Update v6 only mobile network, hotspot prefix should not be removed.
- List<String> testConflicts;
- final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp);
+ // - test mobile network with null NetworkCapabilities. Ideally this should not happen
+ // because NetworkCapabilities update should always happen before LinkProperties update
+ // and the UpstreamNetworkState update, just make sure no crash in this case.
+ final UpstreamNetworkState noCapUpstream = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("10.0.0.8/24"), null, null);
+ mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream);
+ verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ // - test mobile upstream with no address.
+ final UpstreamNetworkState noAddress = buildUpstreamNetworkState(mMobileNetwork,
+ null, null, makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream);
+ verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ // - Update v6 only mobile network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v6OnlyMobile = buildUpstreamNetworkState(mMobileNetwork,
+ null, new LinkAddress("2001:db8::/64"),
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyMobile);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork);
- // 3. Update v4 only mobile network, hotspot prefix should not be removed.
- final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp);
+ // - Update v4 only mobile network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v4OnlyMobile = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("10.0.0.8/24"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyMobile);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- // 4. Update v4v6 mobile network, hotspot prefix should not be removed.
- final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp);
+ // - Update v4v6 mobile network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v4v6Mobile = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("10.0.0.8/24"), new LinkAddress("2001:db8::/64"),
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4v6Mobile);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- // 5. Update v6 only wifi network, hotspot prefix should not be removed.
- final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp);
+ // - Update v6 only wifi network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v6OnlyWifi = buildUpstreamNetworkState(mWifiNetwork,
+ null, new LinkAddress("2001:db8::/64"), makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyWifi);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
- // 6. Update v4 only wifi network, it conflict with hotspot prefix.
- final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp);
+ // - Update vpn network, it conflict with hotspot prefix but VPN networks are ignored.
+ final UpstreamNetworkState v4OnlyVpn = buildUpstreamNetworkState(mVpnNetwork,
+ new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_VPN));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyVpn);
+ verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ // - Update v4 only wifi network, it conflict with hotspot prefix.
+ final UpstreamNetworkState v4OnlyWifi = buildUpstreamNetworkState(mWifiNetwork,
+ new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
reset(mHotspotIpServer);
- // 7. Restart hotspot again and its prefix is different previous.
+ // - Restart hotspot again and its prefix is different previous.
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2);
+ mHotspotIpServer, true /* useLastAddress */);
+ final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2);
assertNotEquals(hotspotPrefix, hotspotPrefix2);
when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp);
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- // 7. Usb tethering can be enabled and its prefix is different with conflict one.
+ // - Usb tethering can be enabled and its prefix is different with conflict one.
final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr);
+ mUsbIpServer, true /* useLastAddress */);
+ final IpPrefix usbPrefix = asIpPrefix(usbAddr);
assertNotEquals(predefinedPrefix, usbPrefix);
assertNotEquals(hotspotPrefix2, usbPrefix);
when(mUsbIpServer.getAddress()).thenReturn(usbAddr);
- // 8. Disable wifi upstream, then wifi's prefix can be selected again.
+ // - Disable wifi upstream, then wifi's prefix can be selected again.
mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mEthernetIpServer);
- final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr);
+ mEthernetIpServer, true /* useLastAddress */);
+ final IpPrefix ethPrefix = asIpPrefix(ethAddr);
assertEquals(predefinedPrefix, ethPrefix);
}
@@ -283,9 +321,9 @@ public final class PrivateAddressCoordinatorTest {
private void assertReseveredWifiP2pPrefix() throws Exception {
LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress);
+ mHotspotIpServer, true /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(address);
+ final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress);
assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
}
@@ -303,7 +341,7 @@ public final class PrivateAddressCoordinatorTest {
// If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mWifiP2pIpServer);
+ mWifiP2pIpServer, true /* useLastAddress */);
assertEquals(mLegacyWifiP2pAddress, address);
mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
}