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

Commit 87dfff62 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by android-build-merger
Browse files

Merge "Switch DHCP server based on global setting" am: 846c80ac

am: 85b40cb7

Change-Id: Icea0fa2a4a76a680016bdfd4516d8213ad68729f
parents 5ecc085b 85b40cb7
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -1126,7 +1126,9 @@ public class Tethering extends BaseNetworkObserver {
    }

    public String[] getTetheredDhcpRanges() {
        return mConfig.dhcpRanges;
        // TODO: this is only valid for the old DHCP server. Latest search suggests it is only used
        // by WifiP2pServiceImpl to start dnsmasq: remove/deprecate after migrating callers.
        return mConfig.legacyDhcpRanges;
    }

    public String[] getErroredIfaces() {
@@ -1297,13 +1299,17 @@ public class Tethering extends BaseNetworkObserver {
                return false;
            }
            // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
            // Legacy DHCP server is disabled if passed an empty ranges array
            final String[] dhcpRanges = cfg.enableLegacyDhcpServer
                    ? cfg.legacyDhcpRanges
                    : new String[0];
            try {
                // TODO: Find a more accurate method name (startDHCPv4()?).
                mNMService.startTethering(cfg.dhcpRanges);
                mNMService.startTethering(dhcpRanges);
            } catch (Exception e) {
                try {
                    mNMService.stopTethering();
                    mNMService.startTethering(cfg.dhcpRanges);
                    mNMService.startTethering(dhcpRanges);
                } catch (Exception ee) {
                    mLog.e(ee);
                    transitionTo(mStartTetheringErrorState);
@@ -1972,7 +1978,7 @@ public class Tethering extends BaseNetworkObserver {
        final TetherState tetherState = new TetherState(
                new TetherInterfaceStateMachine(
                    iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
                    makeControlCallback(iface), mDeps));
                    makeControlCallback(iface), mConfig.enableLegacyDhcpServer, mDeps));
        mTetherStates.put(iface, tetherState);
        tetherState.stateMachine.start();
    }
+70 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.connectivity.tethering;

import static android.net.NetworkUtils.numericToInetAddress;
import static android.net.util.NetworkConstants.asByte;
import static android.net.util.NetworkConstants.FF;
import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
@@ -27,8 +28,9 @@ import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
import android.net.ip.InterfaceController;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
@@ -49,6 +51,7 @@ import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -73,6 +76,13 @@ public class TetherInterfaceStateMachine extends StateMachine {
    private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
    private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;

    // TODO: have PanService use some visible version of this constant
    private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
    private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;

    // TODO: have this configurable
    private static final int DHCP_LEASE_TIME_SECS = 3600;

    private final static String TAG = "TetherInterfaceSM";
    private final static boolean DBG = false;
    private final static boolean VDBG = false;
@@ -119,6 +129,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
    private final String mIfaceName;
    private final int mInterfaceType;
    private final LinkProperties mLinkProperties;
    private final boolean mUsingLegacyDhcp;

    private final TetheringDependencies mDeps;

@@ -134,12 +145,13 @@ public class TetherInterfaceStateMachine extends StateMachine {
    // Advertisements (otherwise, we do not add them to mLinkProperties at all).
    private LinkProperties mLastIPv6LinkProperties;
    private RouterAdvertisementDaemon mRaDaemon;
    private DhcpServer mDhcpServer;
    private RaParams mLastRaParams;

    public TetherInterfaceStateMachine(
            String ifaceName, Looper looper, int interfaceType, SharedLog log,
            INetworkManagementService nMService, INetworkStatsService statsService,
            IControlsTethering tetherController,
            IControlsTethering tetherController, boolean usingLegacyDhcp,
            TetheringDependencies deps) {
        super(ifaceName, looper);
        mLog = log.forSubComponent(ifaceName);
@@ -151,6 +163,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
        mIfaceName = ifaceName;
        mInterfaceType = interfaceType;
        mLinkProperties = new LinkProperties();
        mUsingLegacyDhcp = usingLegacyDhcp;
        mDeps = deps;
        resetLinkProperties();
        mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
@@ -188,6 +201,52 @@ public class TetherInterfaceStateMachine extends StateMachine {

    private boolean startIPv4() { return configureIPv4(true); }

    private boolean startDhcp(Inet4Address addr, int prefixLen) {
        if (mUsingLegacyDhcp) {
            return true;
        }

        final InterfaceParams ifaceParams = mDeps.getInterfaceParams(mIfaceName);
        if (ifaceParams == null) {
            Log.e(TAG, "Failed to find interface params for DHCPv4");
            return false;
        }
        final DhcpServingParams params;
        try {
            params = new DhcpServingParams.Builder()
                    .setDefaultRouters(addr)
                    .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
                    .setDnsServers(addr)
                    .setServerAddr(new LinkAddress(addr, prefixLen))
                    .build();
            // TODO: also advertise link MTU
        } catch (DhcpServingParams.InvalidParameterException e) {
            Log.e(TAG, "Invalid DHCP parameters", e);
            return false;
        }

        mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), ifaceParams, params,
                mLog.forSubComponent("DHCP"));
        mDhcpServer.start();
        return true;
    }

    private void stopDhcp() {
        if (mDhcpServer != null) {
            mDhcpServer.stop();
            mDhcpServer = null;
        }
    }

    private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) {
        if (enable) {
            return startDhcp(addr, prefixLen);
        } else {
            stopDhcp();
            return true;
        }
    }

    private void stopIPv4() {
        configureIPv4(false);
        // NOTE: All of configureIPv4() will be refactored out of existence
@@ -210,8 +269,9 @@ public class TetherInterfaceStateMachine extends StateMachine {
            ipAsString = getRandomWifiIPv4Address();
            prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
        } else {
            // Nothing to do, BT does this elsewhere.
            return true;
            // BT configures the interface elsewhere: only start DHCP.
            final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR);
            return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
        }

        final LinkAddress linkAddr;
@@ -222,7 +282,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
                return false;
            }

            InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
            InetAddress addr = numericToInetAddress(ipAsString);
            linkAddr = new LinkAddress(addr, prefixLen);
            ifcg.setLinkAddress(linkAddr);
            if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
@@ -239,6 +299,10 @@ public class TetherInterfaceStateMachine extends StateMachine {
            }
            ifcg.clearFlag("running");
            mNMService.setInterfaceConfig(mIfaceName, ifcg);

            if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) {
                return false;
            }
        } catch (Exception e) {
            mLog.e("Error configuring interface " + e);
            return false;
@@ -258,7 +322,7 @@ public class TetherInterfaceStateMachine extends StateMachine {

    private String getRandomWifiIPv4Address() {
        try {
            byte[] bytes = NetworkUtils.numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
            byte[] bytes = numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
            bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
            return InetAddress.getByAddress(bytes).getHostAddress();
        } catch (Exception e) {
+20 −7
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;

import static com.android.internal.R.array.config_mobile_hotspot_provision_app;
import static com.android.internal.R.array.config_tether_bluetooth_regexs;
import static com.android.internal.R.array.config_tether_dhcp_range;
@@ -30,15 +32,16 @@ import static com.android.internal.R.array.config_tether_wifi_regexs;
import static com.android.internal.R.bool.config_tether_upstream_automatic;
import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui;

import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.util.SharedLog;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R;

import java.io.PrintWriter;
import java.util.ArrayList;
@@ -68,12 +71,13 @@ public class TetheringConfiguration {
    public static final int DUN_REQUIRED = 1;
    public static final int DUN_UNSPECIFIED = 2;

    // Default ranges used for the legacy DHCP server.
    // USB is  192.168.42.1 and 255.255.255.0
    // Wifi is 192.168.43.1 and 255.255.255.0
    // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
    // with 255.255.255.0
    // P2P is 192.168.49.1 and 255.255.255.0
    private static final String[] DHCP_DEFAULT_RANGE = {
    private static final String[] LEGACY_DHCP_DEFAULT_RANGE = {
        "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
        "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
        "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
@@ -89,8 +93,9 @@ public class TetheringConfiguration {
    public final boolean isDunRequired;
    public final boolean chooseUpstreamAutomatically;
    public final Collection<Integer> preferredUpstreamIfaceTypes;
    public final String[] dhcpRanges;
    public final String[] legacyDhcpRanges;
    public final String[] defaultIPv4DNS;
    public final boolean enableLegacyDhcpServer;

    public final String[] provisioningApp;
    public final String provisioningAppNoUi;
@@ -112,8 +117,9 @@ public class TetheringConfiguration {
        preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
        isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);

        dhcpRanges = getDhcpRanges(ctx);
        legacyDhcpRanges = getLegacyDhcpRanges(ctx);
        defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
        enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx);

        provisioningApp = getResourceStringArray(ctx, config_mobile_hotspot_provision_app);
        provisioningAppNoUi = getProvisioningAppNoUi(ctx);
@@ -150,7 +156,7 @@ public class TetheringConfiguration {
        dumpStringArray(pw, "preferredUpstreamIfaceTypes",
                preferredUpstreamNames(preferredUpstreamIfaceTypes));

        dumpStringArray(pw, "dhcpRanges", dhcpRanges);
        dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges);
        dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS);

        dumpStringArray(pw, "provisioningApp", provisioningApp);
@@ -276,12 +282,12 @@ public class TetheringConfiguration {
        return false;
    }

    private static String[] getDhcpRanges(Context ctx) {
    private static String[] getLegacyDhcpRanges(Context ctx) {
        final String[] fromResource = getResourceStringArray(ctx, config_tether_dhcp_range);
        if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) {
            return fromResource;
        }
        return copy(DHCP_DEFAULT_RANGE);
        return copy(LEGACY_DHCP_DEFAULT_RANGE);
    }

    private static String getProvisioningAppNoUi(Context ctx) {
@@ -309,6 +315,13 @@ public class TetheringConfiguration {
        }
    }

    private static boolean getEnableLegacyDhcpServer(Context ctx) {
        // TODO: make the default false (0) and update javadoc in Settings.java
        final ContentResolver cr = ctx.getContentResolver();
        final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
        return intVal != 0;
    }

    private static String[] copy(String[] strarray) {
        return Arrays.copyOf(strarray, strarray.length);
    }
+8 −0
Original line number Diff line number Diff line
@@ -19,11 +19,14 @@ package com.android.server.connectivity.tethering;
import android.content.Context;
import android.net.INetd;
import android.net.NetworkRequest;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams;
import android.net.util.NetdService;
import android.os.Handler;
import android.net.util.SharedLog;
import android.os.Looper;

import com.android.internal.util.StateMachine;

@@ -69,4 +72,9 @@ public class TetheringDependencies {
    public NetworkRequest getDefaultNetworkRequest() {
        return null;
    }

    public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface, DhcpServingParams params,
            SharedLog log) {
        return new DhcpServer(looper, iface, params, log);
    }
}
+78 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.connectivity.tethering;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
@@ -23,7 +24,9 @@ import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -40,9 +43,15 @@ import static com.android.server.connectivity.tethering.IControlsTethering.STATE

import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
import android.net.util.SharedLog;
import android.os.INetworkManagementService;
@@ -58,6 +67,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -68,33 +78,58 @@ public class TetherInterfaceStateMachineTest {
    private static final String IFACE_NAME = "testnet1";
    private static final String UPSTREAM_IFACE = "upstream0";
    private static final String UPSTREAM_IFACE2 = "upstream1";
    private static final int DHCP_LEASE_TIME_SECS = 3600;

    private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
            IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);

    @Mock private INetworkManagementService mNMService;
    @Mock private INetworkStatsService mStatsService;
    @Mock private IControlsTethering mTetherHelper;
    @Mock private InterfaceConfiguration mInterfaceConfiguration;
    @Mock private SharedLog mSharedLog;
    @Mock private DhcpServer mDhcpServer;
    @Mock private RouterAdvertisementDaemon mRaDaemon;
    @Mock private TetheringDependencies mTetheringDependencies;

    @Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor;

    private final TestLooper mLooper = new TestLooper();
    private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
            ArgumentCaptor.forClass(LinkProperties.class);
    private TetherInterfaceStateMachine mTestedSm;

    private void initStateMachine(int interfaceType) throws Exception {
        initStateMachine(interfaceType, false /* usingLegacyDhcp */);
    }

    private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
        mTestedSm = new TetherInterfaceStateMachine(
                IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
                mNMService, mStatsService, mTetherHelper, mTetheringDependencies);
                mNMService, mStatsService, mTetherHelper, usingLegacyDhcp,
                mTetheringDependencies);
        mTestedSm.start();
        // Starting the state machine always puts us in a consistent state and notifies
        // the rest of the world that we've changed from an unknown to available state.
        mLooper.dispatchAll();
        reset(mNMService, mStatsService, mTetherHelper);
        when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
        when(mTetheringDependencies.makeDhcpServer(
                any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer);
        when(mTetheringDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
        when(mTetheringDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);

        when(mRaDaemon.start()).thenReturn(true);
    }

    private void initTetheredStateMachine(int interfaceType, String upstreamIface)
            throws Exception {
        initTetheredStateMachine(interfaceType, upstreamIface, false);
    }

    private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception {
        initStateMachine(interfaceType);
    private void initTetheredStateMachine(int interfaceType, String upstreamIface,
            boolean usingLegacyDhcp) throws Exception {
        initStateMachine(interfaceType, usingLegacyDhcp);
        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
        if (upstreamIface != null) {
            dispatchTetherConnectionChanged(upstreamIface);
@@ -112,7 +147,7 @@ public class TetherInterfaceStateMachineTest {
    public void startsOutAvailable() {
        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
                mTetheringDependencies);
                false /* usingLegacyDhcp */, mTetheringDependencies);
        mTestedSm.start();
        mLooper.dispatchAll();
        verify(mTetherHelper).updateInterfaceState(
@@ -345,6 +380,45 @@ public class TetherInterfaceStateMachineTest {
        }
    }

    @Test
    public void startsDhcpServer() throws Exception {
        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
        dispatchTetherConnectionChanged(UPSTREAM_IFACE);

        assertDhcpStarted(new IpPrefix("192.168.43.0/24"));
    }

    @Test
    public void startsDhcpServerOnBluetooth() throws Exception {
        initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
        dispatchTetherConnectionChanged(UPSTREAM_IFACE);

        assertDhcpStarted(new IpPrefix("192.168.44.0/24"));
    }

    @Test
    public void doesNotStartDhcpServerIfDisabled() throws Exception {
        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
        dispatchTetherConnectionChanged(UPSTREAM_IFACE);

        verify(mTetheringDependencies, never()).makeDhcpServer(any(), any(), any(), any());
    }

    private void assertDhcpStarted(IpPrefix expectedPrefix) {
        verify(mTetheringDependencies, times(1)).makeDhcpServer(
                eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog));
        verify(mDhcpServer, times(1)).start();
        final DhcpServingParams params = mDhcpParamsCaptor.getValue();
        // Last address byte is random
        assertTrue(expectedPrefix.contains(params.serverAddr.getAddress()));
        assertEquals(expectedPrefix.getPrefixLength(), params.serverAddr.getPrefixLength());
        assertEquals(1, params.defaultRouters.size());
        assertEquals(params.serverAddr.getAddress(), params.defaultRouters.iterator().next());
        assertEquals(1, params.dnsServers.size());
        assertEquals(params.serverAddr.getAddress(), params.dnsServers.iterator().next());
        assertEquals(DHCP_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
    }

    /**
     * Send a command to the state machine under test, and run the event loop to idle.
     *
Loading