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

Commit 98ed3325 authored by Xiao Ma's avatar Xiao Ma
Browse files

Restore the default interface MTU when disconnecting from Wi-Fi AP.

Bug: 113350007
Test: atest FrameworksNetTests NetworkStackTests
Test: atest NetworkStackIntegrationTests
Test: manual test
Change-Id: I4b0ecdb63df567f0cbbb13d2b48bbfaaa7aee4d9
parent 03886222
Loading
Loading
Loading
Loading
+36 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.net.ip;
import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;

import static com.android.server.util.NetworkStackConstants.ETHER_MTU;
import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;

import android.annotation.NonNull;
@@ -48,6 +49,7 @@ import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -69,6 +71,8 @@ import com.android.server.NetworkStackService.NetworkStackServiceManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
@@ -380,6 +384,8 @@ public class IpClient extends StateMachine {
    private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();

    public static class Dependencies {
        private static final String TAG = "IpClient.Dependencies";

        /**
         * Get interface parameters for the specified interface.
         */
@@ -387,6 +393,18 @@ public class IpClient extends StateMachine {
            return InterfaceParams.getByName(ifname);
        }

        /**
         * Get the current MTU for the specified interface.
         */
        public int getInterfaceMtu(String ifname) {
            try {
                return NetworkInterface.getByName(ifname).getMTU();
            } catch (SocketException e) {
                Log.e(TAG, "unexpected failure to get the interface MTU");
                return ETHER_MTU;
            }
        }

        /**
         * Get a INetd connector.
         */
@@ -850,10 +868,14 @@ public class IpClient extends StateMachine {
        return shouldLog;
    }

    private void logError(String fmt, Object... args) {
    private void logError(String fmt, Throwable e, Object... args) {
        final String msg = "ERROR " + String.format(fmt, args);
        Log.e(mTag, msg);
        mLog.log(msg);
        Log.e(mTag, msg, e);
        mLog.e(msg, e);
    }

    private void logError(String fmt, Object... args) {
        logError(fmt, null, args);
    }

    // This needs to be called with care to ensure that our LinkProperties
@@ -1351,6 +1373,17 @@ public class IpClient extends StateMachine {
                // There's no DHCPv4 for which to wait; proceed to stopped.
                deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
            }

            // Restore the interface MTU to initial value if it has changed.
            final int mtu = mDependencies.getInterfaceMtu(mInterfaceName);
            try {
                if (mtu != mInterfaceParams.defaultMtu) {
                    mNetd.interfaceSetMtu(mInterfaceName, mInterfaceParams.defaultMtu);
                }
            } catch (RemoteException | ServiceSpecificException e) {
                logError("Couldn't reset MTU from "
                        + mtu + " to " + mInterfaceParams.defaultMtu + ": " + e);
            }
        }

        @Override
+2 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ public final class NetworkStackConstants {
    public static final int ETHER_TYPE_IPV4 = 0x0800;
    public static final int ETHER_TYPE_IPV6 = 0x86dd;
    public static final int ETHER_HEADER_LEN = 14;
    public static final int ETHER_MTU = 1500;

    /**
     * ARP constants.
@@ -97,6 +98,7 @@ public final class NetworkStackConstants {
    public static final int IPV6_PROTOCOL_OFFSET = 6;
    public static final int IPV6_SRC_ADDR_OFFSET = 8;
    public static final int IPV6_DST_ADDR_OFFSET = 24;
    public static final int IPV6_MIN_MTU = 1280;

    /**
     * ICMPv6 constants.
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ android_test {
        "androidx.annotation_annotation",
        "androidx.test.rules",
        "mockito-target-extended-minus-junit4",
        "net-tests-utils",
        "NetworkStackBase",
        "testables",
    ],
+52 −18
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.NetworkObserverRegistry;
import com.android.server.NetworkStackService.NetworkStackServiceManager;
import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
import com.android.testutils.HandlerUtilsKt;

import org.junit.After;
import org.junit.Before;
@@ -158,7 +159,8 @@ public class IpClientIntegrationTest {
    private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
            SERVER_ADDR, PREFIX_LENGTH);
    private static final String HOSTNAME = "testhostname";
    private static final short MTU = 1500;
    private static final int TEST_DEFAULT_MTU = 1500;
    private static final int TEST_MIN_MTU = 1280;

    private static class TapPacketReader extends PacketReader {
        private final ParcelFileDescriptor mTapFd;
@@ -203,6 +205,7 @@ public class IpClientIntegrationTest {
    private class Dependencies extends IpClient.Dependencies {
        private boolean mIsDhcpLeaseCacheEnabled;
        private boolean mIsDhcpRapidCommitEnabled;
        private int mMtu = TEST_DEFAULT_MTU;

        public void setDhcpLeaseCacheEnabled(final boolean enable) {
            mIsDhcpLeaseCacheEnabled = enable;
@@ -212,6 +215,10 @@ public class IpClientIntegrationTest {
            mIsDhcpRapidCommitEnabled = enable;
        }

        public void setMtu(final int mtu) {
            mMtu = mtu;
        }

        @Override
        public INetd getNetd(Context context) {
            return mNetd;
@@ -242,6 +249,11 @@ public class IpClientIntegrationTest {
                }
            };
        }

        @Override
        public int getInterfaceMtu(String ifName) {
            return mMtu;
        }
    }

    @Before
@@ -345,7 +357,7 @@ public class IpClientIntegrationTest {
    }

    private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet,
            final Integer leaseTimeSec) {
            final Integer leaseTimeSec, final short mtu) {
        return DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
                false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
                CLIENT_ADDR /* yourIp */, packet.getClientMac(), leaseTimeSec,
@@ -353,11 +365,11 @@ public class IpClientIntegrationTest {
                Collections.singletonList(SERVER_ADDR) /* gateways */,
                Collections.singletonList(SERVER_ADDR) /* dnsServers */,
                SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME,
                false /* metered */, MTU);
                false /* metered */, mtu);
    }

    private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet,
            final Integer leaseTimeSec) {
            final Integer leaseTimeSec, final short mtu) {
        return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
                false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
                CLIENT_ADDR /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(),
@@ -365,7 +377,7 @@ public class IpClientIntegrationTest {
                Collections.singletonList(SERVER_ADDR) /* gateways */,
                Collections.singletonList(SERVER_ADDR) /* dnsServers */,
                SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME,
                false /* metered */, MTU);
                false /* metered */, mtu);
    }

    private static ByteBuffer buildDhcpNakPacket(final DhcpPacket packet) {
@@ -397,7 +409,7 @@ public class IpClientIntegrationTest {
    }

    private void assertIpMemoryStoreNetworkAttributes(final Integer leaseTimeSec,
            final long startTime) {
            final long startTime, final int mtu) {
        final ArgumentCaptor<NetworkAttributes> networkAttributes =
                ArgumentCaptor.forClass(NetworkAttributes.class);

@@ -416,7 +428,7 @@ public class IpClientIntegrationTest {
            assertTrue(lowerBound < expiry);
        }
        assertEquals(Collections.singletonList(SERVER_ADDR), naValueCaptured.dnsAddresses);
        assertEquals(new Integer((int) MTU), naValueCaptured.mtu);
        assertEquals(new Integer(mtu), naValueCaptured.mtu);
    }

    private void assertIpMemoryNeverStoreNetworkAttributes() {
@@ -433,13 +445,16 @@ public class IpClientIntegrationTest {
        while ((packet = getNextDhcpPacket()) != null) {
            if (packet instanceof DhcpDiscoverPacket) {
                if (isDhcpRapidCommitEnabled) {
                    sendResponse(buildDhcpAckPacket(packet, leaseTimeSec));
                    sendResponse(buildDhcpAckPacket(packet, leaseTimeSec,
                            (short) mDependencies.getInterfaceMtu(mIfaceName)));
                } else {
                    sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec));
                    sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec,
                            (short) mDependencies.getInterfaceMtu(mIfaceName)));
                }
            } else if (packet instanceof DhcpRequestPacket) {
                final ByteBuffer byteBuffer = isSuccessLease
                        ? buildDhcpAckPacket(packet, leaseTimeSec)
                        ? buildDhcpAckPacket(packet, leaseTimeSec,
                                (short) mDependencies.getInterfaceMtu(mIfaceName))
                        : buildDhcpNakPacket(packet);
                sendResponse(byteBuffer);
            } else {
@@ -487,7 +502,7 @@ public class IpClientIntegrationTest {
        final long currentTime = System.currentTimeMillis();
        performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
                true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */);
        assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime);
        assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
    }

    @Test
