From 67c7a7868cbe45dd1f8a24f7b1c08d6c4f7af5c7 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Mon, 5 Oct 2020 04:46:25 +0000 Subject: [PATCH 1/2] Make PrivateAddressCoordinator ignore vpn network If vpn app make its netmask as 0, PrivateAddressCoordinator would not able to find suitable address for tethering downstream. Since tethering do not support vpn as upstream, just ignore vpn in PrivateAddressCoordinator. Bug: 166365863 Test: atest TetheringTests atest CtsTetheringTest Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1413610 Change-Id: I70b49d0a10b80f378dcd2ba78b5bac848e40e5c9 Merged-In: Iabe265467044fea9fa437674ca29ffc7bcdefe3b (cherry picked from commit a089de8bab2fcfc7c2c1823d27c33af2cd2ce204) --- .../tethering/PrivateAddressCoordinator.java | 22 ++-- .../networkstack/tethering/Tethering.java | 12 +- .../PrivateAddressCoordinatorTest.java | 118 ++++++++++-------- 3 files changed, 84 insertions(+), 68 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index fd9e36080c..b285849f9e 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -15,6 +15,7 @@ */ package com.android.networkstack.tethering; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static java.util.Arrays.asList; @@ -23,7 +24,6 @@ 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; @@ -90,16 +90,24 @@ public class PrivateAddressCoordinator { /** * 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 ipv4Prefixes = getIpv4Prefixes(lp.getAllLinkAddresses()); - if (ipv4Prefixes.isEmpty()) { - removeUpstreamPrefix(network); + public void updateUpstreamPrefix(final UpstreamNetworkState ns) { + // Do not support VPN as upstream + if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) { + removeUpstreamPrefix(ns.network); return; } - mUpstreamPrefixMap.put(network, ipv4Prefixes); + final ArrayList ipv4Prefixes = getIpv4Prefixes( + ns.linkProperties.getAllLinkAddresses()); + if (ipv4Prefixes.isEmpty()) { + removeUpstreamPrefix(ns.network); + return; + } + + mUpstreamPrefixMap.put(ns.network, ipv4Prefixes); handleMaybePrefixConflict(ipv4Prefixes); } diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 7dd5290ee8..877cf9dd04 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/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/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 8e93c2e447..7b6632c36f 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -15,6 +15,10 @@ */ 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; @@ -30,13 +34,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; @@ -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; @@ -69,7 +69,8 @@ public final class PrivateAddressCoordinatorTest { 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); @@ -184,33 +185,25 @@ public final class PrivateAddressCoordinatorTest { 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"; - } - + 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); + } + + private NetworkCapabilities makeNetworkCapabilities(final int transportType) { + final NetworkCapabilities cap = new NetworkCapabilities(); + cap.addTransportType(transportType); + if (transportType == TRANSPORT_VPN) { + cap.removeCapability(NET_CAPABILITY_NOT_VPN); } - if (withIPv6) { - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), - NetworkConstants.RFC7421_PREFIX_LENGTH)); - } - return prop; + return cap; } @Test @@ -220,53 +213,76 @@ 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); assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); - // 2. Update v6 only mobile network, hotspot prefix should not be removed. - List testConflicts; - final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true); - mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp); + // - test mobile network with null NetworkCapabilities. Ideally this should not happen, + // 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); 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); 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); From 6eacfb6b733e1d4dee3db3438f81c42d944d88f8 Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Wed, 7 Oct 2020 09:55:32 +0000 Subject: [PATCH 2/2] Make the IP subnet persistent till reboot Make the IP subnet persistent if it do not conflict with upstream. It allow client to reuse its IP that usually reduce DHCP procedure. Bug: 168169687 Test: atest TetheringTests Change-Id: Iddc5304730dce7b11c5d124b7eddce057d752bbd Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1432958 Change-Id: I60ed54651034f21ca1cd253d272ac3478881b4e0 Merged-In: Iddc5304730dce7b11c5d124b7eddce057d752bbd (cherry picked from commit 177e2d8d1867d7e72d00c81d6fbbed756c9f0568) --- Tethering/src/android/net/ip/IpServer.java | 8 +- .../tethering/PrivateAddressCoordinator.java | 78 +++++--- .../unit/src/android/net/ip/IpServerTest.java | 18 +- .../PrivateAddressCoordinatorTest.java | 170 ++++++++++-------- 4 files changed, 165 insertions(+), 109 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 673cbf09d2..66f216b160 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/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/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index b285849f9e..6276c4e2aa 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -16,7 +16,9 @@ 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; @@ -26,9 +28,9 @@ import android.net.IpPrefix; import android.net.LinkAddress; 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 mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { mDownstreams = new ArraySet<>(); @@ -86,6 +88,10 @@ 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)); } /** @@ -94,7 +100,8 @@ public class PrivateAddressCoordinator { * UpstreamNetworkState must have an already populated LinkProperties. */ public void updateUpstreamPrefix(final UpstreamNetworkState ns) { - // Do not support VPN as upstream + // 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; @@ -116,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; @@ -155,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(); @@ -177,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); @@ -187,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() { @@ -244,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 (IpServer downstream : mDownstreams) { - final IpPrefix prefix = getDownstreamPrefix(downstream); - if (source.equals(prefix)) return true; + 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 target = getDownstreamPrefix(downstream); + if (target == null) continue; + + if (isConflictPrefix(prefix, target)) return true; + } + return false; } @@ -258,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) { @@ -268,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/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 3b72b5b471..2d9f8ed117 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/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 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/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 7b6632c36f..191eb6e711 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -23,6 +23,7 @@ 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; @@ -40,7 +41,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.ip.IpServer; -import android.net.util.PrefixUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -65,7 +65,7 @@ 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); @@ -91,98 +91,119 @@ 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); - 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); + mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } @Test - public void testNoConflictDownstreamPrefix() throws Exception { + 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 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); + + 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, @@ -215,12 +236,13 @@ public final class PrivateAddressCoordinatorTest { when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); // - 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); - // - test mobile network with null NetworkCapabilities. Ideally this should not happen, - // just make sure no crash in this case. + // - 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); @@ -269,24 +291,24 @@ public final class PrivateAddressCoordinatorTest { // - 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(v4OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); // - 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); // - 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); } @@ -299,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); } @@ -319,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); }