From 49649c9aeac709abaeb345f89b6a3a0e5a279435 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 15 Mar 2023 06:45:04 +0000 Subject: [PATCH] Support SAP and LOHS enabled at the same time Use type + scope as key to build cached address map so that SAP (key: TETHERING_WIFI + INTERNET) and LOHS (key: TETHERING_WIFI + LOCAL) can use different address. Bug: 233175023 Test: atest TetheringTests Change-Id: I46a4b3ee919628092b7540202a43d79f407b09b6 --- Tethering/src/android/net/ip/IpServer.java | 28 +++-- .../tethering/PrivateAddressCoordinator.java | 49 ++++++-- .../unit/src/android/net/ip/IpServerTest.java | 30 +++-- .../PrivateAddressCoordinatorTest.java | 105 +++++++++++------- 4 files changed, 143 insertions(+), 69 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 9d0f6b4b84..6affb62a6f 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -17,6 +17,8 @@ package android.net.ip; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; import static android.net.TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR; import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; @@ -405,8 +407,8 @@ public class IpServer extends StateMachine { /** Internals. */ - private boolean startIPv4() { - return configureIPv4(true); + private boolean startIPv4(int scope) { + return configureIPv4(true, scope); } /** @@ -616,7 +618,7 @@ public class IpServer extends StateMachine { } private void stopIPv4() { - configureIPv4(false); + configureIPv4(false /* enabled */, CONNECTIVITY_SCOPE_GLOBAL /* not used */); // NOTE: All of configureIPv4() will be refactored out of existence // into calls to InterfaceController, shared with startIPv4(). mInterfaceCtrl.clearIPv4Address(); @@ -627,11 +629,11 @@ public class IpServer extends StateMachine { mStaticIpv4ClientAddr = null; } - private boolean configureIPv4(boolean enabled) { + private boolean configureIPv4(boolean enabled, int scope) { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (enabled) { - mIpv4Address = requestIpv4Address(true /* useLastAddress */); + mIpv4Address = requestIpv4Address(scope, true /* useLastAddress */); } if (mIpv4Address == null) { @@ -679,12 +681,12 @@ public class IpServer extends StateMachine { return (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) && !SdkLevel.isAtLeastT(); } - private LinkAddress requestIpv4Address(final boolean useLastAddress) { + private LinkAddress requestIpv4Address(final int scope, final boolean useLastAddress) { if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (shouldNotConfigureBluetoothInterface()) return new LinkAddress(BLUETOOTH_IFACE_ADDR); - return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress); + return mPrivateAddressCoordinator.requestDownstreamAddress(this, scope, useLastAddress); } private boolean startIPv6() { @@ -1133,8 +1135,16 @@ public class IpServer extends StateMachine { sendInterfaceState(mDesiredInterfaceState); } + private int getScope() { + if (mDesiredInterfaceState == STATE_TETHERED) { + return CONNECTIVITY_SCOPE_GLOBAL; + } + + return CONNECTIVITY_SCOPE_LOCAL; + } + private void startServingInterface() { - if (!startIPv4()) { + if (!startIPv4(getScope())) { mLastError = TETHER_ERROR_IFACE_CFG_ERROR; return; } @@ -1222,7 +1232,7 @@ public class IpServer extends StateMachine { } final LinkAddress deprecatedLinkAddress = mIpv4Address; - mIpv4Address = requestIpv4Address(false); + mIpv4Address = requestIpv4Address(getScope(), 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 41a10ae60e..6c0ca822ac 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -16,6 +16,8 @@ package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_WIFI_P2P; @@ -34,7 +36,6 @@ import android.net.Network; import android.net.ip.IpServer; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -77,7 +78,7 @@ public class PrivateAddressCoordinator { private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; // keyed by downstream type(TetheringManager.TETHERING_*). - private final SparseArray mCachedAddresses; + private final ArrayMap mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { mDownstreams = new ArraySet<>(); @@ -85,10 +86,12 @@ public class PrivateAddressCoordinator { mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); mConfig = config; - mCachedAddresses = new SparseArray<>(); + mCachedAddresses = new ArrayMap(); // 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)); + mCachedAddresses.put(new AddressKey(TETHERING_BLUETOOTH, CONNECTIVITY_SCOPE_GLOBAL), + new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); + mCachedAddresses.put(new AddressKey(TETHERING_WIFI_P2P, CONNECTIVITY_SCOPE_LOCAL), + new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); mTetheringPrefixes = new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16"), new IpPrefix("172.16.0.0/12"), new IpPrefix("10.0.0.0/8"))); @@ -166,16 +169,18 @@ public class PrivateAddressCoordinator { * returns null if there is no available address. */ @Nullable - public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { + public LinkAddress requestDownstreamAddress(final IpServer ipServer, final int scope, + boolean useLastAddress) { if (mConfig.shouldEnableWifiP2pDedicatedIp() && ipServer.interfaceType() == TETHERING_WIFI_P2P) { return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS); } + final AddressKey addrKey = new AddressKey(ipServer.interfaceType(), scope); // This ensures that tethering isn't started on 2 different interfaces with the same type. // Once tethering could support multiple interface with the same type, // TetheringSoftApCallback would need to handle it among others. - final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType()); + final LinkAddress cachedAddress = mCachedAddresses.get(addrKey); if (useLastAddress && cachedAddress != null && !isConflictWithUpstream(asIpPrefix(cachedAddress))) { mDownstreams.add(ipServer); @@ -186,7 +191,7 @@ public class PrivateAddressCoordinator { final LinkAddress newAddress = chooseDownstreamAddress(prefixRange); if (newAddress != null) { mDownstreams.add(ipServer); - mCachedAddresses.put(ipServer.interfaceType(), newAddress); + mCachedAddresses.put(addrKey, newAddress); return newAddress; } } @@ -384,6 +389,34 @@ public class PrivateAddressCoordinator { return asIpPrefix(address); } + private static class AddressKey { + private final int mTetheringType; + private final int mScope; + + private AddressKey(int type, int scope) { + mTetheringType = type; + mScope = scope; + } + + @Override + public int hashCode() { + return (mTetheringType << 16) + mScope; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof AddressKey)) return false; + final AddressKey other = (AddressKey) obj; + + return mTetheringType == other.mTetheringType && mScope == other.mScope; + } + + @Override + public String toString() { + return "AddressKey(" + mTetheringType + ", " + mScope + ")"; + } + } + void dump(final IndentingPrintWriter pw) { pw.println("mTetheringPrefixes:"); pw.increaseIndent(); diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index f0d9057ac3..46e50ef835 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -19,6 +19,8 @@ package android.net.ip; import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_UP; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; @@ -48,6 +50,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; @@ -271,8 +274,8 @@ public class IpServerTest { dispatchTetherConnectionChanged(upstreamIface, lp, 0); } reset(mNetd, mCallback, mAddressCoordinator, mBpfCoordinator); - when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( - mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(), + anyBoolean())).thenReturn(mTestAddress); } @SuppressWarnings("DoNotCall") // Ignore warning for synchronous to call to Thread.run() @@ -293,8 +296,8 @@ public class IpServerTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); - when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( - mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(), + anyBoolean())).thenReturn(mTestAddress); when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(DEFAULT_USING_BPF_OFFLOAD); when(mTetherConfig.useLegacyDhcpServer()).thenReturn(false /* default value */); @@ -428,7 +431,8 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); if (isAtLeastT()) { - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_GLOBAL), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); } @@ -477,7 +481,8 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_GLOBAL), 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); @@ -498,7 +503,8 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_LOCAL), 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); @@ -766,7 +772,8 @@ public class IpServerTest { final ArgumentCaptor lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_LOCAL), 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), @@ -779,12 +786,13 @@ 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(), anyBoolean())).thenReturn( - newAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(), + anyBoolean())).thenReturn(newAddress); eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); mLooper.dispatchAll(); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_LOCAL), 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 55d9852b34..91b092ad0f 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -19,6 +19,8 @@ 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.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; @@ -61,6 +63,7 @@ public final class PrivateAddressCoordinatorTest { private static final String TEST_IFNAME = "test0"; @Mock private IpServer mHotspotIpServer; + @Mock private IpServer mLocalHotspotIpServer; @Mock private IpServer mUsbIpServer; @Mock private IpServer mEthernetIpServer; @Mock private IpServer mWifiP2pIpServer; @@ -90,6 +93,7 @@ public final class PrivateAddressCoordinatorTest { when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB); when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET); when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI); + when(mLocalHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI); when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P); } @@ -104,9 +108,10 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig)); } - private LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { + private LinkAddress requestDownstreamAddress(final IpServer ipServer, int scope, + boolean useLastAddress) { final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - ipServer, useLastAddress); + ipServer, scope, useLastAddress); when(ipServer.getAddress()).thenReturn(address); return address; } @@ -115,19 +120,19 @@ public final class PrivateAddressCoordinatorTest { public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception { final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress); final LinkAddress address = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(address); assertNotEquals(hotspotPrefix, bluetoothPrefix); final LinkAddress newAddress = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix testDupRequest = asIpPrefix(newAddress); assertNotEquals(hotspotPrefix, testDupRequest); assertNotEquals(bluetoothPrefix, testDupRequest); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddress); assertNotEquals(usbPrefix, bluetoothPrefix); assertNotEquals(usbPrefix, hotspotPrefix); @@ -139,25 +144,28 @@ public final class PrivateAddressCoordinatorTest { int fakeSubAddr = 0x2b00; // 43.0. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); LinkAddress actualAddress = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2d01; // 45.1. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2eff; // 46.255. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2f05; // 47.5. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } @@ -168,7 +176,7 @@ public final class PrivateAddressCoordinatorTest { when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mBluetoothAddress.getAddress().getAddress())); final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress); assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); @@ -177,7 +185,7 @@ public final class PrivateAddressCoordinatorTest { when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(hotspotAddress.getAddress().getAddress())); final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddress); assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix); assertNotEquals(hotspotPrefix, usbPrefix); @@ -187,7 +195,7 @@ public final class PrivateAddressCoordinatorTest { when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); final LinkAddress etherAddress = requestDownstreamAddress(mEthernetIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix etherPrefix = asIpPrefix(etherAddress); assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix); assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix); @@ -200,11 +208,11 @@ public final class PrivateAddressCoordinatorTest { final int fakeHotspotSubAddr = 0x2b05; // 43.5 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress); final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); @@ -214,10 +222,10 @@ public final class PrivateAddressCoordinatorTest { when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress newHotspotAddress = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals(hotspotAddress, newHotspotAddress); final LinkAddress newUsbAddress = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals(usbAddress, newUsbAddress); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, @@ -257,7 +265,7 @@ public final class PrivateAddressCoordinatorTest { when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); // - Enable hotspot with prefix 192.168.43.0/24 final LinkAddress hotspotAddr = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr); assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); // - test mobile network with null NetworkCapabilities. Ideally this should not happen @@ -311,21 +319,21 @@ public final class PrivateAddressCoordinatorTest { // - Restart hotspot again and its prefix is different previous. mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); final LinkAddress hotspotAddr2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2); assertNotEquals(hotspotPrefix, hotspotPrefix2); 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 = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddr); assertNotEquals(predefinedPrefix, usbPrefix); assertNotEquals(hotspotPrefix2, usbPrefix); // - Disable wifi upstream, then wifi's prefix can be selected again. mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); final LinkAddress ethAddr = requestDownstreamAddress(mEthernetIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix ethPrefix = asIpPrefix(ethAddr); assertEquals(predefinedPrefix, ethPrefix); } @@ -335,7 +343,7 @@ public final class PrivateAddressCoordinatorTest { final int randomAddress = 0x8605; // 134.5 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); final LinkAddress addr0 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5. assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, @@ -345,7 +353,7 @@ public final class PrivateAddressCoordinatorTest { // Check whether return address is next prefix of 192.168.134.0/24. final LinkAddress addr1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1); final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork, new LinkAddress("192.168.149.16/19"), null, @@ -355,7 +363,7 @@ public final class PrivateAddressCoordinatorTest { // The conflict range is 128 ~ 159, so the address is 192.168.160.5/24. final LinkAddress addr2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2); final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, new LinkAddress("192.168.129.53/18"), null, @@ -370,7 +378,7 @@ public final class PrivateAddressCoordinatorTest { // The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24. final LinkAddress addr3 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3); final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, new LinkAddress("192.168.188.133/17"), null, @@ -380,7 +388,7 @@ public final class PrivateAddressCoordinatorTest { // Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because // 192.168.134/24 ~ 192.168.255.255/24 is not available. final LinkAddress addr4 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4); final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, new LinkAddress("192.168.3.59/21"), null, @@ -389,7 +397,7 @@ public final class PrivateAddressCoordinatorTest { // Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24. final LinkAddress addr5 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5); final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, new LinkAddress("192.168.68.43/21"), null, @@ -399,7 +407,7 @@ public final class PrivateAddressCoordinatorTest { // Update an upstream that does *not* conflict, check whether return the same address // 192.168.5/24. final LinkAddress addr6 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6); final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6, new LinkAddress("192.168.10.97/21"), null, @@ -408,7 +416,7 @@ public final class PrivateAddressCoordinatorTest { // Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24. final LinkAddress addr7 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7); final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6, new LinkAddress("192.168.0.0/17"), null, @@ -417,7 +425,7 @@ public final class PrivateAddressCoordinatorTest { // Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16. final LinkAddress addr8 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8); } @@ -426,7 +434,7 @@ public final class PrivateAddressCoordinatorTest { final int randomAddress = 0x1f2b2a; // 31.43.42 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); final LinkAddress classC1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42. assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, @@ -437,7 +445,7 @@ public final class PrivateAddressCoordinatorTest { // Check whether return address is next address of prefix 192.168.128.0/17. final LinkAddress classC2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2); final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, new LinkAddress("192.1.2.3/8"), null, @@ -447,7 +455,7 @@ public final class PrivateAddressCoordinatorTest { // Check whether return address is under prefix 172.16.0.0/12. final LinkAddress classB1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1); final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, new LinkAddress("172.28.123.100/14"), null, @@ -458,12 +466,12 @@ public final class PrivateAddressCoordinatorTest { // 172.28.0.0 ~ 172.31.255.255 is not available. // Check whether return address is next address of prefix 172.16.0.0/14. final LinkAddress classB2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2); // Check whether new downstream is next address of address 172.16.0.42/24. final LinkAddress classB3 = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3); final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, new LinkAddress("172.16.0.1/24"), null, @@ -474,7 +482,7 @@ public final class PrivateAddressCoordinatorTest { // Check whether return address is next address of prefix 172.16.1.42/24. final LinkAddress classB4 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4); final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, new LinkAddress("172.16.0.1/13"), null, @@ -485,11 +493,11 @@ public final class PrivateAddressCoordinatorTest { // Check whether return address is next address of prefix 172.16.0.1/13. final LinkAddress classB5 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5); // Check whether return address is next address of prefix 172.24.0.42/24. final LinkAddress classB6 = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6); final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, new LinkAddress("172.24.0.1/12"), null, @@ -500,11 +508,11 @@ public final class PrivateAddressCoordinatorTest { // Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42. final LinkAddress classA1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1); // Check whether new downstream is next address of address 10.31.43.42/24. final LinkAddress classA2 = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2); } @@ -524,7 +532,7 @@ public final class PrivateAddressCoordinatorTest { private void assertReseveredWifiP2pPrefix() throws Exception { LinkAddress address = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(address); final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress); assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix); @@ -544,8 +552,23 @@ public final class PrivateAddressCoordinatorTest { // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address. LinkAddress address = requestDownstreamAddress(mWifiP2pIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_LOCAL, true /* useLastAddress */); assertEquals(mLegacyWifiP2pAddress, address); mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer); } + + @Test + public void testEnableSapAndLohsConcurrently() throws Exception { + // 0x2b05 -> 43.5, 0x8605 -> 134.5 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(0x2b05, 0x8605); + + final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); + assertEquals("Wrong hotspot prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress); + + final LinkAddress localHotspotAddress = requestDownstreamAddress(mLocalHotspotIpServer, + CONNECTIVITY_SCOPE_LOCAL, true /* useLastAddress */); + assertEquals("Wrong local hotspot prefix: ", new LinkAddress("192.168.134.5/24"), + localHotspotAddress); + } }