@@ -502,7 +517,7 @@ public class IpClientIntegrationTest {
        final long currentTime = System.currentTimeMillis();
        performDhcpHandshake(true /* isSuccessLease */, INFINITE_LEASE,
                true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */);
        assertIpMemoryStoreNetworkAttributes(INFINITE_LEASE, currentTime);
        assertIpMemoryStoreNetworkAttributes(INFINITE_LEASE, currentTime, TEST_DEFAULT_MTU);
    }

    @Test
@@ -510,7 +525,7 @@ public class IpClientIntegrationTest {
        final long currentTime = System.currentTimeMillis();
        performDhcpHandshake(true /* isSuccessLease */, null /* no lease time */,
                true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */);
        assertIpMemoryStoreNetworkAttributes(null, currentTime);
        assertIpMemoryStoreNetworkAttributes(null, currentTime, TEST_DEFAULT_MTU);
    }

    @Test
@@ -527,7 +542,7 @@ public class IpClientIntegrationTest {
        final long currentTime = System.currentTimeMillis();
        performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
                true /* isDhcpLeaseCacheEnabled */, true /* isDhcpRapidCommitEnabled */);
        assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime);
        assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
    }

    @Test
@@ -536,7 +551,7 @@ public class IpClientIntegrationTest {
                new NetworkAttributes.Builder()
                    .setAssignedV4Address(CLIENT_ADDR)
                    .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid
                    .setMtu(new Integer(MTU))
                    .setMtu(new Integer(TEST_DEFAULT_MTU))
                    .setGroupHint(TEST_GROUPHINT)
                    .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
                    .build(), false /* timeout */);
