Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78c744d2 authored by Mark Chien's avatar Mark Chien Committed by Automerger Merge Worker
Browse files

Merge "Make the IP subnet persistent till reboot" am: 818da784 am: fabe5787 am: 17c20405

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1432958

Change-Id: I6d76e970384a3021e1fe519a268627628f45d446
parents 1d970907 17c20405
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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;
+53 −23
Original line number Diff line number Diff line
@@ -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();
    }
}
+11 −7
Original line number Diff line number Diff line
@@ -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);
+92 −70

File changed.

Preview size limit exceeded, changes collapsed.