diff options
4 files changed, 160 insertions, 104 deletions
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 336124dc1b90..52d59fcdc19b 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -616,7 +616,7 @@ public class IpServer extends StateMachine { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (enabled) { - mIpv4Address = requestIpv4Address(); + mIpv4Address = requestIpv4Address(true /* useLastAddress */); } if (mIpv4Address == null) { @@ -661,14 +661,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() { @@ -957,7 +957,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 b285849f9edf..6276c4e2aa7d 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/packages/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<LinkAddress> 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 (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; } @@ -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/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 1a976adc60e0..2eb75895ac3e 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; @@ -230,7 +231,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 { @@ -250,7 +252,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( @@ -372,7 +375,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); @@ -393,7 +396,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); @@ -607,7 +610,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), @@ -620,11 +623,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 7b6632c36f24..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 @@ -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); + 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); + + 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); } |