Loading packages/Tethering/src/android/net/ip/IpServer.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -616,7 +616,7 @@ public class IpServer extends StateMachine { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (enabled) { if (enabled) { mIpv4Address = requestIpv4Address(); mIpv4Address = requestIpv4Address(true /* useLastAddress */); } } if (mIpv4Address == null) { if (mIpv4Address == null) { Loading Loading @@ -661,14 +661,14 @@ public class IpServer extends StateMachine { return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } } private LinkAddress requestIpv4Address() { private LinkAddress requestIpv4Address(final boolean useLastAddress) { if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { return new LinkAddress(BLUETOOTH_IFACE_ADDR); return new LinkAddress(BLUETOOTH_IFACE_ADDR); } } return mPrivateAddressCoordinator.requestDownstreamAddress(this); return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress); } } private boolean startIPv6() { private boolean startIPv6() { Loading Loading @@ -957,7 +957,7 @@ public class IpServer extends StateMachine { } } final LinkAddress deprecatedLinkAddress = mIpv4Address; final LinkAddress deprecatedLinkAddress = mIpv4Address; mIpv4Address = requestIpv4Address(); mIpv4Address = requestIpv4Address(false); if (mIpv4Address == null) { if (mIpv4Address == null) { mLog.e("Fail to request a new downstream prefix"); mLog.e("Fail to request a new downstream prefix"); return; return; Loading packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +53 −23 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.networkstack.tethering; package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.TRANSPORT_VPN; 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.TetheringManager.TETHERING_WIFI_P2P; import static android.net.util.PrefixUtils.asIpPrefix; import static java.util.Arrays.asList; import static java.util.Arrays.asList; Loading @@ -26,9 +28,9 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkAddress; import android.net.Network; import android.net.Network; import android.net.ip.IpServer; import android.net.ip.IpServer; import android.net.util.PrefixUtils; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.SparseArray; import androidx.annotation.Nullable; import androidx.annotation.Nullable; Loading Loading @@ -58,9 +60,6 @@ public class PrivateAddressCoordinator { private static final int MAX_UBYTE = 256; private static final int MAX_UBYTE = 256; private static final int BYTE_MASK = 0xff; 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; private static final byte DEFAULT_ID = (byte) 42; // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream Loading @@ -75,9 +74,12 @@ public class PrivateAddressCoordinator { // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers. // 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 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_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 IpPrefix mTetheringPrefix; private final ConnectivityManager mConnectivityMgr; private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; private final TetheringConfiguration mConfig; // keyed by downstream type(TetheringManager.TETHERING_*). private final SparseArray<LinkAddress> mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { mDownstreams = new ArraySet<>(); mDownstreams = new ArraySet<>(); Loading @@ -86,6 +88,10 @@ public class PrivateAddressCoordinator { mConnectivityMgr = (ConnectivityManager) context.getSystemService( mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); Context.CONNECTIVITY_SERVICE); mConfig = config; 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)); } } /** /** Loading @@ -94,7 +100,8 @@ public class PrivateAddressCoordinator { * UpstreamNetworkState must have an already populated LinkProperties. * UpstreamNetworkState must have an already populated LinkProperties. */ */ public void updateUpstreamPrefix(final UpstreamNetworkState ns) { 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)) { if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) { removeUpstreamPrefix(ns.network); removeUpstreamPrefix(ns.network); return; return; Loading @@ -116,7 +123,7 @@ public class PrivateAddressCoordinator { for (LinkAddress address : linkAddresses) { for (LinkAddress address : linkAddresses) { if (!address.isIpv4()) continue; if (!address.isIpv4()) continue; list.add(PrefixUtils.asIpPrefix(address)); list.add(asIpPrefix(address)); } } return list; return list; Loading Loading @@ -155,21 +162,23 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.removeAll(toBeRemoved); 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, * Pick a random available address and mark its prefix as in use for the provided IpServer, * returns null if there is no available address. * returns null if there is no available address. */ */ @Nullable @Nullable public LinkAddress requestDownstreamAddress(final IpServer ipServer) { public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { if (mConfig.shouldEnableWifiP2pDedicatedIp() if (mConfig.shouldEnableWifiP2pDedicatedIp() && ipServer.interfaceType() == TETHERING_WIFI_P2P) { && ipServer.interfaceType() == TETHERING_WIFI_P2P) { return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS); 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. // Address would be 192.168.[subAddress]/24. final byte[] bytes = mTetheringPrefix.getRawAddress(); final byte[] bytes = mTetheringPrefix.getRawAddress(); final int subAddress = getRandomSubAddr(); final int subAddress = getRandomSubAddr(); Loading @@ -177,9 +186,8 @@ public class PrivateAddressCoordinator { bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); for (int i = 0; i < MAX_UBYTE; i++) { for (int i = 0; i < MAX_UBYTE; i++) { final int newSubNet = (subNet + i) & BYTE_MASK; final int newSubNet = (subNet + i) & BYTE_MASK; if (isReservedSubnet(newSubNet)) continue; bytes[2] = (byte) newSubNet; bytes[2] = (byte) newSubNet; final InetAddress addr; final InetAddress addr; try { try { addr = InetAddress.getByAddress(bytes); addr = InetAddress.getByAddress(bytes); Loading @@ -187,20 +195,23 @@ public class PrivateAddressCoordinator { throw new IllegalStateException("Invalid address, shouldn't happen.", e); throw new IllegalStateException("Invalid address, shouldn't happen.", e); } } final IpPrefix prefix = new IpPrefix(addr, PREFIX_LENGTH); if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue; // 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; mDownstreams.add(ipServer); 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. // No available address. return null; 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. */ /** Get random sub address value. Return value is in 0 ~ 0xffff. */ @VisibleForTesting @VisibleForTesting public int getRandomSubAddr() { public int getRandomSubAddr() { Loading Loading @@ -244,13 +255,24 @@ public class PrivateAddressCoordinator { return prefix1.contains(prefix2.getAddress()); 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 // 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. // 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) { for (IpServer downstream : mDownstreams) { final IpPrefix prefix = getDownstreamPrefix(downstream); final IpPrefix target = getDownstreamPrefix(downstream); if (source.equals(prefix)) return true; if (target == null) continue; if (isConflictPrefix(prefix, target)) return true; } } return false; return false; } } Loading @@ -258,7 +280,7 @@ public class PrivateAddressCoordinator { final LinkAddress address = downstream.getAddress(); final LinkAddress address = downstream.getAddress(); if (address == null) return null; if (address == null) return null; return PrefixUtils.asIpPrefix(address); return asIpPrefix(address); } } void dump(final IndentingPrintWriter pw) { void dump(final IndentingPrintWriter pw) { Loading @@ -268,11 +290,19 @@ public class PrivateAddressCoordinator { pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); } } pw.decreaseIndent(); pw.decreaseIndent(); pw.println("mDownstreams:"); pw.println("mDownstreams:"); pw.increaseIndent(); pw.increaseIndent(); for (IpServer ipServer : mDownstreams) { for (IpServer ipServer : mDownstreams) { pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); } } pw.decreaseIndent(); 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(); } } } } packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +11 −7 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer; Loading Loading @@ -230,7 +231,8 @@ public class IpServerTest { dispatchTetherConnectionChanged(upstreamIface, lp, 0); dispatchTetherConnectionChanged(upstreamIface, lp, 0); } } reset(mNetd, mCallback, mAddressCoordinator); reset(mNetd, mCallback, mAddressCoordinator); when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( mTestAddress); } } private void setUpDhcpServer() throws Exception { private void setUpDhcpServer() throws Exception { Loading @@ -250,7 +252,8 @@ public class IpServerTest { @Before public void setUp() throws Exception { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); 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 */); when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */); mBpfCoordinator = spy(new BpfCoordinator( mBpfCoordinator = spy(new BpfCoordinator( Loading Loading @@ -372,7 +375,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); Loading @@ -393,7 +396,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); Loading Loading @@ -607,7 +610,7 @@ public class IpServerTest { final ArgumentCaptor<LinkProperties> lpCaptor = final ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); 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); inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); // One for ipv4 route, one for ipv6 link local route. // One for ipv4 route, one for ipv6 link local route. inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), Loading @@ -620,11 +623,12 @@ public class IpServerTest { // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals // onNewPrefixRequest callback. // onNewPrefixRequest callback. final LinkAddress newAddress = new LinkAddress("192.168.100.125/24"); 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")); eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); mLooper.dispatchAll(); mLooper.dispatchAll(); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false)); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); verifyNoMoreInteractions(mCallback); verifyNoMoreInteractions(mCallback); Loading packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +92 −70 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/Tethering/src/android/net/ip/IpServer.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -616,7 +616,7 @@ public class IpServer extends StateMachine { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (enabled) { if (enabled) { mIpv4Address = requestIpv4Address(); mIpv4Address = requestIpv4Address(true /* useLastAddress */); } } if (mIpv4Address == null) { if (mIpv4Address == null) { Loading Loading @@ -661,14 +661,14 @@ public class IpServer extends StateMachine { return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } } private LinkAddress requestIpv4Address() { private LinkAddress requestIpv4Address(final boolean useLastAddress) { if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { return new LinkAddress(BLUETOOTH_IFACE_ADDR); return new LinkAddress(BLUETOOTH_IFACE_ADDR); } } return mPrivateAddressCoordinator.requestDownstreamAddress(this); return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress); } } private boolean startIPv6() { private boolean startIPv6() { Loading Loading @@ -957,7 +957,7 @@ public class IpServer extends StateMachine { } } final LinkAddress deprecatedLinkAddress = mIpv4Address; final LinkAddress deprecatedLinkAddress = mIpv4Address; mIpv4Address = requestIpv4Address(); mIpv4Address = requestIpv4Address(false); if (mIpv4Address == null) { if (mIpv4Address == null) { mLog.e("Fail to request a new downstream prefix"); mLog.e("Fail to request a new downstream prefix"); return; return; Loading
packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +53 −23 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.networkstack.tethering; package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.TRANSPORT_VPN; 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.TetheringManager.TETHERING_WIFI_P2P; import static android.net.util.PrefixUtils.asIpPrefix; import static java.util.Arrays.asList; import static java.util.Arrays.asList; Loading @@ -26,9 +28,9 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkAddress; import android.net.Network; import android.net.Network; import android.net.ip.IpServer; import android.net.ip.IpServer; import android.net.util.PrefixUtils; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.SparseArray; import androidx.annotation.Nullable; import androidx.annotation.Nullable; Loading Loading @@ -58,9 +60,6 @@ public class PrivateAddressCoordinator { private static final int MAX_UBYTE = 256; private static final int MAX_UBYTE = 256; private static final int BYTE_MASK = 0xff; 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; private static final byte DEFAULT_ID = (byte) 42; // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream Loading @@ -75,9 +74,12 @@ public class PrivateAddressCoordinator { // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers. // 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 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_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 IpPrefix mTetheringPrefix; private final ConnectivityManager mConnectivityMgr; private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; private final TetheringConfiguration mConfig; // keyed by downstream type(TetheringManager.TETHERING_*). private final SparseArray<LinkAddress> mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { mDownstreams = new ArraySet<>(); mDownstreams = new ArraySet<>(); Loading @@ -86,6 +88,10 @@ public class PrivateAddressCoordinator { mConnectivityMgr = (ConnectivityManager) context.getSystemService( mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); Context.CONNECTIVITY_SERVICE); mConfig = config; 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)); } } /** /** Loading @@ -94,7 +100,8 @@ public class PrivateAddressCoordinator { * UpstreamNetworkState must have an already populated LinkProperties. * UpstreamNetworkState must have an already populated LinkProperties. */ */ public void updateUpstreamPrefix(final UpstreamNetworkState ns) { 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)) { if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) { removeUpstreamPrefix(ns.network); removeUpstreamPrefix(ns.network); return; return; Loading @@ -116,7 +123,7 @@ public class PrivateAddressCoordinator { for (LinkAddress address : linkAddresses) { for (LinkAddress address : linkAddresses) { if (!address.isIpv4()) continue; if (!address.isIpv4()) continue; list.add(PrefixUtils.asIpPrefix(address)); list.add(asIpPrefix(address)); } } return list; return list; Loading Loading @@ -155,21 +162,23 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.removeAll(toBeRemoved); 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, * Pick a random available address and mark its prefix as in use for the provided IpServer, * returns null if there is no available address. * returns null if there is no available address. */ */ @Nullable @Nullable public LinkAddress requestDownstreamAddress(final IpServer ipServer) { public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { if (mConfig.shouldEnableWifiP2pDedicatedIp() if (mConfig.shouldEnableWifiP2pDedicatedIp() && ipServer.interfaceType() == TETHERING_WIFI_P2P) { && ipServer.interfaceType() == TETHERING_WIFI_P2P) { return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS); 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. // Address would be 192.168.[subAddress]/24. final byte[] bytes = mTetheringPrefix.getRawAddress(); final byte[] bytes = mTetheringPrefix.getRawAddress(); final int subAddress = getRandomSubAddr(); final int subAddress = getRandomSubAddr(); Loading @@ -177,9 +186,8 @@ public class PrivateAddressCoordinator { bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); for (int i = 0; i < MAX_UBYTE; i++) { for (int i = 0; i < MAX_UBYTE; i++) { final int newSubNet = (subNet + i) & BYTE_MASK; final int newSubNet = (subNet + i) & BYTE_MASK; if (isReservedSubnet(newSubNet)) continue; bytes[2] = (byte) newSubNet; bytes[2] = (byte) newSubNet; final InetAddress addr; final InetAddress addr; try { try { addr = InetAddress.getByAddress(bytes); addr = InetAddress.getByAddress(bytes); Loading @@ -187,20 +195,23 @@ public class PrivateAddressCoordinator { throw new IllegalStateException("Invalid address, shouldn't happen.", e); throw new IllegalStateException("Invalid address, shouldn't happen.", e); } } final IpPrefix prefix = new IpPrefix(addr, PREFIX_LENGTH); if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue; // 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; mDownstreams.add(ipServer); 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. // No available address. return null; 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. */ /** Get random sub address value. Return value is in 0 ~ 0xffff. */ @VisibleForTesting @VisibleForTesting public int getRandomSubAddr() { public int getRandomSubAddr() { Loading Loading @@ -244,13 +255,24 @@ public class PrivateAddressCoordinator { return prefix1.contains(prefix2.getAddress()); 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 // 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. // 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) { for (IpServer downstream : mDownstreams) { final IpPrefix prefix = getDownstreamPrefix(downstream); final IpPrefix target = getDownstreamPrefix(downstream); if (source.equals(prefix)) return true; if (target == null) continue; if (isConflictPrefix(prefix, target)) return true; } } return false; return false; } } Loading @@ -258,7 +280,7 @@ public class PrivateAddressCoordinator { final LinkAddress address = downstream.getAddress(); final LinkAddress address = downstream.getAddress(); if (address == null) return null; if (address == null) return null; return PrefixUtils.asIpPrefix(address); return asIpPrefix(address); } } void dump(final IndentingPrintWriter pw) { void dump(final IndentingPrintWriter pw) { Loading @@ -268,11 +290,19 @@ public class PrivateAddressCoordinator { pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); } } pw.decreaseIndent(); pw.decreaseIndent(); pw.println("mDownstreams:"); pw.println("mDownstreams:"); pw.increaseIndent(); pw.increaseIndent(); for (IpServer ipServer : mDownstreams) { for (IpServer ipServer : mDownstreams) { pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); } } pw.decreaseIndent(); 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(); } } } }
packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +11 −7 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer; Loading Loading @@ -230,7 +231,8 @@ public class IpServerTest { dispatchTetherConnectionChanged(upstreamIface, lp, 0); dispatchTetherConnectionChanged(upstreamIface, lp, 0); } } reset(mNetd, mCallback, mAddressCoordinator); reset(mNetd, mCallback, mAddressCoordinator); when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( mTestAddress); } } private void setUpDhcpServer() throws Exception { private void setUpDhcpServer() throws Exception { Loading @@ -250,7 +252,8 @@ public class IpServerTest { @Before public void setUp() throws Exception { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); 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 */); when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */); mBpfCoordinator = spy(new BpfCoordinator( mBpfCoordinator = spy(new BpfCoordinator( Loading Loading @@ -372,7 +375,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); Loading @@ -393,7 +396,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); Loading Loading @@ -607,7 +610,7 @@ public class IpServerTest { final ArgumentCaptor<LinkProperties> lpCaptor = final ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); 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); inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); // One for ipv4 route, one for ipv6 link local route. // One for ipv4 route, one for ipv6 link local route. inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), Loading @@ -620,11 +623,12 @@ public class IpServerTest { // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals // onNewPrefixRequest callback. // onNewPrefixRequest callback. final LinkAddress newAddress = new LinkAddress("192.168.100.125/24"); 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")); eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); mLooper.dispatchAll(); mLooper.dispatchAll(); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false)); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); verifyNoMoreInteractions(mCallback); verifyNoMoreInteractions(mCallback); Loading
packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +92 −70 File changed.Preview size limit exceeded, changes collapsed. Show changes