@@ -549,7 +564,7 @@ public class IpClientIntegrationTest {
                 new NetworkAttributes.Builder()
                    .setAssignedV4Address(CLIENT_ADDR)
                    .setAssignedV4AddressExpiry(EXPIRED_LEASE)
                    .setMtu(new Integer(MTU))
                    .setMtu(new Integer(TEST_DEFAULT_MTU))
                    .setGroupHint(TEST_GROUPHINT)
                    .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
                    .build(), false /* timeout */);
@@ -568,7 +583,7 @@ public class IpClientIntegrationTest {
                new NetworkAttributes.Builder()
                    .setAssignedV4Address(CLIENT_ADDR)
                    .setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000)
                    .setMtu(new Integer(MTU))
                    .setMtu(new Integer(TEST_DEFAULT_MTU))
                    .setGroupHint(TEST_GROUPHINT)
                    .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
                    .build(), true /* timeout */);
@@ -579,7 +594,7 @@ public class IpClientIntegrationTest {
    public void testDhcpClientStartWithCachedLeaseWithoutIPAddress() throws Exception {
        final DhcpPacket packet = getReplyFromDhcpLease(
                new NetworkAttributes.Builder()
                    .setMtu(new Integer(MTU))
                    .setMtu(new Integer(TEST_DEFAULT_MTU))
                    .setGroupHint(TEST_GROUPHINT)
                    .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
                    .build(), false /* timeout */);
@@ -593,4 +608,23 @@ public class IpClientIntegrationTest {
        final DhcpPacket packet = getNextDhcpPacket();
        assertTrue(DhcpDiscoverPacket.class.isInstance(packet));
    }

    @Test
    public void testRestoreInitialInterfaceMtu() throws Exception {
        final long currentTime = System.currentTimeMillis();

        // check the initial interface MTU
        assertTrue(mDependencies.getInterfaceMtu(mIfaceName) == TEST_DEFAULT_MTU);

        // change the MTU and pass the new MTU into DHCPOFFER and DHCPACK packet
        mDependencies.setMtu(TEST_MIN_MTU);
        performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
                true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */);
        assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_MIN_MTU);

        mIpc.shutdown();
        HandlerUtilsKt.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
        // verify that mtu indeed has been restored
        verify(mNetd, times(1)).interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU);
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ public class IpClientTest {
    private static final String INVALID = "INVALID";
    private static final String TEST_IFNAME = "test_wlan0";
    private static final int TEST_IFINDEX = 1001;
    private static final int TEST_MTU = 1500;
    // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
    private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
    private static final int TEST_TIMEOUT_MS = 400;
@@ -122,6 +123,7 @@ public class IpClientTest {
        when(mDependencies.getInterfaceParams(any())).thenReturn(mInterfaceParams);
        when(mDependencies.getIpMemoryStore(mContext, mNetworkStackServiceManager))
                .thenReturn(mIpMemoryStore);
        when(mDependencies.getInterfaceMtu(TEST_IFNAME)).thenReturn(TEST_MTU);

        mIfParams = null;
    }