blob: 1c161fef0bd67f0a5677b0a432f7ab764b0e82c4 [file] [log] [blame]
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.ip;
18
Lorenzo Colittid17b7282022-01-25 17:57:39 +090019import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
Xiao Mac00a7932019-06-03 10:30:04 +090020import static android.net.dhcp.DhcpClient.EXPIRED_LEASE;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090021import static android.net.dhcp.DhcpPacket.DHCP_BOOTREQUEST;
22import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
Xiao Ma6e2818b2020-06-22 01:18:22 +090023import static android.net.dhcp.DhcpPacket.DHCP_IPV6_ONLY_PREFERRED;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090024import static android.net.dhcp.DhcpPacket.DHCP_MAGIC_COOKIE;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090025import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
26import static android.net.dhcp.DhcpPacket.ENCAP_L2;
Xiao Ma7b60bfa2019-12-09 10:23:32 +090027import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
Xiao Mac00a7932019-06-03 10:30:04 +090028import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
Xiao Ma6e2818b2020-06-22 01:18:22 +090029import static android.net.dhcp.DhcpPacket.MIN_V6ONLY_WAIT_MS;
Remi NGUYEN VANc2ec05d2020-04-06 16:22:56 +090030import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable;
Xiao Maac371ef2021-09-15 03:37:41 +000031import static android.net.ip.IpClientLinkObserver.CLAT_PREFIX;
Xiao Ma148f5742022-06-06 11:20:33 +090032import static android.net.ip.IpClientLinkObserver.CONFIG_SOCKET_RECV_BUFSIZE;
Xiao Ma69a936a2021-04-21 08:14:44 +000033import static android.net.ip.IpReachabilityMonitor.MIN_NUD_SOLICIT_NUM;
34import static android.net.ip.IpReachabilityMonitor.NUD_MCAST_RESOLICIT_NUM;
Xiao Ma374387c2021-11-02 02:25:55 +000035import static android.net.ip.IpReachabilityMonitor.nudEventTypeToInt;
Xiao Mac00a7932019-06-03 10:30:04 +090036import static android.net.ipmemorystore.Status.SUCCESS;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +090037import static android.system.OsConstants.ETH_P_IPV6;
Lorenzo Colitti5e384442020-04-26 20:18:04 +090038import static android.system.OsConstants.IFA_F_TEMPORARY;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +090039import static android.system.OsConstants.IPPROTO_ICMPV6;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +090040
Remi NGUYEN VAN5b00d422020-06-08 15:34:22 +090041import static com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress;
42import static com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address;
Remi NGUYEN VANe3cd6c42020-09-28 19:03:05 +090043import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
44import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST;
45import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
Xiao Ma8a0b7672021-04-19 08:33:29 +000046import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
Remi NGUYEN VANe3cd6c42020-09-28 19:03:05 +090047import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
Remi NGUYEN VANe3cd6c42020-09-28 19:03:05 +090048import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_OFFSET;
Xiao Ma60175d22021-06-02 12:28:40 +000049import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
Xiao Ma002dd5a2020-12-22 01:14:49 +000050import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
Xiao Ma60175d22021-06-02 12:28:40 +000051import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
Remi NGUYEN VANe3cd6c42020-09-28 19:03:05 +090052import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
53import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY;
Xiao Maaf321442021-02-05 09:04:42 +000054import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST;
Xiao Ma002dd5a2020-12-22 01:14:49 +000055import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST;
Remi NGUYEN VANe3cd6c42020-09-28 19:03:05 +090056import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
Remi NGUYEN VANe3cd6c42020-09-28 19:03:05 +090057import static com.android.net.module.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET;
Xiao Ma69a936a2021-04-21 08:14:44 +000058import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE;
Xiao Ma60175d22021-06-02 12:28:40 +000059import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER;
60import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
Xiao Ma002dd5a2020-12-22 01:14:49 +000061import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS;
62import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK;
Xiao Ma326820d2020-11-24 16:21:04 +090063import static com.android.testutils.MiscAsserts.assertThrows;
Xiao Mac4fa89c2021-12-24 08:48:48 +000064import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
Lorenzo Colittid17b7282022-01-25 17:57:39 +090065import static com.android.testutils.TestPermissionUtil.runAsShell;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090066
67import static junit.framework.Assert.fail;
68
Xiao Ma7b60bfa2019-12-09 10:23:32 +090069import static org.junit.Assert.assertArrayEquals;
Xiao Mac00a7932019-06-03 10:30:04 +090070import static org.junit.Assert.assertEquals;
Lorenzo Colitti32336c92020-02-19 19:53:59 +090071import static org.junit.Assert.assertFalse;
Xiao Ma16b21ef2020-01-22 17:51:26 +090072import static org.junit.Assert.assertNotEquals;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090073import static org.junit.Assert.assertNotNull;
Xiao Ma8bcd6732019-08-26 17:24:26 +090074import static org.junit.Assert.assertNull;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090075import static org.junit.Assert.assertTrue;
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +090076import static org.junit.Assume.assumeFalse;
77import static org.junit.Assume.assumeTrue;
Lorenzo Colitti31c7a512020-04-22 16:03:41 +090078import static org.mockito.ArgumentMatchers.anyInt;
Xiao Ma7ae2ec32021-09-29 06:07:15 +000079import static org.mockito.ArgumentMatchers.anyLong;
Lorenzo Colitti31c7a512020-04-22 16:03:41 +090080import static org.mockito.ArgumentMatchers.contains;
81import static org.mockito.ArgumentMatchers.longThat;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090082import static org.mockito.Mockito.any;
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +090083import static org.mockito.Mockito.argThat;
Remi NGUYEN VAN5304b782020-09-01 09:40:41 +090084import static org.mockito.Mockito.atLeastOnce;
Xiao Mac00a7932019-06-03 10:30:04 +090085import static org.mockito.Mockito.doAnswer;
Xiao Ma1ef8fd82019-07-16 19:16:39 +090086import static org.mockito.Mockito.doThrow;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090087import static org.mockito.Mockito.eq;
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +090088import static org.mockito.Mockito.inOrder;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +090089import static org.mockito.Mockito.mock;
Xiao Mac00a7932019-06-03 10:30:04 +090090import static org.mockito.Mockito.never;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +090091import static org.mockito.Mockito.reset;
Lorenzo Colitti1e868b32019-11-29 16:17:58 +090092import static org.mockito.Mockito.spy;
Xiao Mac00a7932019-06-03 10:30:04 +090093import static org.mockito.Mockito.timeout;
Xiao Ma53ed1ac2019-06-03 15:48:39 +090094import static org.mockito.Mockito.times;
95import static org.mockito.Mockito.verify;
96import static org.mockito.Mockito.when;
97
98import android.app.AlarmManager;
Lorenzo Colitti31c7a512020-04-22 16:03:41 +090099import android.app.AlarmManager.OnAlarmListener;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900100import android.app.Instrumentation;
101import android.content.ContentResolver;
102import android.content.Context;
103import android.content.res.Resources;
104import android.net.ConnectivityManager;
Xiao Ma562d2422019-12-16 13:20:59 +0900105import android.net.DhcpResults;
106import android.net.DhcpResultsParcelable;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900107import android.net.INetd;
Xiao Mac00a7932019-06-03 10:30:04 +0900108import android.net.InetAddresses;
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900109import android.net.InterfaceConfigurationParcel;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +0900110import android.net.IpPrefix;
Xiao Ma8bbceb42019-10-08 16:21:07 +0900111import android.net.Layer2InformationParcelable;
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900112import android.net.Layer2PacketParcelable;
113import android.net.LinkAddress;
Xiao Ma619c28c2019-08-23 16:47:22 +0900114import android.net.LinkProperties;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +0900115import android.net.MacAddress;
Xiao Mac00a7932019-06-03 10:30:04 +0900116import android.net.NetworkStackIpMemoryStore;
Xiao Ma326820d2020-11-24 16:21:04 +0900117import android.net.RouteInfo;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900118import android.net.TestNetworkInterface;
119import android.net.TestNetworkManager;
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +0900120import android.net.Uri;
Xiao Mac00a7932019-06-03 10:30:04 +0900121import android.net.dhcp.DhcpClient;
Xiao Ma7d733952019-07-02 18:55:11 +0900122import android.net.dhcp.DhcpDeclinePacket;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900123import android.net.dhcp.DhcpDiscoverPacket;
124import android.net.dhcp.DhcpPacket;
125import android.net.dhcp.DhcpPacket.ParseException;
Xiao Mac00a7932019-06-03 10:30:04 +0900126import android.net.dhcp.DhcpRequestPacket;
Xiao Ma60175d22021-06-02 12:28:40 +0000127import android.net.ip.IpNeighborMonitor.NeighborEventConsumer;
Xiao Mac00a7932019-06-03 10:30:04 +0900128import android.net.ipmemorystore.NetworkAttributes;
129import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener;
130import android.net.ipmemorystore.Status;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900131import android.net.networkstack.TestNetworkStackServiceClient;
Xiao Mae31734e2020-12-10 21:09:26 +0900132import android.net.networkstack.aidl.dhcp.DhcpOption;
Xiao Ma374387c2021-11-02 02:25:55 +0000133import android.net.networkstack.aidl.ip.ReachabilityLossInfoParcelable;
Xiao Ma33cc64a2021-11-03 09:31:35 +0000134import android.net.networkstack.aidl.ip.ReachabilityLossReason;
Xiao Mab5721cc2020-04-16 16:20:25 +0900135import android.net.shared.Layer2Information;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900136import android.net.shared.ProvisioningConfiguration;
Xiao Ma562d2422019-12-16 13:20:59 +0900137import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
Xiao Mac00a7932019-06-03 10:30:04 +0900138import android.net.util.NetworkStackUtils;
Xiao Ma60175d22021-06-02 12:28:40 +0000139import android.net.util.SharedLog;
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900140import android.os.Build;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900141import android.os.Handler;
142import android.os.HandlerThread;
143import android.os.IBinder;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900144import android.os.ParcelFileDescriptor;
Xiao Ma7d733952019-07-02 18:55:11 +0900145import android.os.PowerManager;
Xiao Mac00a7932019-06-03 10:30:04 +0900146import android.os.RemoteException;
Lorenzo Colitti31c7a512020-04-22 16:03:41 +0900147import android.os.SystemClock;
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900148import android.os.SystemProperties;
lifrf9105de2021-05-06 15:31:04 +0800149import android.stats.connectivity.NetworkQuirkEvent;
Xiao Ma374387c2021-11-02 02:25:55 +0000150import android.stats.connectivity.NudEventType;
Xiao Ma619c28c2019-08-23 16:47:22 +0900151import android.system.ErrnoException;
152import android.system.Os;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900153
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900154import androidx.annotation.NonNull;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900155import androidx.test.InstrumentationRegistry;
156import androidx.test.filters.SmallTest;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900157
Xiao Ma45676f02021-04-20 09:15:42 +0000158import com.android.internal.util.HexDump;
Lorenzo Colittib891b5e2020-02-05 16:48:09 +0900159import com.android.internal.util.StateMachine;
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900160import com.android.net.module.util.ArrayTrackRecord;
Patrick Rohr96227862022-03-04 16:13:34 +0100161import com.android.net.module.util.InterfaceParams;
Xiao Maaf321442021-02-05 09:04:42 +0000162import com.android.net.module.util.Ipv6Utils;
Xiao Ma6f4019c2021-07-01 13:53:48 +0000163import com.android.net.module.util.netlink.StructNdOptPref64;
Xiao Ma60175d22021-06-02 12:28:40 +0000164import com.android.net.module.util.structs.LlaOption;
Xiao Maaf321442021-02-05 09:04:42 +0000165import com.android.net.module.util.structs.PrefixInformationOption;
166import com.android.net.module.util.structs.RdnssOption;
Xiao Ma9661f0b2021-12-13 12:56:32 +0000167import com.android.networkstack.R;
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +0900168import com.android.networkstack.apishim.CaptivePortalDataShimImpl;
Lorenzo Colitti75aac042020-04-24 17:01:37 +0900169import com.android.networkstack.apishim.ConstantsShim;
Remi NGUYEN VAN046bfa72020-05-14 14:32:03 +0900170import com.android.networkstack.apishim.common.ShimUtils;
Xiao Ma7d733952019-07-02 18:55:11 +0900171import com.android.networkstack.arp.ArpPacket;
lifr342cb2c2020-05-18 00:56:23 +0800172import com.android.networkstack.metrics.IpProvisioningMetrics;
Xiao Mad9d3bcc2020-12-14 01:25:50 +0000173import com.android.networkstack.metrics.IpReachabilityMonitorMetrics;
lifrf9105de2021-05-06 15:31:04 +0800174import com.android.networkstack.metrics.NetworkQuirkMetrics;
Xiao Ma002dd5a2020-12-22 01:14:49 +0000175import com.android.networkstack.packets.NeighborAdvertisement;
Xiao Ma60175d22021-06-02 12:28:40 +0000176import com.android.networkstack.packets.NeighborSolicitation;
Lorenzo Colitti58da4e32020-04-24 21:57:22 +0900177import com.android.server.NetworkObserver;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900178import com.android.server.NetworkObserverRegistry;
Xiao Mac00a7932019-06-03 10:30:04 +0900179import com.android.server.NetworkStackService.NetworkStackServiceManager;
180import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +0900181import com.android.testutils.DevSdkIgnoreRule;
Xiao Mafa33d492020-05-15 21:59:00 +0900182import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
Lorenzo Colitti46a78742020-04-02 20:21:16 +0900183import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
Chalard Jean23a06302020-06-26 00:41:00 +0900184import com.android.testutils.HandlerUtils;
Lorenzo Colitti32215002020-03-13 19:40:32 +0900185import com.android.testutils.TapPacketReader;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900186
187import org.junit.After;
188import org.junit.Before;
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +0900189import org.junit.Rule;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900190import org.junit.Test;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900191import org.junit.rules.TestName;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900192import org.junit.runner.RunWith;
Xiao Ma93533832021-09-13 04:14:33 +0000193import org.junit.runners.Parameterized;
Xiao Mac00a7932019-06-03 10:30:04 +0900194import org.mockito.ArgumentCaptor;
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +0900195import org.mockito.InOrder;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900196import org.mockito.Mock;
197import org.mockito.MockitoAnnotations;
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900198import org.mockito.Spy;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900199
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900200import java.io.BufferedReader;
Lorenzo Colitti675e0f52020-08-18 22:13:24 +0900201import java.io.File;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900202import java.io.FileDescriptor;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900203import java.io.FileReader;
Xiao Mac00a7932019-06-03 10:30:04 +0900204import java.io.IOException;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900205import java.lang.annotation.ElementType;
206import java.lang.annotation.Retention;
207import java.lang.annotation.RetentionPolicy;
208import java.lang.annotation.Target;
209import java.lang.reflect.Method;
Xiao Mac00a7932019-06-03 10:30:04 +0900210import java.net.Inet4Address;
Xiao Maaf321442021-02-05 09:04:42 +0000211import java.net.Inet6Address;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +0900212import java.net.InetAddress;
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900213import java.net.NetworkInterface;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900214import java.nio.ByteBuffer;
Xiao Ma7d733952019-07-02 18:55:11 +0900215import java.util.ArrayList;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900216import java.util.Arrays;
Xiao Ma16b21ef2020-01-22 17:51:26 +0900217import java.util.Collection;
Xiao Mac00a7932019-06-03 10:30:04 +0900218import java.util.Collections;
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900219import java.util.HashMap;
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900220import java.util.List;
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +0900221import java.util.Objects;
Xiao Ma562d2422019-12-16 13:20:59 +0900222import java.util.Random;
Xiao Ma4edc4f62020-05-21 10:32:47 +0900223import java.util.concurrent.CompletableFuture;
Lorenzo Colitti58da4e32020-04-24 21:57:22 +0900224import java.util.concurrent.CountDownLatch;
225import java.util.concurrent.TimeUnit;
Lorenzo Colitti5e384442020-04-26 20:18:04 +0900226import java.util.concurrent.atomic.AtomicReference;
227import java.util.function.Predicate;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900228
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900229import kotlin.Lazy;
230import kotlin.LazyKt;
231
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900232/**
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900233 * Base class for IpClient tests.
234 *
235 * Tests in this class can either be run with signature permissions, or with root access.
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900236 */
Xiao Ma93533832021-09-13 04:14:33 +0000237@RunWith(Parameterized.class)
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900238@SmallTest
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900239public abstract class IpClientIntegrationTestCommon {
Xiao Mac00a7932019-06-03 10:30:04 +0900240 private static final int DATA_BUFFER_LEN = 4096;
241 private static final int PACKET_TIMEOUT_MS = 5_000;
Chalard Jeanb2896832020-05-13 19:16:49 +0900242 private static final String TEST_CLUSTER = "some cluster";
Xiao Mac00a7932019-06-03 10:30:04 +0900243 private static final int TEST_LEASE_DURATION_S = 3_600; // 1 hour
Xiao Ma6e2818b2020-06-22 01:18:22 +0900244 private static final int TEST_IPV6_ONLY_WAIT_S = 1_800; // 30 min
245 private static final int TEST_LOWER_IPV6_ONLY_WAIT_S = (int) (MIN_V6ONLY_WAIT_MS / 1000 - 1);
246 private static final int TEST_ZERO_IPV6_ONLY_WAIT_S = 0;
247 private static final long TEST_MAX_IPV6_ONLY_WAIT_S = 0xffffffffL;
Xiao Ma927a8912021-01-07 08:05:02 +0000248 protected static final String TEST_L2KEY = "some l2key";
Xiao Mac00a7932019-06-03 10:30:04 +0900249
Lorenzo Colitti558eb962020-04-27 11:43:23 +0900250 // TODO: move to NetlinkConstants, NetworkStackConstants, or OsConstants.
251 private static final int IFA_F_STABLE_PRIVACY = 0x800;
252
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900253 protected static final long TEST_TIMEOUT_MS = 2_000L;
254
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +0900255 @Rule
256 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900257 @Rule
258 public final TestName mTestNameRule = new TestName();
259
Xiao Ma93533832021-09-13 04:14:33 +0000260 // Indicate whether the flag of parsing netlink event is enabled or not. If it's disabled,
261 // integration test still covers the old codepath(i.e. using NetworkObserver), otherwise,
262 // test goes through the new codepath(i.e. processRtNetlinkxxx).
263 @Parameterized.Parameter(0)
264 public boolean mIsNetlinkEventParseEnabled;
265
266 @Parameterized.Parameters
267 public static Iterable<? extends Object> data() {
Xiao Maebc22a82021-08-13 06:34:39 +0000268 return Arrays.asList(Boolean.FALSE, Boolean.TRUE);
Xiao Ma93533832021-09-13 04:14:33 +0000269 }
270
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900271 /**
272 * Indicates that a test requires signature permissions to run.
273 *
274 * Such tests can only be run on devices that use known signing keys, so this annotation must be
275 * avoided as much as possible. Consider whether the test can be written to use shell and root
276 * shell permissions, and run against the NetworkStack AIDL interface (IIpClient) instead.
277 */
278 @Retention(RetentionPolicy.RUNTIME)
279 @Target({ElementType.METHOD})
280 private @interface SignatureRequiredTest {
281 String reason();
282 }
283
284 /**** BEGIN signature required test members ****/
285 // Do not use unless the test *really* cannot be written to exercise IIpClient without mocks.
286 // Tests using the below members must be annotated with @SignatureRequiredTest (otherwise the
287 // members will be null), and can only be run on devices that use known signing keys.
288 // The members could technically be moved to the IpClientIntegrationTest subclass together with
289 // the tests requiring signature permissions, but this would make it harder to follow tests in
290 // multiple classes, and harder to migrate tests between signature required and not required.
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +0900291
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900292 @Mock private Context mContext;
293 @Mock private ConnectivityManager mCm;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900294 @Mock private Resources mResources;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900295 @Mock private AlarmManager mAlarm;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900296 @Mock private ContentResolver mContentResolver;
Xiao Mac00a7932019-06-03 10:30:04 +0900297 @Mock private NetworkStackServiceManager mNetworkStackServiceManager;
Xiao Mac00a7932019-06-03 10:30:04 +0900298 @Mock private IpMemoryStoreService mIpMemoryStoreService;
Xiao Ma7d733952019-07-02 18:55:11 +0900299 @Mock private PowerManager.WakeLock mTimeoutWakeLock;
Xiao Ma927a8912021-01-07 08:05:02 +0000300 @Mock protected NetworkStackIpMemoryStore mIpMemoryStore;
lifrf9105de2021-05-06 15:31:04 +0800301 @Mock private NetworkQuirkMetrics.Dependencies mNetworkQuirkMetricsDeps;
Xiao Mad9d3bcc2020-12-14 01:25:50 +0000302 @Mock private IpReachabilityMonitorMetrics mIpReachabilityMonitorMetrics;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900303
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900304 @Spy private INetd mNetd;
Lorenzo Colitti58da4e32020-04-24 21:57:22 +0900305 private NetworkObserverRegistry mNetworkObserverRegistry;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900306
307 protected IpClient mIpc;
308 protected Dependencies mDependencies;
309
310 /***** END signature required test members *****/
311
Xiao Ma60175d22021-06-02 12:28:40 +0000312 protected IIpClientCallbacks mCb;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900313 private IIpClient mIIpClient;
314 private String mIfaceName;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900315 private HandlerThread mPacketReaderThread;
Xiao Mac66d5d02019-09-03 10:41:58 +0900316 private Handler mHandler;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900317 private TapPacketReader mPacketReader;
Lorenzo Colitti32215002020-03-13 19:40:32 +0900318 private FileDescriptor mTapFd;
Xiao Ma7d733952019-07-02 18:55:11 +0900319 private byte[] mClientMac;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900320
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900321 private boolean mIsSignatureRequiredTest;
322
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900323 // ReadHeads for various packet streams. Cannot be initialized in @Before because ReadHead is
324 // single-thread-only, and AndroidJUnitRunner runs @Before and @Test on different threads.
325 // While it looks like these are created only once per test, they are actually created once per
326 // test method because JUnit recreates a fresh test class instance before every test method.
327 private Lazy<ArrayTrackRecord<byte[]>.ReadHead> mDhcpPacketReadHead =
328 LazyKt.lazy(() -> mPacketReader.getReceivedPackets().newReadHead());
329 private Lazy<ArrayTrackRecord<byte[]>.ReadHead> mArpPacketReadHead =
330 LazyKt.lazy(() -> mPacketReader.getReceivedPackets().newReadHead());
331
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900332 // Ethernet header
333 private static final int ETH_HEADER_LEN = 14;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900334
335 // IP header
336 private static final int IPV4_HEADER_LEN = 20;
Xiao Mac00a7932019-06-03 10:30:04 +0900337 private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900338 private static final int IPV4_DST_ADDR_OFFSET = IPV4_SRC_ADDR_OFFSET + 4;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900339
340 // UDP header
341 private static final int UDP_HEADER_LEN = 8;
342 private static final int UDP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
343 private static final int UDP_SRC_PORT_OFFSET = UDP_HEADER_OFFSET + 0;
344
345 // DHCP header
346 private static final int DHCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN
347 + UDP_HEADER_LEN;
348 private static final int DHCP_MESSAGE_OP_CODE_OFFSET = DHCP_HEADER_OFFSET + 0;
349 private static final int DHCP_TRANSACTION_ID_OFFSET = DHCP_HEADER_OFFSET + 4;
350 private static final int DHCP_OPTION_MAGIC_COOKIE_OFFSET = DHCP_HEADER_OFFSET + 236;
Xiao Mac00a7932019-06-03 10:30:04 +0900351
352 private static final Inet4Address SERVER_ADDR =
353 (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.100");
354 private static final Inet4Address CLIENT_ADDR =
355 (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.2");
Xiao Ma8bbceb42019-10-08 16:21:07 +0900356 private static final Inet4Address CLIENT_ADDR_NEW =
357 (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.3");
Xiao Mac00a7932019-06-03 10:30:04 +0900358 private static final Inet4Address INADDR_ANY =
359 (Inet4Address) InetAddresses.parseNumericAddress("0.0.0.0");
360 private static final int PREFIX_LENGTH = 24;
361 private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH);
362 private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
363 SERVER_ADDR, PREFIX_LENGTH);
Xiao Ma78c89f42022-03-30 22:07:50 +0900364 private static final String IPV6_LINK_LOCAL_PREFIX = "fe80::/64";
365 private static final String IPV4_TEST_SUBNET_PREFIX = "192.168.1.0/24";
366 private static final String IPV4_ANY_ADDRESS_PREFIX = "0.0.0.0/0";
Xiao Mac00a7932019-06-03 10:30:04 +0900367 private static final String HOSTNAME = "testhostname";
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900368 private static final int TEST_DEFAULT_MTU = 1500;
369 private static final int TEST_MIN_MTU = 1280;
Xiao Ma60175d22021-06-02 12:28:40 +0000370 private static final MacAddress ROUTER_MAC = MacAddress.fromString("00:1A:11:22:33:44");
371 private static final byte[] ROUTER_MAC_BYTES = ROUTER_MAC.toByteArray();
372 private static final Inet6Address ROUTER_LINK_LOCAL =
373 (Inet6Address) InetAddresses.parseNumericAddress("fe80::1");
Xiao Ma8bcd6732019-08-26 17:24:26 +0900374 private static final String TEST_HOST_NAME = "AOSP on Crosshatch";
375 private static final String TEST_HOST_NAME_TRANSLITERATION = "AOSP-on-Crosshatch";
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +0900376 private static final String TEST_CAPTIVE_PORTAL_URL = "https://example.com/capportapi";
Xiao Ma562d2422019-12-16 13:20:59 +0900377 private static final byte[] TEST_HOTSPOT_OUI = new byte[] {
378 (byte) 0x00, (byte) 0x17, (byte) 0xF2
379 };
380 private static final byte TEST_VENDOR_SPECIFIC_TYPE = 0x06;
Xiao Ma8bbceb42019-10-08 16:21:07 +0900381
382 private static final String TEST_DEFAULT_SSID = "test_ssid";
Xiao Maf784d612020-04-02 23:16:04 +0900383 private static final String TEST_DEFAULT_BSSID = "00:11:22:33:44:55";
Xiao Ma8bbceb42019-10-08 16:21:07 +0900384 private static final String TEST_DHCP_ROAM_SSID = "0001docomo";
385 private static final String TEST_DHCP_ROAM_BSSID = "00:4e:35:17:98:55";
386 private static final String TEST_DHCP_ROAM_L2KEY = "roaming_l2key";
Chalard Jeanb2896832020-05-13 19:16:49 +0900387 private static final String TEST_DHCP_ROAM_CLUSTER = "roaming_cluster";
Xiao Ma8bbceb42019-10-08 16:21:07 +0900388 private static final byte[] TEST_AP_OUI = new byte[] { 0x00, 0x1A, 0x11 };
Xiao Mae31734e2020-12-10 21:09:26 +0900389 private static final byte[] TEST_OEM_OUI = new byte[] {(byte) 0x00, (byte) 0x17, (byte) 0xc3};
390 private static final String TEST_OEM_VENDOR_ID = "vendor-class-identifier";
391 private static final byte[] TEST_OEM_USER_CLASS_INFO = new byte[] {
392 // Instance of User Class: [0]
393 (byte) 0x03, /* UC_Len_0 */ (byte) 0x11, (byte) 0x22, (byte) 0x33,
394 // Instance of User Class: [1]
395 (byte) 0x03, /* UC_Len_1 */ (byte) 0x44, (byte) 0x55, (byte) 0x66,
396 };
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900397
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900398 protected class Dependencies extends IpClient.Dependencies {
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900399 // Can't use SparseIntArray, it doesn't have an easy way to know if a key is not present.
400 private HashMap<String, Integer> mIntConfigProperties = new HashMap<>();
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900401 private DhcpClient mDhcpClient;
Xiao Ma8bcd6732019-08-26 17:24:26 +0900402 private boolean mIsHostnameConfigurationEnabled;
403 private String mHostname;
Xiao Ma7dc8ef82020-08-13 15:25:06 +0900404 private boolean mIsInterfaceRecovered;
Xiao Ma6e2818b2020-06-22 01:18:22 +0900405
Xiao Ma8bcd6732019-08-26 17:24:26 +0900406 public void setHostnameConfiguration(final boolean enable, final String hostname) {
407 mIsHostnameConfigurationEnabled = enable;
408 mHostname = hostname;
409 }
410
Xiao Ma7dc8ef82020-08-13 15:25:06 +0900411 // Enable this flag to simulate the interface has been added back after removing
412 // on the provisioning start. However, the actual tap interface has been removed,
413 // interface parameters query will get null when attempting to restore Interface
414 // MTU. Create a new InterfaceParams instance and return instead just for interface
415 // toggling test case.
416 public void simulateInterfaceRecover() {
417 mIsInterfaceRecovered = true;
418 }
419
420 @Override
421 public InterfaceParams getInterfaceParams(String ifname) {
422 return mIsInterfaceRecovered
423 ? new InterfaceParams(ifname, 1 /* index */,
424 MacAddress.fromString("00:11:22:33:44:55"))
425 : super.getInterfaceParams(ifname);
426 }
427
Xiao Mac00a7932019-06-03 10:30:04 +0900428 @Override
429 public INetd getNetd(Context context) {
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900430 return mNetd;
Xiao Mac00a7932019-06-03 10:30:04 +0900431 }
432
433 @Override
434 public NetworkStackIpMemoryStore getIpMemoryStore(Context context,
435 NetworkStackServiceManager nssManager) {
436 return mIpMemoryStore;
437 }
438
439 @Override
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900440 public DhcpClient makeDhcpClient(Context context, StateMachine controller,
441 InterfaceParams ifParams, DhcpClient.Dependencies deps) {
442 mDhcpClient = DhcpClient.makeDhcpClient(context, controller, ifParams, deps);
443 return mDhcpClient;
444 }
445
Xiao Ma002dd5a2020-12-22 01:14:49 +0000446 @Override
Xiao Ma60175d22021-06-02 12:28:40 +0000447 public IpReachabilityMonitor getIpReachabilityMonitor(Context context,
448 InterfaceParams ifParams, Handler h, SharedLog log,
449 IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker,
450 IpReachabilityMonitor.Dependencies deps, final INetd netd) {
Xiao Ma374387c2021-11-02 02:25:55 +0000451 return new IpReachabilityMonitor(context, ifParams, h, log, callback,
Xiao Ma60175d22021-06-02 12:28:40 +0000452 usingMultinetworkPolicyTracker, deps, netd);
453 }
454
455 @Override
Xiao Maeb15c5e2021-03-09 08:40:50 +0000456 public boolean isFeatureEnabled(final Context context, final String name,
457 final boolean defaultEnabled) {
458 return IpClientIntegrationTestCommon.this.isFeatureEnabled(name, defaultEnabled);
459 }
460
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900461 @Override
Xiao Mac00a7932019-06-03 10:30:04 +0900462 public DhcpClient.Dependencies getDhcpClientDependencies(
lifr342cb2c2020-05-18 00:56:23 +0800463 NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics) {
464 return new DhcpClient.Dependencies(ipMemoryStore, metrics) {
Xiao Mac00a7932019-06-03 10:30:04 +0900465 @Override
Xiao Mafa33d492020-05-15 21:59:00 +0900466 public boolean isFeatureEnabled(final Context context, final String name,
467 final boolean defaultEnabled) {
Xiao Maeb15c5e2021-03-09 08:40:50 +0000468 return Dependencies.this.isFeatureEnabled(context, name, defaultEnabled);
Xiao Mac00a7932019-06-03 10:30:04 +0900469 }
Xiao Ma7d733952019-07-02 18:55:11 +0900470
471 @Override
Xiao Mad64f58e2019-12-10 15:56:41 +0900472 public int getIntDeviceConfig(final String name, int minimumValue,
473 int maximumValue, int defaultValue) {
Xiao Ma7d733952019-07-02 18:55:11 +0900474 return getDeviceConfigPropertyInt(name, 0 /* default value */);
475 }
476
477 @Override
478 public PowerManager.WakeLock getWakeLock(final PowerManager powerManager) {
479 return mTimeoutWakeLock;
480 }
Xiao Ma8bcd6732019-08-26 17:24:26 +0900481
482 @Override
483 public boolean getSendHostnameOption(final Context context) {
484 return mIsHostnameConfigurationEnabled;
485 }
486
487 @Override
488 public String getDeviceName(final Context context) {
489 return mIsHostnameConfigurationEnabled ? mHostname : null;
490 }
Xiao Mac00a7932019-06-03 10:30:04 +0900491 };
492 }
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900493
494 @Override
Xiao Ma60175d22021-06-02 12:28:40 +0000495 public IpReachabilityMonitor.Dependencies getIpReachabilityMonitorDeps(Context context,
496 String name) {
497 return new IpReachabilityMonitor.Dependencies() {
498 public void acquireWakeLock(long durationMs) {
499 // It doesn't matter for the integration test app on whether the wake lock
500 // is acquired or not.
501 return;
502 }
503
504 public IpNeighborMonitor makeIpNeighborMonitor(Handler h, SharedLog log,
505 NeighborEventConsumer cb) {
506 return new IpNeighborMonitor(h, log, cb);
507 }
Xiao Ma69a936a2021-04-21 08:14:44 +0000508
509 public boolean isFeatureEnabled(final Context context, final String name,
510 boolean defaultEnabled) {
511 return Dependencies.this.isFeatureEnabled(context, name, defaultEnabled);
512 }
Xiao Mad9d3bcc2020-12-14 01:25:50 +0000513
514 public IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics() {
515 return mIpReachabilityMonitorMetrics;
516 }
Xiao Ma60175d22021-06-02 12:28:40 +0000517 };
518 }
519
520 @Override
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900521 public int getDeviceConfigPropertyInt(String name, int defaultValue) {
522 Integer value = mIntConfigProperties.get(name);
523 if (value == null) {
524 throw new IllegalStateException("Non-mocked device config property " + name);
525 }
526 return value;
527 }
528
529 public void setDeviceConfigProperty(String name, int value) {
530 mIntConfigProperties.put(name, value);
531 }
lifrf9105de2021-05-06 15:31:04 +0800532
533 @Override
534 public NetworkQuirkMetrics getNetworkQuirkMetrics() {
535 return new NetworkQuirkMetrics(mNetworkQuirkMetricsDeps);
536 }
Xiao Mac00a7932019-06-03 10:30:04 +0900537 }
538
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900539 @NonNull
540 protected abstract IIpClient makeIIpClient(
541 @NonNull String ifaceName, @NonNull IIpClientCallbacks cb);
542
Xiao Maeb15c5e2021-03-09 08:40:50 +0000543 protected abstract void setFeatureEnabled(String name, boolean enabled);
544
545 protected abstract boolean isFeatureEnabled(String name, boolean defaultEnabled);
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900546
547 protected abstract boolean useNetworkStackSignature();
548
Xiao Ma927a8912021-01-07 08:05:02 +0000549 protected abstract NetworkAttributes getStoredNetworkAttributes(String l2Key, long timeout);
550
Xiao Ma4ca906c2021-01-30 12:09:41 +0000551 protected abstract void storeNetworkAttributes(String l2Key, NetworkAttributes na);
552
Xiao Ma927a8912021-01-07 08:05:02 +0000553 protected abstract void assertIpMemoryNeverStoreNetworkAttributes(String l2Key, long timeout);
554
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900555 protected final boolean testSkipped() {
556 // TODO: split out a test suite for root tests, and fail hard instead of skipping the test
557 // if it is run on devices where TestNetworkStackServiceClient is not supported
558 return !useNetworkStackSignature()
559 && (mIsSignatureRequiredTest || !TestNetworkStackServiceClient.isSupported());
560 }
561
Xiao Maeb15c5e2021-03-09 08:40:50 +0000562 protected void setDhcpFeatures(final boolean isDhcpLeaseCacheEnabled,
563 final boolean isRapidCommitEnabled, final boolean isDhcpIpConflictDetectEnabled,
564 final boolean isIPv6OnlyPreferredEnabled) {
565 setFeatureEnabled(NetworkStackUtils.DHCP_INIT_REBOOT_VERSION, isDhcpLeaseCacheEnabled);
566 setFeatureEnabled(NetworkStackUtils.DHCP_RAPID_COMMIT_VERSION, isRapidCommitEnabled);
567 setFeatureEnabled(NetworkStackUtils.DHCP_IP_CONFLICT_DETECT_VERSION,
568 isDhcpIpConflictDetectEnabled);
569 setFeatureEnabled(NetworkStackUtils.DHCP_IPV6_ONLY_PREFERRED_VERSION,
570 isIPv6OnlyPreferredEnabled);
571 }
572
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900573 @Before
574 public void setUp() throws Exception {
Xiao Ma93533832021-09-13 04:14:33 +0000575 // Suffix "[0]" or "[1]" is added to the end of test method name after running with
576 // Parameterized.class, that's intended behavior, to iterate each test method with the
577 // parameterize value. However, Class#getMethod() throws NoSuchMethodException when
578 // searching the target test method name due to this change. Just keep the original test
579 // method name to fix NoSuchMethodException, and find the correct annotation associated
580 // to test method.
581 final String testMethodName = mTestNameRule.getMethodName().split("\\[")[0];
582 final Method testMethod = IpClientIntegrationTestCommon.class.getMethod(testMethodName);
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900583 mIsSignatureRequiredTest = testMethod.getAnnotation(SignatureRequiredTest.class) != null;
584 assumeFalse(testSkipped());
585
Xiao Maebc22a82021-08-13 06:34:39 +0000586 // Depend on the parameterized value to enable/disable netlink message refactor flag.
587 // Make sure both of the old codepath(rely on the INetdUnsolicitedEventListener aidl)
588 // and new codepath(parse netlink event from kernel) will be executed.
589 //
590 // Note this must be called before making IpClient instance since MyNetlinkMontior ctor
591 // in IpClientLinkObserver will use mIsNetlinkEventParseEnabled to decide the proper
592 // bindGroups, otherwise, the parameterized value got from ArrayMap(integration test) is
593 // always false.
594 setFeatureEnabled(NetworkStackUtils.IPCLIENT_PARSE_NETLINK_EVENTS_VERSION,
595 mIsNetlinkEventParseEnabled /* default value */);
596
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900597 setUpTapInterface();
598 mCb = mock(IIpClientCallbacks.class);
599
600 if (useNetworkStackSignature()) {
601 setUpMocks();
602 setUpIpClient();
Xiao Ma7ae2ec32021-09-29 06:07:15 +0000603 // Enable packet retransmit alarm in DhcpClient.
604 enableRealAlarm("DhcpClient." + mIfaceName + ".KICK");
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900605 }
606
607 mIIpClient = makeIIpClient(mIfaceName, mCb);
608 }
609
610 protected void setUpMocks() throws Exception {
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900611 MockitoAnnotations.initMocks(this);
612
Xiao Mac00a7932019-06-03 10:30:04 +0900613 mDependencies = new Dependencies();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900614 when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
615 when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
616 when(mContext.getResources()).thenReturn(mResources);
Xiao Ma9661f0b2021-12-13 12:56:32 +0000617 when(mResources.getInteger(eq(R.integer.config_nud_postroaming_solicit_num))).thenReturn(5);
618 when(mResources.getInteger(eq(R.integer.config_nud_postroaming_solicit_interval)))
619 .thenReturn(750);
620 when(mResources.getInteger(eq(R.integer.config_nud_steadystate_solicit_num)))
621 .thenReturn(10);
622 when(mResources.getInteger(eq(R.integer.config_nud_steadystate_solicit_interval)))
623 .thenReturn(750);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900624 when(mContext.getContentResolver()).thenReturn(mContentResolver);
Xiao Mac00a7932019-06-03 10:30:04 +0900625 when(mNetworkStackServiceManager.getIpMemoryStoreService())
626 .thenReturn(mIpMemoryStoreService);
Xiao Ma374387c2021-11-02 02:25:55 +0000627 when(mCb.getInterfaceVersion()).thenReturn(IpClient.VERSION_ADDED_REACHABILITY_FAILURE);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900628
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900629 mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67);
Xiao Ma7d733952019-07-02 18:55:11 +0900630 mDependencies.setDeviceConfigProperty(DhcpClient.DHCP_RESTART_CONFIG_DELAY, 10);
631 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_FIRST_PROBE_DELAY_MS, 10);
632 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_PROBE_MIN_MS, 10);
633 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_PROBE_MAX_MS, 20);
634 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_FIRST_ANNOUNCE_DELAY_MS, 10);
635 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_ANNOUNCE_INTERVAL_MS, 10);
Xiao Ma148f5742022-06-06 11:20:33 +0900636
637 // Set the initial netlink socket receive buffer size to a minimum of 10KB to ensure test
638 // cases are still working, meanwhile in order to easily overflow the receive buffer by
639 // sending as few RAs as possible for test case where it's used to verify ENOBUFS.
640 mDependencies.setDeviceConfigProperty(CONFIG_SOCKET_RECV_BUFSIZE, 10 * 1024);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900641 }
642
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900643 private void awaitIpClientShutdown() throws Exception {
644 verify(mCb, timeout(TEST_TIMEOUT_MS)).onQuit();
645 }
646
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900647 @After
648 public void tearDown() throws Exception {
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900649 if (testSkipped()) return;
Lorenzo Colitti8b93f292021-10-12 16:58:56 +0900650 teardownTapInterface();
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900651 mIIpClient.shutdown();
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900652 awaitIpClientShutdown();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900653 }
654
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900655 private void setUpTapInterface() throws Exception {
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900656 final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
Lorenzo Colittid17b7282022-01-25 17:57:39 +0900657 final TestNetworkInterface iface = runAsShell(MANAGE_TEST_NETWORKS, () -> {
658 final TestNetworkManager tnm =
659 inst.getContext().getSystemService(TestNetworkManager.class);
660 return tnm.createTapInterface();
661 });
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900662 mIfaceName = iface.getInterfaceName();
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900663 mClientMac = getIfaceMacAddr(mIfaceName).toByteArray();
664 mPacketReaderThread = new HandlerThread(
665 IpClientIntegrationTestCommon.class.getSimpleName());
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900666 mPacketReaderThread.start();
Xiao Mac66d5d02019-09-03 10:41:58 +0900667 mHandler = mPacketReaderThread.getThreadHandler();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900668
Lorenzo Colitti097a6d22020-04-17 23:22:50 +0900669 // Detach the FileDescriptor from the ParcelFileDescriptor.
670 // Otherwise, the garbage collector might call the ParcelFileDescriptor's finalizer, which
671 // closes the FileDescriptor and destroys our tap interface. An alternative would be to
672 // make the ParcelFileDescriptor or the TestNetworkInterface a class member so they never
673 // go out of scope.
674 mTapFd = new FileDescriptor();
675 mTapFd.setInt$(iface.getFileDescriptor().detachFd());
Lorenzo Colitti32215002020-03-13 19:40:32 +0900676 mPacketReader = new TapPacketReader(mHandler, mTapFd, DATA_BUFFER_LEN);
Xiao Mac66d5d02019-09-03 10:41:58 +0900677 mHandler.post(() -> mPacketReader.start());
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900678 }
679
Xiao Maac371ef2021-09-15 03:37:41 +0000680 private TestNetworkInterface setUpClatInterface(@NonNull String baseIface) throws Exception {
681 final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
682 final TestNetworkInterface iface = runAsShell(MANAGE_TEST_NETWORKS, () -> {
683 final TestNetworkManager tnm =
684 inst.getContext().getSystemService(TestNetworkManager.class);
685 return tnm.createTapInterface(false /* bringUp */, CLAT_PREFIX + baseIface);
686 });
687 return iface;
688 }
689
Lorenzo Colitti8b93f292021-10-12 16:58:56 +0900690 private void teardownTapInterface() {
691 if (mPacketReader != null) {
692 mHandler.post(() -> mPacketReader.stop()); // Also closes the socket
693 mTapFd = null;
694 }
695 if (mPacketReaderThread != null) {
696 mPacketReaderThread.quitSafely();
697 }
698 }
699
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900700 private MacAddress getIfaceMacAddr(String ifaceName) throws IOException {
701 // InterfaceParams.getByName requires CAP_NET_ADMIN: read the mac address with the shell
702 final String strMacAddr = getOneLineCommandOutput(
703 "su root cat /sys/class/net/" + ifaceName + "/address");
704 return MacAddress.fromString(strMacAddr);
705 }
706
707 private String getOneLineCommandOutput(String cmd) throws IOException {
708 try (ParcelFileDescriptor fd = InstrumentationRegistry.getInstrumentation()
709 .getUiAutomation().executeShellCommand(cmd);
710 BufferedReader reader = new BufferedReader(new FileReader(fd.getFileDescriptor()))) {
711 return reader.readLine();
712 }
713 }
714
Xiao Ma7ae2ec32021-09-29 06:07:15 +0000715 private void enableRealAlarm(String cmdName) {
716 doAnswer((inv) -> {
717 final Context context = InstrumentationRegistry.getTargetContext();
718 final AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
719 alarmManager.setExact(inv.getArgument(0), inv.getArgument(1), inv.getArgument(2),
720 inv.getArgument(3), inv.getArgument(4));
721 return null;
722 }).when(mAlarm).setExact(anyInt(), anyLong(), eq(cmdName), any(OnAlarmListener.class),
723 any(Handler.class));
724 }
725
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900726 private IpClient makeIpClient() throws Exception {
727 IpClient ipc = new IpClient(mContext, mIfaceName, mCb, mNetworkObserverRegistry,
728 mNetworkStackServiceManager, mDependencies);
729 // Wait for IpClient to enter its initial state. Otherwise, additional setup steps or tests
730 // that mock IpClient's dependencies might interact with those mocks while IpClient is
731 // starting. This would cause UnfinishedStubbingExceptions as mocks cannot be interacted
732 // with while they are being stubbed.
733 HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
734 return ipc;
735 }
736
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900737 private void setUpIpClient() throws Exception {
738 final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
739 final IBinder netdIBinder =
740 (IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE);
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900741 mNetd = spy(INetd.Stub.asInterface(netdIBinder));
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900742 when(mContext.getSystemService(eq(Context.NETD_SERVICE))).thenReturn(netdIBinder);
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900743 assertNotNull(mNetd);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900744
Lorenzo Colitti58da4e32020-04-24 21:57:22 +0900745 mNetworkObserverRegistry = new NetworkObserverRegistry();
746 mNetworkObserverRegistry.register(mNetd);
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900747 mIpc = makeIpClient();
Lorenzo Colittibd919742020-04-24 23:16:49 +0900748
749 // Tell the IpMemoryStore immediately to answer any question about network attributes with a
750 // null response. Otherwise, the DHCP client will wait for two seconds before starting,
751 // while its query to the IpMemoryStore times out.
752 // This does not affect any test that makes the mock memory store return results, because
753 // unlike when(), it is documented that doAnswer() can be called more than once, to change
754 // the behaviour of a mock in the middle of a test.
755 doAnswer(invocation -> {
756 final String l2Key = invocation.getArgument(0);
757 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1))
758 .onNetworkAttributesRetrieved(new Status(SUCCESS), l2Key, null);
759 return null;
760 }).when(mIpMemoryStore).retrieveNetworkAttributes(any(), any());
761
762 disableIpv6ProvisioningDelays();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900763 }
764
Lorenzo Colitti5e384442020-04-26 20:18:04 +0900765 private <T> T verifyWithTimeout(InOrder inOrder, T t) {
766 if (inOrder != null) {
767 return inOrder.verify(t, timeout(TEST_TIMEOUT_MS));
768 } else {
769 return verify(t, timeout(TEST_TIMEOUT_MS));
770 }
771 }
772
Lorenzo Colitti31c7a512020-04-22 16:03:41 +0900773 private void expectAlarmCancelled(InOrder inOrder, OnAlarmListener listener) {
774 inOrder.verify(mAlarm, timeout(TEST_TIMEOUT_MS)).cancel(eq(listener));
775 }
776
Xiao Ma6e2818b2020-06-22 01:18:22 +0900777 private OnAlarmListener expectAlarmSet(InOrder inOrder, String tagMatch, long afterSeconds,
778 Handler handler) {
Lorenzo Colitti31c7a512020-04-22 16:03:41 +0900779 // Allow +/- 3 seconds to prevent flaky tests.
780 final long when = SystemClock.elapsedRealtime() + afterSeconds * 1000;
781 final long min = when - 3 * 1000;
782 final long max = when + 3 * 1000;
783 ArgumentCaptor<OnAlarmListener> captor = ArgumentCaptor.forClass(OnAlarmListener.class);
Lorenzo Colitti5e384442020-04-26 20:18:04 +0900784 verifyWithTimeout(inOrder, mAlarm).setExact(
785 anyInt(), longThat(x -> x >= min && x <= max),
Xiao Ma6e2818b2020-06-22 01:18:22 +0900786 contains(tagMatch), captor.capture(), eq(handler));
Lorenzo Colitti31c7a512020-04-22 16:03:41 +0900787 return captor.getValue();
788 }
789
Xiao Ma6e2818b2020-06-22 01:18:22 +0900790 private OnAlarmListener expectAlarmSet(InOrder inOrder, String tagMatch, int afterSeconds) {
791 return expectAlarmSet(inOrder, tagMatch, (long) afterSeconds, mIpc.getHandler());
792 }
793
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900794 private boolean packetContainsExpectedField(final byte[] packet, final int offset,
795 final byte[] expected) {
796 if (packet.length < offset + expected.length) return false;
797 for (int i = 0; i < expected.length; ++i) {
798 if (packet[offset + i] != expected[i]) return false;
799 }
800 return true;
801 }
802
803 private boolean isDhcpPacket(final byte[] packet) {
804 final ByteBuffer buffer = ByteBuffer.wrap(packet);
805
806 // check the packet length
807 if (packet.length < DHCP_HEADER_OFFSET) return false;
808
809 // check the source port and dest port in UDP header
810 buffer.position(UDP_SRC_PORT_OFFSET);
811 final short udpSrcPort = buffer.getShort();
812 final short udpDstPort = buffer.getShort();
813 if (udpSrcPort != DHCP_CLIENT || udpDstPort != DHCP_SERVER) return false;
814
815 // check DHCP message type
816 buffer.position(DHCP_MESSAGE_OP_CODE_OFFSET);
817 final byte dhcpOpCode = buffer.get();
818 if (dhcpOpCode != DHCP_BOOTREQUEST) return false;
819
820 // check DHCP magic cookie
821 buffer.position(DHCP_OPTION_MAGIC_COOKIE_OFFSET);
822 final int dhcpMagicCookie = buffer.getInt();
823 if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) return false;
824
825 return true;
826 }
827
Xiao Ma7d733952019-07-02 18:55:11 +0900828 private ArpPacket parseArpPacketOrNull(final byte[] packet) {
829 try {
830 return ArpPacket.parseArpPacket(packet, packet.length);
831 } catch (ArpPacket.ParseException e) {
832 return null;
833 }
834 }
835
Xiao Ma002dd5a2020-12-22 01:14:49 +0000836 private NeighborAdvertisement parseNeighborAdvertisementOrNull(final byte[] packet) {
837 try {
838 return NeighborAdvertisement.parse(packet, packet.length);
839 } catch (NeighborAdvertisement.ParseException e) {
840 return null;
841 }
842 }
843
Xiao Ma60175d22021-06-02 12:28:40 +0000844 private NeighborSolicitation parseNeighborSolicitationOrNull(final byte[] packet) {
845 try {
846 return NeighborSolicitation.parse(packet, packet.length);
847 } catch (NeighborSolicitation.ParseException e) {
848 return null;
849 }
850 }
851
Xiao Mac00a7932019-06-03 10:30:04 +0900852 private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900853 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
854 final String captivePortalUrl, final Integer ipv6OnlyWaitTime) {
Xiao Mac00a7932019-06-03 10:30:04 +0900855 return DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
856 false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900857 clientAddress /* yourIp */, packet.getClientMac(), leaseTimeSec,
Xiao Mac00a7932019-06-03 10:30:04 +0900858 NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */,
859 Collections.singletonList(SERVER_ADDR) /* gateways */,
860 Collections.singletonList(SERVER_ADDR) /* dnsServers */,
861 SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900862 false /* metered */, mtu, captivePortalUrl, ipv6OnlyWaitTime);
863 }
864
865 private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet,
866 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
867 final String captivePortalUrl) {
868 return buildDhcpOfferPacket(packet, clientAddress, leaseTimeSec, mtu, captivePortalUrl,
869 null /* ipv6OnlyWaitTime */);
Xiao Mac00a7932019-06-03 10:30:04 +0900870 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900871
Xiao Mac00a7932019-06-03 10:30:04 +0900872 private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet,
Xiao Ma8bbceb42019-10-08 16:21:07 +0900873 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900874 final boolean rapidCommit, final String captivePortalApiUrl,
875 final Integer ipv6OnlyWaitTime) {
Xiao Mac00a7932019-06-03 10:30:04 +0900876 return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
877 false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
Xiao Ma8bbceb42019-10-08 16:21:07 +0900878 clientAddress /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(),
Xiao Mac00a7932019-06-03 10:30:04 +0900879 leaseTimeSec, NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */,
880 Collections.singletonList(SERVER_ADDR) /* gateways */,
881 Collections.singletonList(SERVER_ADDR) /* dnsServers */,
882 SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900883 false /* metered */, mtu, rapidCommit, captivePortalApiUrl, ipv6OnlyWaitTime);
884 }
885
886 private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet,
887 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
888 final boolean rapidCommit, final String captivePortalApiUrl) {
889 return buildDhcpAckPacket(packet, clientAddress, leaseTimeSec, mtu, rapidCommit,
890 captivePortalApiUrl, null /* ipv6OnlyWaitTime */);
Xiao Mac00a7932019-06-03 10:30:04 +0900891 }
892
Xiao Ma780c09e2021-11-05 09:43:12 +0000893 private static ByteBuffer buildDhcpNakPacket(final DhcpPacket packet, final String message) {
Xiao Mac00a7932019-06-03 10:30:04 +0900894 return DhcpPacket.buildNakPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
895 SERVER_ADDR /* serverIp */, INADDR_ANY /* relayIp */, packet.getClientMac(),
Xiao Ma780c09e2021-11-05 09:43:12 +0000896 false /* broadcast */, message);
Xiao Mac00a7932019-06-03 10:30:04 +0900897 }
898
Xiao Ma7d733952019-07-02 18:55:11 +0900899 private void sendArpReply(final byte[] clientMac) throws IOException {
900 final ByteBuffer packet = ArpPacket.buildArpPacket(clientMac /* dst */,
Xiao Ma60175d22021-06-02 12:28:40 +0000901 ROUTER_MAC_BYTES /* srcMac */, INADDR_ANY.getAddress() /* target IP */,
Xiao Ma7d733952019-07-02 18:55:11 +0900902 clientMac /* target HW address */, CLIENT_ADDR.getAddress() /* sender IP */,
903 (short) ARP_REPLY);
Lorenzo Colitti32215002020-03-13 19:40:32 +0900904 mPacketReader.sendResponse(packet);
Xiao Ma7d733952019-07-02 18:55:11 +0900905 }
906
907 private void sendArpProbe() throws IOException {
908 final ByteBuffer packet = ArpPacket.buildArpPacket(DhcpPacket.ETHER_BROADCAST /* dst */,
Xiao Ma60175d22021-06-02 12:28:40 +0000909 ROUTER_MAC_BYTES /* srcMac */, CLIENT_ADDR.getAddress() /* target IP */,
Xiao Ma7d733952019-07-02 18:55:11 +0900910 new byte[ETHER_ADDR_LEN] /* target HW address */,
911 INADDR_ANY.getAddress() /* sender IP */, (short) ARP_REQUEST);
Lorenzo Colitti32215002020-03-13 19:40:32 +0900912 mPacketReader.sendResponse(packet);
Xiao Ma7d733952019-07-02 18:55:11 +0900913 }
914
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900915 private void startIpClientProvisioning(final ProvisioningConfiguration cfg) throws Exception {
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900916 mIIpClient.startProvisioning(cfg.toStableParcelable());
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900917 }
918
Xiao Mac00a7932019-06-03 10:30:04 +0900919 private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled,
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900920 final boolean shouldReplyRapidCommitAck, final boolean isPreconnectionEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +0000921 final boolean isDhcpIpConflictDetectEnabled, final boolean isIPv6OnlyPreferredEnabled,
Xiao Ma861fe422021-04-16 03:03:03 +0000922 final String displayName, final ScanResultInfo scanResultInfo,
923 final Layer2Information layer2Info) throws Exception {
Xiao Mab5721cc2020-04-16 16:20:25 +0900924 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
Xiao Mac00a7932019-06-03 10:30:04 +0900925 .withoutIpReachabilityMonitor()
Xiao Ma861fe422021-04-16 03:03:03 +0000926 .withLayer2Information(layer2Info == null
927 ? new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
928 MacAddress.fromString(TEST_DEFAULT_BSSID))
929 : layer2Info)
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900930 .withoutIPv6();
Xiao Mab5721cc2020-04-16 16:20:25 +0900931 if (isPreconnectionEnabled) prov.withPreconnection();
932 if (displayName != null) prov.withDisplayName(displayName);
933 if (scanResultInfo != null) prov.withScanResultInfo(scanResultInfo);
Xiao Mac00a7932019-06-03 10:30:04 +0900934
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900935 setDhcpFeatures(isDhcpLeaseCacheEnabled, shouldReplyRapidCommitAck,
Xiao Ma927a8912021-01-07 08:05:02 +0000936 isDhcpIpConflictDetectEnabled, isIPv6OnlyPreferredEnabled);
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900937
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900938 startIpClientProvisioning(prov.build());
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900939 if (!isPreconnectionEnabled) {
940 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
941 }
Xiao Mac00a7932019-06-03 10:30:04 +0900942 verify(mCb, never()).onProvisioningFailure(any());
943 }
944
Xiao Ma8bcd6732019-08-26 17:24:26 +0900945 private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled,
946 final boolean isDhcpRapidCommitEnabled, final boolean isPreconnectionEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +0000947 final boolean isDhcpIpConflictDetectEnabled, final boolean isIPv6OnlyPreferredEnabled)
948 throws Exception {
Xiao Ma8bcd6732019-08-26 17:24:26 +0900949 startIpClientProvisioning(isDhcpLeaseCacheEnabled, isDhcpRapidCommitEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +0000950 isPreconnectionEnabled, isDhcpIpConflictDetectEnabled, isIPv6OnlyPreferredEnabled,
Xiao Ma861fe422021-04-16 03:03:03 +0000951 null /* displayName */, null /* ScanResultInfo */, null /* layer2Info */);
Xiao Ma8bcd6732019-08-26 17:24:26 +0900952 }
953
Xiao Mac00a7932019-06-03 10:30:04 +0900954 private void assertIpMemoryStoreNetworkAttributes(final Integer leaseTimeSec,
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900955 final long startTime, final int mtu) {
Xiao Ma927a8912021-01-07 08:05:02 +0000956 final NetworkAttributes na = getStoredNetworkAttributes(TEST_L2KEY, TEST_TIMEOUT_MS);
957 assertNotNull(na);
958 assertEquals(CLIENT_ADDR, na.assignedV4Address);
Xiao Mac00a7932019-06-03 10:30:04 +0900959 if (leaseTimeSec == null || leaseTimeSec.intValue() == DhcpPacket.INFINITE_LEASE) {
Xiao Ma927a8912021-01-07 08:05:02 +0000960 assertEquals(Long.MAX_VALUE, na.assignedV4AddressExpiry.longValue());
Xiao Mac00a7932019-06-03 10:30:04 +0900961 } else {
962 // check the lease expiry's scope
963 final long upperBound = startTime + 7_200_000; // start timestamp + 2h
964 final long lowerBound = startTime + 3_600_000; // start timestamp + 1h
Xiao Ma927a8912021-01-07 08:05:02 +0000965 final long expiry = na.assignedV4AddressExpiry;
Xiao Mac00a7932019-06-03 10:30:04 +0900966 assertTrue(upperBound > expiry);
967 assertTrue(lowerBound < expiry);
968 }
Xiao Ma927a8912021-01-07 08:05:02 +0000969 assertEquals(Collections.singletonList(SERVER_ADDR), na.dnsAddresses);
970 assertEquals(new Integer(mtu), na.mtu);
Xiao Mac00a7932019-06-03 10:30:04 +0900971 }
972
973 private void assertIpMemoryNeverStoreNetworkAttributes() {
Xiao Ma927a8912021-01-07 08:05:02 +0000974 assertIpMemoryNeverStoreNetworkAttributes(TEST_L2KEY, TEST_TIMEOUT_MS);
Xiao Mac00a7932019-06-03 10:30:04 +0900975 }
976
Xiao Ma8bcd6732019-08-26 17:24:26 +0900977 private void assertHostname(final boolean isHostnameConfigurationEnabled,
978 final String hostname, final String hostnameAfterTransliteration,
979 final List<DhcpPacket> packetList) throws Exception {
980 for (DhcpPacket packet : packetList) {
981 if (!isHostnameConfigurationEnabled || hostname == null) {
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900982 assertNoHostname(packet.getHostname());
Xiao Ma8bcd6732019-08-26 17:24:26 +0900983 } else {
984 assertEquals(packet.getHostname(), hostnameAfterTransliteration);
985 }
986 }
987 }
988
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900989 private void assertNoHostname(String hostname) {
Lorenzo Colitti0d08b442020-04-27 11:49:39 +0900990 if (ShimUtils.isAtLeastR()) {
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900991 assertNull(hostname);
992 } else {
993 // Until Q, if no hostname is set, the device falls back to the hostname set via
994 // system property, to avoid breaking Q devices already launched with that setup.
995 assertEquals(SystemProperties.get("net.hostname"), hostname);
996 }
997 }
998
Xiao Mac00a7932019-06-03 10:30:04 +0900999 // Helper method to complete DHCP 2-way or 4-way handshake
Xiao Ma8bcd6732019-08-26 17:24:26 +09001000 private List<DhcpPacket> performDhcpHandshake(final boolean isSuccessLease,
Xiao Mac00a7932019-06-03 10:30:04 +09001001 final Integer leaseTimeSec, final boolean isDhcpLeaseCacheEnabled,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001002 final boolean shouldReplyRapidCommitAck, final int mtu,
Xiao Ma8bcd6732019-08-26 17:24:26 +09001003 final boolean isDhcpIpConflictDetectEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +00001004 final boolean isIPv6OnlyPreferredEnabled,
Xiao Ma562d2422019-12-16 13:20:59 +09001005 final String captivePortalApiUrl, final String displayName,
Xiao Ma861fe422021-04-16 03:03:03 +00001006 final ScanResultInfo scanResultInfo, final Layer2Information layer2Info)
1007 throws Exception {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001008 startIpClientProvisioning(isDhcpLeaseCacheEnabled, shouldReplyRapidCommitAck,
Xiao Ma8bcd6732019-08-26 17:24:26 +09001009 false /* isPreconnectionEnabled */, isDhcpIpConflictDetectEnabled,
Xiao Ma861fe422021-04-16 03:03:03 +00001010 isIPv6OnlyPreferredEnabled, displayName, scanResultInfo, layer2Info);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001011 return handleDhcpPackets(isSuccessLease, leaseTimeSec, shouldReplyRapidCommitAck, mtu,
Xiao Ma872b2362020-05-27 12:10:40 +09001012 captivePortalApiUrl);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001013 }
Xiao Mac00a7932019-06-03 10:30:04 +09001014
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001015 private List<DhcpPacket> handleDhcpPackets(final boolean isSuccessLease,
1016 final Integer leaseTimeSec, final boolean shouldReplyRapidCommitAck, final int mtu,
Xiao Ma872b2362020-05-27 12:10:40 +09001017 final String captivePortalApiUrl) throws Exception {
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001018 final List<DhcpPacket> packetList = new ArrayList<>();
Xiao Mac00a7932019-06-03 10:30:04 +09001019 DhcpPacket packet;
1020 while ((packet = getNextDhcpPacket()) != null) {
Xiao Ma8bcd6732019-08-26 17:24:26 +09001021 packetList.add(packet);
Xiao Mac00a7932019-06-03 10:30:04 +09001022 if (packet instanceof DhcpDiscoverPacket) {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001023 if (shouldReplyRapidCommitAck) {
Xiao Ma8bbceb42019-10-08 16:21:07 +09001024 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec,
1025 (short) mtu, true /* rapidCommit */, captivePortalApiUrl));
Xiao Mac00a7932019-06-03 10:30:04 +09001026 } else {
Xiao Ma6e2818b2020-06-22 01:18:22 +09001027 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR,
1028 leaseTimeSec, (short) mtu, captivePortalApiUrl));
Xiao Mac00a7932019-06-03 10:30:04 +09001029 }
1030 } else if (packet instanceof DhcpRequestPacket) {
1031 final ByteBuffer byteBuffer = isSuccessLease
Xiao Ma8bbceb42019-10-08 16:21:07 +09001032 ? buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec, (short) mtu,
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001033 false /* rapidCommit */, captivePortalApiUrl)
Xiao Ma780c09e2021-11-05 09:43:12 +00001034 : buildDhcpNakPacket(packet, "duplicated request IP address");
Lorenzo Colitti32215002020-03-13 19:40:32 +09001035 mPacketReader.sendResponse(byteBuffer);
Xiao Mac00a7932019-06-03 10:30:04 +09001036 } else {
1037 fail("invalid DHCP packet");
1038 }
Xiao Ma16b21ef2020-01-22 17:51:26 +09001039
Xiao Mac00a7932019-06-03 10:30:04 +09001040 // wait for reply to DHCPOFFER packet if disabling rapid commit option
Xiao Ma8bcd6732019-08-26 17:24:26 +09001041 if (shouldReplyRapidCommitAck || !(packet instanceof DhcpDiscoverPacket)) {
1042 return packetList;
1043 }
Xiao Mac00a7932019-06-03 10:30:04 +09001044 }
1045 fail("No DHCPREQUEST received on interface");
Xiao Ma8bcd6732019-08-26 17:24:26 +09001046 return packetList;
1047 }
1048
1049 private List<DhcpPacket> performDhcpHandshake(final boolean isSuccessLease,
1050 final Integer leaseTimeSec, final boolean isDhcpLeaseCacheEnabled,
1051 final boolean isDhcpRapidCommitEnabled, final int mtu,
1052 final boolean isDhcpIpConflictDetectEnabled) throws Exception {
1053 return performDhcpHandshake(isSuccessLease, leaseTimeSec, isDhcpLeaseCacheEnabled,
1054 isDhcpRapidCommitEnabled, mtu, isDhcpIpConflictDetectEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +00001055 false /* isIPv6OnlyPreferredEnabled */,
Xiao Ma861fe422021-04-16 03:03:03 +00001056 null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */,
1057 null /* layer2Info */);
Xiao Mac00a7932019-06-03 10:30:04 +09001058 }
1059
Lorenzo Colitti46a78742020-04-02 20:21:16 +09001060 private List<DhcpPacket> performDhcpHandshake() throws Exception {
1061 return performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
1062 false /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
1063 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
1064 }
1065
Xiao Ma861fe422021-04-16 03:03:03 +00001066 private DhcpPacket getNextDhcpPacket(final long timeout) throws Exception {
1067 byte[] packet;
1068 while ((packet = mDhcpPacketReadHead.getValue()
1069 .poll(timeout, this::isDhcpPacket)) != null) {
1070 final DhcpPacket dhcpPacket = DhcpPacket.decodeFullPacket(packet, packet.length,
1071 ENCAP_L2);
1072 if (dhcpPacket != null) return dhcpPacket;
1073 }
1074 return null;
1075 }
1076
1077 private DhcpPacket getNextDhcpPacket() throws Exception {
1078 final DhcpPacket packet = getNextDhcpPacket(PACKET_TIMEOUT_MS);
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001079 assertNotNull("No expected DHCP packet received on interface within timeout", packet);
Xiao Ma861fe422021-04-16 03:03:03 +00001080 return packet;
Xiao Mac00a7932019-06-03 10:30:04 +09001081 }
1082
1083 private DhcpPacket getReplyFromDhcpLease(final NetworkAttributes na, boolean timeout)
1084 throws Exception {
1085 doAnswer(invocation -> {
1086 if (timeout) return null;
1087 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1))
1088 .onNetworkAttributesRetrieved(new Status(SUCCESS), TEST_L2KEY, na);
1089 return null;
1090 }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any());
1091 startIpClientProvisioning(true /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001092 false /* shouldReplyRapidCommitAck */, false /* isPreconnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001093 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mac00a7932019-06-03 10:30:04 +09001094 return getNextDhcpPacket();
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001095 }
1096
Xiao Maac371ef2021-09-15 03:37:41 +00001097 private void removeTestInterface(final FileDescriptor fd) {
Xiao Ma619c28c2019-08-23 16:47:22 +09001098 try {
1099 Os.close(fd);
1100 } catch (ErrnoException e) {
1101 fail("Fail to close file descriptor: " + e);
1102 }
1103 }
1104
1105 private void verifyAfterIpClientShutdown() throws RemoteException {
1106 final LinkProperties emptyLp = new LinkProperties();
1107 emptyLp.setInterfaceName(mIfaceName);
1108 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(emptyLp);
1109 }
1110
Xiao Ma872b2362020-05-27 12:10:40 +09001111 // Verify IPv4-only provisioning success. No need to verify IPv4 provisioning when below cases
1112 // happen:
1113 // 1. if there's a failure lease, onProvisioningSuccess() won't be called;
1114 // 2. if duplicated IPv4 address detection is enabled, verify TIMEOUT will affect ARP packets
1115 // capture running in other test cases.
1116 // 3. if IPv6 is enabled, e.g. withoutIPv6() isn't called when starting provisioning.
1117 private void verifyIPv4OnlyProvisioningSuccess(final Collection<InetAddress> addresses)
1118 throws Exception {
1119 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
Xiao Ma16b21ef2020-01-22 17:51:26 +09001120 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
1121 LinkProperties lp = captor.getValue();
1122 assertNotNull(lp);
1123 assertNotEquals(0, lp.getDnsServers().size());
1124 assertEquals(addresses.size(), lp.getAddresses().size());
1125 assertTrue(lp.getAddresses().containsAll(addresses));
1126 }
1127
Xiao Ma619c28c2019-08-23 16:47:22 +09001128 private void doRestoreInitialMtuTest(final boolean shouldChangeMtu,
Xiao Maac371ef2021-09-15 03:37:41 +00001129 final boolean shouldRemoveTestInterface) throws Exception {
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001130 final long currentTime = System.currentTimeMillis();
1131 int mtu = TEST_DEFAULT_MTU;
1132
1133 if (shouldChangeMtu) mtu = TEST_MIN_MTU;
1134 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001135 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001136 mtu, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001137 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001138 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, mtu);
1139
1140 if (shouldChangeMtu) {
1141 // Pretend that ConnectivityService set the MTU.
1142 mNetd.interfaceSetMtu(mIfaceName, mtu);
1143 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), mtu);
1144 }
1145
Xiao Ma5c110212020-03-29 16:11:47 +09001146 // Sometimes, IpClient receives an update with an empty LinkProperties during startup,
1147 // when the link-local address is deleted after interface bringup. Reset expectations
1148 // here to ensure that verifyAfterIpClientShutdown does not fail because it sees two
1149 // empty LinkProperties changes instead of one.
1150 reset(mCb);
1151
Xiao Maac371ef2021-09-15 03:37:41 +00001152 if (shouldRemoveTestInterface) removeTestInterface(mTapFd);
Xiao Ma619c28c2019-08-23 16:47:22 +09001153 try {
1154 mIpc.shutdown();
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001155 awaitIpClientShutdown();
Xiao Maac371ef2021-09-15 03:37:41 +00001156 if (shouldRemoveTestInterface) {
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001157 verify(mNetd, never()).interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU);
Xiao Ma619c28c2019-08-23 16:47:22 +09001158 } else {
1159 // Verify that MTU indeed has been restored or not.
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001160 verify(mNetd, times(shouldChangeMtu ? 1 : 0))
Xiao Ma619c28c2019-08-23 16:47:22 +09001161 .interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU);
1162 }
1163 verifyAfterIpClientShutdown();
1164 } catch (Exception e) {
1165 fail("Exception should not have been thrown after shutdown: " + e);
1166 }
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001167 }
1168
Xiao Ma96147b72020-05-06 19:09:38 +09001169 private DhcpPacket assertDiscoverPacketOnPreconnectionStart() throws Exception {
1170 final ArgumentCaptor<List<Layer2PacketParcelable>> l2PacketList =
1171 ArgumentCaptor.forClass(List.class);
1172
1173 verify(mCb, timeout(TEST_TIMEOUT_MS)).onPreconnectionStart(l2PacketList.capture());
1174 final byte[] payload = l2PacketList.getValue().get(0).payload;
1175 DhcpPacket packet = DhcpPacket.decodeFullPacket(payload, payload.length, ENCAP_L2);
1176 assertTrue(packet instanceof DhcpDiscoverPacket);
1177 assertArrayEquals(INADDR_BROADCAST.getAddress(),
1178 Arrays.copyOfRange(payload, IPV4_DST_ADDR_OFFSET, IPV4_DST_ADDR_OFFSET + 4));
1179 return packet;
1180 }
1181
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001182 private void doIpClientProvisioningWithPreconnectionTest(
1183 final boolean shouldReplyRapidCommitAck, final boolean shouldAbortPreconnection,
1184 final boolean shouldFirePreconnectionTimeout,
1185 final boolean timeoutBeforePreconnectionComplete) throws Exception {
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001186 final long currentTime = System.currentTimeMillis();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001187 final ArgumentCaptor<InterfaceConfigurationParcel> ifConfig =
1188 ArgumentCaptor.forClass(InterfaceConfigurationParcel.class);
1189
1190 startIpClientProvisioning(true /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001191 shouldReplyRapidCommitAck, true /* isDhcpPreConnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001192 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Ma96147b72020-05-06 19:09:38 +09001193 DhcpPacket packet = assertDiscoverPacketOnPreconnectionStart();
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001194 final int preconnDiscoverTransId = packet.getTransactionId();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001195
1196 if (shouldAbortPreconnection) {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001197 if (shouldFirePreconnectionTimeout && timeoutBeforePreconnectionComplete) {
1198 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1199 }
1200
1201 mIpc.notifyPreconnectionComplete(false /* abort */);
Chalard Jean23a06302020-06-26 00:41:00 +09001202 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001203
1204 if (shouldFirePreconnectionTimeout && !timeoutBeforePreconnectionComplete) {
1205 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1206 }
1207
1208 // Either way should get DhcpClient go back to INIT state, and broadcast
1209 // DISCOVER with new transaction ID.
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001210 packet = getNextDhcpPacket();
1211 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001212 assertTrue(packet.getTransactionId() != preconnDiscoverTransId);
1213 } else if (shouldFirePreconnectionTimeout && timeoutBeforePreconnectionComplete) {
1214 // If timeout fires before success preconnection, DhcpClient will go back to INIT state,
1215 // and broadcast DISCOVER with new transaction ID.
1216 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1217 packet = getNextDhcpPacket();
1218 assertTrue(packet instanceof DhcpDiscoverPacket);
1219 assertTrue(packet.getTransactionId() != preconnDiscoverTransId);
1220 // any old response would be ignored due to mismatched transaction ID.
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001221 }
1222
1223 final short mtu = (short) TEST_DEFAULT_MTU;
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001224 if (!shouldReplyRapidCommitAck) {
Xiao Ma6e2818b2020-06-22 01:18:22 +09001225 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR,
1226 TEST_LEASE_DURATION_S, mtu, null /* captivePortalUrl */));
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001227 packet = getNextDhcpPacket();
1228 assertTrue(packet instanceof DhcpRequestPacket);
1229 }
Xiao Ma8bbceb42019-10-08 16:21:07 +09001230 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, TEST_LEASE_DURATION_S,
1231 mtu, shouldReplyRapidCommitAck, null /* captivePortalUrl */));
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001232
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001233 if (!shouldAbortPreconnection) {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001234 mIpc.notifyPreconnectionComplete(true /* success */);
Chalard Jean23a06302020-06-26 00:41:00 +09001235 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001236
1237 // If timeout fires after successful preconnection, right now DhcpClient will have
1238 // already entered BOUND state, the delayed CMD_TIMEOUT command would be ignored. So
1239 // this case should be very rare, because the timeout alarm is cancelled when state
1240 // machine exits from Preconnecting state.
1241 if (shouldFirePreconnectionTimeout && !timeoutBeforePreconnectionComplete) {
1242 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1243 }
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001244 }
1245 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
1246
1247 final LinkAddress ipAddress = new LinkAddress(CLIENT_ADDR, PREFIX_LENGTH);
1248 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetCfg(ifConfig.capture());
1249 assertEquals(ifConfig.getValue().ifName, mIfaceName);
1250 assertEquals(ifConfig.getValue().ipv4Addr, ipAddress.getAddress().getHostAddress());
1251 assertEquals(ifConfig.getValue().prefixLength, PREFIX_LENGTH);
1252 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
1253 }
1254
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001255 private ArpPacket getNextArpPacket(final long timeout) throws Exception {
Xiao Ma7d733952019-07-02 18:55:11 +09001256 byte[] packet;
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001257 while ((packet = mArpPacketReadHead.getValue().poll(timeout, p -> true)) != null) {
Xiao Ma7d733952019-07-02 18:55:11 +09001258 final ArpPacket arpPacket = parseArpPacketOrNull(packet);
1259 if (arpPacket != null) return arpPacket;
1260 }
1261 return null;
1262 }
1263
1264 private ArpPacket getNextArpPacket() throws Exception {
1265 final ArpPacket packet = getNextArpPacket(PACKET_TIMEOUT_MS);
1266 assertNotNull("No expected ARP packet received on interface within timeout", packet);
1267 return packet;
1268 }
1269
1270 private void assertArpPacket(final ArpPacket packet) {
1271 assertEquals(packet.opCode, ARP_REQUEST);
1272 assertEquals(packet.targetIp, CLIENT_ADDR);
1273 assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac));
1274 }
1275
1276 private void assertArpProbe(final ArpPacket packet) {
1277 assertArpPacket(packet);
1278 assertEquals(packet.senderIp, INADDR_ANY);
1279 }
1280
1281 private void assertArpAnnounce(final ArpPacket packet) {
1282 assertArpPacket(packet);
1283 assertEquals(packet.senderIp, CLIENT_ADDR);
1284 }
1285
Xiao Ma8a0b7672021-04-19 08:33:29 +00001286 private void assertGratuitousARP(final ArpPacket packet) {
1287 assertEquals(packet.opCode, ARP_REPLY);
1288 assertEquals(packet.senderIp, CLIENT_ADDR);
1289 assertEquals(packet.targetIp, CLIENT_ADDR);
1290 assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac));
1291 assertTrue(Arrays.equals(packet.targetHwAddress.toByteArray(), ETHER_BROADCAST));
1292 }
1293
Xiao Ma7d733952019-07-02 18:55:11 +09001294 private void doIpAddressConflictDetectionTest(final boolean causeIpAddressConflict,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001295 final boolean shouldReplyRapidCommitAck, final boolean isDhcpIpConflictDetectEnabled,
Xiao Ma7d733952019-07-02 18:55:11 +09001296 final boolean shouldResponseArpReply) throws Exception {
1297 final long currentTime = System.currentTimeMillis();
1298
1299 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001300 true /* isDhcpLeaseCacheEnabled */, shouldReplyRapidCommitAck,
Xiao Ma7d733952019-07-02 18:55:11 +09001301 TEST_DEFAULT_MTU, isDhcpIpConflictDetectEnabled);
1302
1303 // If we receive an ARP packet here, it's guaranteed to be from IP conflict detection,
1304 // because at this time the test interface does not have an IP address and therefore
1305 // won't send ARP for anything.
1306 if (causeIpAddressConflict) {
1307 final ArpPacket arpProbe = getNextArpPacket();
1308 assertArpProbe(arpProbe);
1309
1310 if (shouldResponseArpReply) {
1311 sendArpReply(mClientMac);
1312 } else {
1313 sendArpProbe();
1314 }
1315 final DhcpPacket packet = getNextDhcpPacket();
1316 assertTrue(packet instanceof DhcpDeclinePacket);
1317 assertEquals(packet.mServerIdentifier, SERVER_ADDR);
1318 assertEquals(packet.mRequestedIp, CLIENT_ADDR);
Xiao Ma16b21ef2020-01-22 17:51:26 +09001319
1320 verify(mCb, never()).onProvisioningFailure(any());
Xiao Ma7d733952019-07-02 18:55:11 +09001321 assertIpMemoryNeverStoreNetworkAttributes();
1322 } else if (isDhcpIpConflictDetectEnabled) {
1323 int arpPacketCount = 0;
1324 final List<ArpPacket> packetList = new ArrayList<ArpPacket>();
1325 // Total sent ARP packets should be 5 (3 ARP Probes + 2 ARP Announcements)
1326 ArpPacket packet;
1327 while ((packet = getNextArpPacket(TEST_TIMEOUT_MS)) != null) {
1328 packetList.add(packet);
1329 }
1330 assertEquals(5, packetList.size());
1331 assertArpProbe(packetList.get(0));
1332 assertArpAnnounce(packetList.get(3));
Xiao Ma4edc4f62020-05-21 10:32:47 +09001333 } else {
Xiao Ma872b2362020-05-27 12:10:40 +09001334 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma7d733952019-07-02 18:55:11 +09001335 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime,
1336 TEST_DEFAULT_MTU);
1337 }
1338 }
1339
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001340 @Test @SignatureRequiredTest(reason = "InterfaceParams.getByName requires CAP_NET_ADMIN")
Lorenzo Colitti32336c92020-02-19 19:53:59 +09001341 public void testInterfaceParams() throws Exception {
1342 InterfaceParams params = InterfaceParams.getByName(mIfaceName);
1343 assertNotNull(params);
1344 assertEquals(mIfaceName, params.name);
1345 assertTrue(params.index > 0);
1346 assertNotNull(params.macAddr);
1347 assertTrue(params.hasMacAddress);
1348
Hongguang Chenebb78392020-07-28 15:34:05 -07001349 // Check interface "lo".
Lorenzo Colitti32336c92020-02-19 19:53:59 +09001350 params = InterfaceParams.getByName("lo");
1351 assertNotNull(params);
1352 assertEquals("lo", params.name);
1353 assertTrue(params.index > 0);
1354 assertNotNull(params.macAddr);
1355 assertFalse(params.hasMacAddress);
1356 }
1357
1358 @Test
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001359 public void testDhcpInit() throws Exception {
Xiao Mac00a7932019-06-03 10:30:04 +09001360 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001361 false /* shouldReplyRapidCommitAck */, false /* isPreconnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001362 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mac00a7932019-06-03 10:30:04 +09001363 final DhcpPacket packet = getNextDhcpPacket();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001364 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001365 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001366
Xiao Ma927a8912021-01-07 08:05:02 +00001367 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001368 public void testHandleSuccessDhcpLease() throws Exception {
1369 final long currentTime = System.currentTimeMillis();
1370 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001371 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001372 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001373 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001374 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001375 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001376
Xiao Ma927a8912021-01-07 08:05:02 +00001377 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001378 public void testHandleFailureDhcpLease() throws Exception {
1379 performDhcpHandshake(false /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001380 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001381 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma16b21ef2020-01-22 17:51:26 +09001382
1383 verify(mCb, never()).onProvisioningSuccess(any());
Xiao Mac00a7932019-06-03 10:30:04 +09001384 assertIpMemoryNeverStoreNetworkAttributes();
1385 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001386
Xiao Ma927a8912021-01-07 08:05:02 +00001387 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001388 public void testHandleInfiniteLease() throws Exception {
1389 final long currentTime = System.currentTimeMillis();
1390 performDhcpHandshake(true /* isSuccessLease */, INFINITE_LEASE,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001391 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001392 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001393 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001394 assertIpMemoryStoreNetworkAttributes(INFINITE_LEASE, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001395 }
1396
Xiao Ma927a8912021-01-07 08:05:02 +00001397 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001398 public void testHandleNoLease() throws Exception {
1399 final long currentTime = System.currentTimeMillis();
1400 performDhcpHandshake(true /* isSuccessLease */, null /* no lease time */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001401 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001402 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001403 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001404 assertIpMemoryStoreNetworkAttributes(null, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001405 }
1406
Xiao Mafa33d492020-05-15 21:59:00 +09001407 @Test @IgnoreAfter(Build.VERSION_CODES.Q) // INIT-REBOOT is enabled on R.
Xiao Mac00a7932019-06-03 10:30:04 +09001408 public void testHandleDisableInitRebootState() throws Exception {
1409 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001410 false /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001411 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001412 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Mac00a7932019-06-03 10:30:04 +09001413 assertIpMemoryNeverStoreNetworkAttributes();
1414 }
1415
Xiao Ma927a8912021-01-07 08:05:02 +00001416 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001417 public void testHandleRapidCommitOption() throws Exception {
Xiao Mac00a7932019-06-03 10:30:04 +09001418 final long currentTime = System.currentTimeMillis();
1419 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001420 true /* isDhcpLeaseCacheEnabled */, true /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001421 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001422 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001423 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001424 }
1425
Xiao Ma8d645772022-03-15 01:19:16 +00001426 @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
Xiao Ma7ae2ec32021-09-29 06:07:15 +00001427 public void testRollbackFromRapidCommitOption() throws Exception {
1428 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
1429 true /* isDhcpRapidCommitEnabled */, false /* isPreConnectionEnabled */,
1430 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
1431
1432 final List<DhcpPacket> discoverList = new ArrayList<DhcpPacket>();
1433 DhcpPacket packet;
1434 do {
1435 packet = getNextDhcpPacket();
1436 assertTrue(packet instanceof DhcpDiscoverPacket);
1437 discoverList.add(packet);
1438 } while (discoverList.size() < 4);
1439
1440 // Check the only first 3 DHCPDISCOVERs take rapid commit option.
1441 assertTrue(discoverList.get(0).mRapidCommit);
1442 assertTrue(discoverList.get(1).mRapidCommit);
1443 assertTrue(discoverList.get(2).mRapidCommit);
1444 assertFalse(discoverList.get(3).mRapidCommit);
1445 }
1446
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001447 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001448 public void testDhcpClientStartWithCachedInfiniteLease() throws Exception {
1449 final DhcpPacket packet = getReplyFromDhcpLease(
1450 new NetworkAttributes.Builder()
1451 .setAssignedV4Address(CLIENT_ADDR)
1452 .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001453 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001454 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001455 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1456 .build(), false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001457 assertTrue(packet instanceof DhcpRequestPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001458 }
1459
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001460 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001461 public void testDhcpClientStartWithCachedExpiredLease() throws Exception {
1462 final DhcpPacket packet = getReplyFromDhcpLease(
1463 new NetworkAttributes.Builder()
1464 .setAssignedV4Address(CLIENT_ADDR)
1465 .setAssignedV4AddressExpiry(EXPIRED_LEASE)
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001466 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001467 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001468 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1469 .build(), false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001470 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001471 }
1472
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001473 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001474 public void testDhcpClientStartWithNullRetrieveNetworkAttributes() throws Exception {
1475 final DhcpPacket packet = getReplyFromDhcpLease(null /* na */, false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001476 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001477 }
1478
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001479 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001480 public void testDhcpClientStartWithTimeoutRetrieveNetworkAttributes() throws Exception {
1481 final DhcpPacket packet = getReplyFromDhcpLease(
1482 new NetworkAttributes.Builder()
1483 .setAssignedV4Address(CLIENT_ADDR)
1484 .setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000)
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001485 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001486 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001487 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1488 .build(), true /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001489 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001490 }
1491
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001492 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001493 public void testDhcpClientStartWithCachedLeaseWithoutIPAddress() throws Exception {
1494 final DhcpPacket packet = getReplyFromDhcpLease(
1495 new NetworkAttributes.Builder()
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001496 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001497 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001498 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1499 .build(), false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001500 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001501 }
1502
Xiao Ma927a8912021-01-07 08:05:02 +00001503 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001504 public void testDhcpClientRapidCommitEnabled() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00001505 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001506 true /* shouldReplyRapidCommitAck */, false /* isPreconnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001507 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mac00a7932019-06-03 10:30:04 +09001508 final DhcpPacket packet = getNextDhcpPacket();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001509 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001510 }
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001511
Lorenzo Colitti46a78742020-04-02 20:21:16 +09001512 @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
1513 public void testDhcpServerInLinkProperties() throws Exception {
Lorenzo Colitti75aac042020-04-24 17:01:37 +09001514 assumeTrue(ConstantsShim.VERSION > Build.VERSION_CODES.Q);
1515
Lorenzo Colitti46a78742020-04-02 20:21:16 +09001516 performDhcpHandshake();
1517 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
1518 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
1519 assertEquals(SERVER_ADDR, captor.getValue().getDhcpServerAddress());
1520 }
1521
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001522 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001523 public void testRestoreInitialInterfaceMtu() throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001524 doRestoreInitialMtuTest(true /* shouldChangeMtu */, false /* shouldRemoveTestInterface */);
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001525 }
1526
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001527 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma619c28c2019-08-23 16:47:22 +09001528 public void testRestoreInitialInterfaceMtu_WithoutMtuChange() throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001529 doRestoreInitialMtuTest(false /* shouldChangeMtu */, false /* shouldRemoveTestInterface */);
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001530 }
1531
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001532 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma619c28c2019-08-23 16:47:22 +09001533 public void testRestoreInitialInterfaceMtu_WithException() throws Exception {
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001534 doThrow(new RemoteException("NetdNativeService::interfaceSetMtu")).when(mNetd)
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001535 .interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU);
1536
Xiao Maac371ef2021-09-15 03:37:41 +00001537 doRestoreInitialMtuTest(true /* shouldChangeMtu */, false /* shouldRemoveTestInterface */);
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001538 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_MIN_MTU);
1539 }
Xiao Ma619c28c2019-08-23 16:47:22 +09001540
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001541 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma619c28c2019-08-23 16:47:22 +09001542 public void testRestoreInitialInterfaceMtu_NotFoundInterfaceWhenStopping() throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001543 doRestoreInitialMtuTest(true /* shouldChangeMtu */, true /* shouldRemoveTestInterface */);
Xiao Ma619c28c2019-08-23 16:47:22 +09001544 }
1545
Xiao Ma927a8912021-01-07 08:05:02 +00001546 @Test
Xiao Ma619c28c2019-08-23 16:47:22 +09001547 public void testRestoreInitialInterfaceMtu_NotFoundInterfaceWhenStartingProvisioning()
1548 throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001549 removeTestInterface(mTapFd);
Xiao Ma619c28c2019-08-23 16:47:22 +09001550 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1551 .withoutIpReachabilityMonitor()
1552 .withoutIPv6()
1553 .build();
1554
Xiao Ma927a8912021-01-07 08:05:02 +00001555 startIpClientProvisioning(config);
Xiao Ma5c110212020-03-29 16:11:47 +09001556 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
Xiao Ma619c28c2019-08-23 16:47:22 +09001557 verify(mCb, never()).setNeighborDiscoveryOffload(true);
1558 }
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001559
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001560 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma5c110212020-03-29 16:11:47 +09001561 public void testRestoreInitialInterfaceMtu_stopIpClientAndRestart() throws Exception {
1562 long currentTime = System.currentTimeMillis();
1563
1564 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
1565 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
1566 TEST_MIN_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001567 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma5c110212020-03-29 16:11:47 +09001568 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_MIN_MTU);
1569
1570 // Pretend that ConnectivityService set the MTU.
1571 mNetd.interfaceSetMtu(mIfaceName, TEST_MIN_MTU);
1572 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_MIN_MTU);
1573
1574 reset(mCb);
1575 reset(mIpMemoryStore);
1576
1577 // Stop IpClient and then restart provisioning immediately.
1578 mIpc.stop();
1579 currentTime = System.currentTimeMillis();
1580 // Intend to set mtu option to 0, then verify that won't influence interface mtu restore.
1581 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
1582 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
1583 0 /* mtu */, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001584 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma5c110212020-03-29 16:11:47 +09001585 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, 0 /* mtu */);
1586 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_DEFAULT_MTU);
1587 }
1588
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001589 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7dc8ef82020-08-13 15:25:06 +09001590 public void testRestoreInitialInterfaceMtu_removeInterfaceAndAddback() throws Exception {
1591 doAnswer(invocation -> {
1592 final LinkProperties lp = invocation.getArgument(0);
1593 assertEquals(lp.getInterfaceName(), mIfaceName);
1594 assertEquals(0, lp.getLinkAddresses().size());
1595 assertEquals(0, lp.getDnsServers().size());
1596
1597 mDependencies.simulateInterfaceRecover();
1598 return null;
1599 }).when(mCb).onProvisioningFailure(any());
1600
1601 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1602 .withoutIpReachabilityMonitor()
1603 .withoutIPv6()
1604 .build();
1605
1606 // Intend to remove the tap interface and force IpClient throw provisioning failure
1607 // due to that interface is not found.
Xiao Maac371ef2021-09-15 03:37:41 +00001608 removeTestInterface(mTapFd);
Xiao Ma7dc8ef82020-08-13 15:25:06 +09001609 assertNull(InterfaceParams.getByName(mIfaceName));
1610
Xiao Ma927a8912021-01-07 08:05:02 +00001611 startIpClientProvisioning(config);
Xiao Ma7dc8ef82020-08-13 15:25:06 +09001612 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
1613
1614 // Make sure everything queued by this test was processed (e.g. transition to StoppingState
1615 // from ClearingIpAddressState) and tearDown will check if IpClient exits normally or crash.
1616 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
1617 }
1618
Xiao Ma60175d22021-06-02 12:28:40 +00001619 private boolean isIcmpv6PacketOfType(final byte[] packetBytes, int type) {
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001620 ByteBuffer packet = ByteBuffer.wrap(packetBytes);
1621 return packet.getShort(ETHER_TYPE_OFFSET) == (short) ETH_P_IPV6
1622 && packet.get(ETHER_HEADER_LEN + IPV6_PROTOCOL_OFFSET) == (byte) IPPROTO_ICMPV6
Xiao Ma60175d22021-06-02 12:28:40 +00001623 && packet.get(ETHER_HEADER_LEN + IPV6_HEADER_LEN) == (byte) type;
1624 }
1625
1626 private boolean isRouterSolicitation(final byte[] packetBytes) {
1627 return isIcmpv6PacketOfType(packetBytes, ICMPV6_ROUTER_SOLICITATION);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001628 }
1629
Xiao Ma002dd5a2020-12-22 01:14:49 +00001630 private boolean isNeighborAdvertisement(final byte[] packetBytes) {
Xiao Ma60175d22021-06-02 12:28:40 +00001631 return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_ADVERTISEMENT);
1632 }
1633
1634 private boolean isNeighborSolicitation(final byte[] packetBytes) {
1635 return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_SOLICITATION);
Xiao Ma002dd5a2020-12-22 01:14:49 +00001636 }
1637
1638 private NeighborAdvertisement getNextNeighborAdvertisement() throws ParseException {
1639 final byte[] packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS,
1640 this::isNeighborAdvertisement);
1641 if (packet == null) return null;
1642
1643 final NeighborAdvertisement na = parseNeighborAdvertisementOrNull(packet);
1644 assertNotNull("Invalid neighbour advertisement received", na);
1645 return na;
1646 }
1647
Xiao Ma60175d22021-06-02 12:28:40 +00001648 private NeighborSolicitation getNextNeighborSolicitation() throws ParseException {
1649 final byte[] packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS,
1650 this::isNeighborSolicitation);
1651 if (packet == null) return null;
1652
1653 final NeighborSolicitation ns = parseNeighborSolicitationOrNull(packet);
1654 assertNotNull("Invalid neighbour solicitation received", ns);
1655 return ns;
1656 }
1657
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001658 private void waitForRouterSolicitation() throws ParseException {
Remi NGUYEN VAN0a867502020-06-18 17:08:08 +09001659 assertNotNull("No router solicitation received on interface within timeout",
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001660 mPacketReader.popPacket(PACKET_TIMEOUT_MS, this::isRouterSolicitation));
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001661 }
1662
Xiao Ma4edc4f62020-05-21 10:32:47 +09001663 private void sendRouterAdvertisement(boolean waitForRs, short lifetime) throws Exception {
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001664 final String dnsServer = "2001:4860:4860::64";
1665 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
1666 ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
Xiao Ma4edc4f62020-05-21 10:32:47 +09001667 ByteBuffer ra = buildRaPacket(lifetime, pio, rdnss);
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001668
1669 if (waitForRs) {
1670 waitForRouterSolicitation();
1671 }
1672
1673 mPacketReader.sendResponse(ra);
1674 }
1675
Xiao Ma4edc4f62020-05-21 10:32:47 +09001676 private void sendBasicRouterAdvertisement(boolean waitForRs) throws Exception {
1677 sendRouterAdvertisement(waitForRs, (short) 1800);
1678 }
1679
1680 private void sendRouterAdvertisementWithZeroLifetime() throws Exception {
1681 sendRouterAdvertisement(false /* waitForRs */, (short) 0);
1682 }
1683
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001684 // TODO: move this and the following method to a common location and use them in ApfTest.
1685 private static ByteBuffer buildPioOption(int valid, int preferred, String prefixString)
1686 throws Exception {
Xiao Maaf321442021-02-05 09:04:42 +00001687 return PrefixInformationOption.build(new IpPrefix(prefixString),
Xiao Ma002dd5a2020-12-22 01:14:49 +00001688 (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), valid, preferred);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001689 }
1690
1691 private static ByteBuffer buildRdnssOption(int lifetime, String... servers) throws Exception {
Xiao Maaf321442021-02-05 09:04:42 +00001692 return RdnssOption.build(lifetime, servers);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001693 }
1694
Xiao Ma60175d22021-06-02 12:28:40 +00001695 private static ByteBuffer buildSllaOption() throws Exception {
1696 return LlaOption.build((byte) ICMPV6_ND_OPTION_SLLA, ROUTER_MAC);
1697 }
1698
Xiao Ma4edc4f62020-05-21 10:32:47 +09001699 private static ByteBuffer buildRaPacket(short lifetime, ByteBuffer... options)
1700 throws Exception {
Xiao Ma60175d22021-06-02 12:28:40 +00001701 final MacAddress dstMac =
1702 NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST);
1703 return Ipv6Utils.buildRaPacket(ROUTER_MAC /* srcMac */, dstMac,
1704 ROUTER_LINK_LOCAL /* srcIp */, IPV6_ADDR_ALL_NODES_MULTICAST /* dstIp */,
1705 (byte) 0 /* M=0, O=0 */, lifetime, 0 /* Reachable time, unspecified */,
1706 100 /* Retrans time 100ms */, options);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001707 }
1708
Xiao Ma4edc4f62020-05-21 10:32:47 +09001709 private static ByteBuffer buildRaPacket(ByteBuffer... options) throws Exception {
1710 return buildRaPacket((short) 1800, options);
1711 }
1712
Lorenzo Colittibd919742020-04-24 23:16:49 +09001713 private void disableIpv6ProvisioningDelays() throws Exception {
1714 // Speed up the test by disabling DAD and removing router_solicitation_delay.
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001715 // We don't need to restore the default value because the interface is removed in tearDown.
Lorenzo Colittibd919742020-04-24 23:16:49 +09001716 // TODO: speed up further by not waiting for RS but keying off first IPv6 packet.
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001717 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "router_solicitation_delay", "0");
Lorenzo Colittibd919742020-04-24 23:16:49 +09001718 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits", "0");
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001719 }
1720
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001721 private void assertHasAddressThat(String msg, LinkProperties lp,
1722 Predicate<LinkAddress> condition) {
1723 for (LinkAddress addr : lp.getLinkAddresses()) {
1724 if (condition.test(addr)) {
1725 return;
1726 }
1727 }
1728 fail(msg + " not found in: " + lp);
1729 }
1730
1731 private boolean hasFlag(LinkAddress addr, int flag) {
1732 return (addr.getFlags() & flag) == flag;
1733 }
1734
1735 private boolean isPrivacyAddress(LinkAddress addr) {
1736 return addr.isGlobalPreferred() && hasFlag(addr, IFA_F_TEMPORARY);
1737 }
1738
1739 private boolean isStablePrivacyAddress(LinkAddress addr) {
Xiao Maebc22a82021-08-13 06:34:39 +00001740 // The Q netd does not understand the IFA_F_STABLE_PRIVACY flag.
1741 // See r.android.com/1295670.
1742 final int flag = (mIsNetlinkEventParseEnabled || ShimUtils.isAtLeastR())
1743 ? IFA_F_STABLE_PRIVACY : 0;
Lorenzo Colitti558eb962020-04-27 11:43:23 +09001744 return addr.isGlobalPreferred() && hasFlag(addr, flag);
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001745 }
1746
Xiao Ma8a0b7672021-04-19 08:33:29 +00001747 private LinkProperties doIpv6OnlyProvisioning() throws Exception {
1748 final InOrder inOrder = inOrder(mCb);
1749 final String dnsServer = "2001:4860:4860::64";
1750 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
1751 final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
Xiao Ma60175d22021-06-02 12:28:40 +00001752 final ByteBuffer slla = buildSllaOption();
1753 final ByteBuffer ra = buildRaPacket(pio, rdnss, slla);
Xiao Ma8a0b7672021-04-19 08:33:29 +00001754
1755 return doIpv6OnlyProvisioning(inOrder, ra);
1756 }
1757
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001758 private LinkProperties doIpv6OnlyProvisioning(InOrder inOrder, ByteBuffer ra) throws Exception {
1759 waitForRouterSolicitation();
1760 mPacketReader.sendResponse(ra);
1761
1762 // The lambda below needs to write a LinkProperties to a local variable, but lambdas cannot
1763 // write to non-final local variables. So declare a final variable to write to.
1764 final AtomicReference<LinkProperties> lpRef = new AtomicReference<>();
1765
1766 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
1767 verifyWithTimeout(inOrder, mCb).onProvisioningSuccess(captor.capture());
1768 lpRef.set(captor.getValue());
1769
1770 // Sometimes provisioning completes as soon as the link-local and the stable address appear,
1771 // before the privacy address appears. If so, wait here for the LinkProperties update that
1772 // contains all three address. Otherwise, future calls to verify() might get confused.
1773 if (captor.getValue().getLinkAddresses().size() == 2) {
1774 verifyWithTimeout(inOrder, mCb).onLinkPropertiesChange(argThat(lp -> {
1775 lpRef.set(lp);
1776 return lp.getLinkAddresses().size() == 3;
1777 }));
1778 }
1779
1780 LinkProperties lp = lpRef.get();
1781 assertEquals("Should have 3 IPv6 addresses after provisioning: " + lp,
1782 3, lp.getLinkAddresses().size());
1783 assertHasAddressThat("link-local address", lp, x -> x.getAddress().isLinkLocalAddress());
1784 assertHasAddressThat("privacy address", lp, this::isPrivacyAddress);
1785 assertHasAddressThat("stable privacy address", lp, this::isStablePrivacyAddress);
1786
1787 return lp;
1788 }
1789
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001790 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001791 public void testRaRdnss() throws Exception {
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001792 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1793 .withoutIpReachabilityMonitor()
1794 .withoutIPv4()
1795 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00001796 startIpClientProvisioning(config);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001797
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001798 InOrder inOrder = inOrder(mCb);
1799 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
1800
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001801 final String dnsServer = "2001:4860:4860::64";
1802 final String lowlifeDnsServer = "2001:4860:4860::6464";
1803
1804 final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64");
1805 ByteBuffer rdnss1 = buildRdnssOption(60, lowlifeDnsServer);
1806 ByteBuffer rdnss2 = buildRdnssOption(600, dnsServer);
1807 ByteBuffer ra = buildRaPacket(pio, rdnss1, rdnss2);
1808
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001809 LinkProperties lp = doIpv6OnlyProvisioning(inOrder, ra);
Lorenzo Colitti2cdb76a2020-04-25 01:11:50 +09001810
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +09001811 // Expect that DNS servers with lifetimes below CONFIG_MIN_RDNSS_LIFETIME are not accepted.
1812 assertNotNull(lp);
1813 assertEquals(1, lp.getDnsServers().size());
1814 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +09001815
1816 // If the RDNSS lifetime is above the minimum, the DNS server is accepted.
1817 rdnss1 = buildRdnssOption(68, lowlifeDnsServer);
1818 ra = buildRaPacket(pio, rdnss1, rdnss2);
Lorenzo Colitti32215002020-03-13 19:40:32 +09001819 mPacketReader.sendResponse(ra);
Lorenzo Colitti2cdb76a2020-04-25 01:11:50 +09001820 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(captor.capture());
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +09001821 lp = captor.getValue();
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001822 assertNotNull(lp);
1823 assertEquals(2, lp.getDnsServers().size());
1824 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
1825 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(lowlifeDnsServer)));
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001826
1827 // Expect that setting RDNSS lifetime of 0 causes loss of provisioning.
1828 rdnss1 = buildRdnssOption(0, dnsServer);
1829 rdnss2 = buildRdnssOption(0, lowlifeDnsServer);
1830 ra = buildRaPacket(pio, rdnss1, rdnss2);
Lorenzo Colitti32215002020-03-13 19:40:32 +09001831 mPacketReader.sendResponse(ra);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001832
Lorenzo Colitti2cdb76a2020-04-25 01:11:50 +09001833 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001834 lp = captor.getValue();
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09001835 assertNotNull(lp);
1836 assertEquals(0, lp.getDnsServers().size());
1837 reset(mCb);
1838 }
1839
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001840 private void expectNat64PrefixUpdate(InOrder inOrder, IpPrefix expected) throws Exception {
1841 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(
1842 argThat(lp -> Objects.equals(expected, lp.getNat64Prefix())));
1843
1844 }
1845
1846 private void expectNoNat64PrefixUpdate(InOrder inOrder, IpPrefix unchanged) throws Exception {
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001847 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS).times(0)).onLinkPropertiesChange(argThat(
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001848 lp -> !Objects.equals(unchanged, lp.getNat64Prefix())));
1849
1850 }
1851
1852 @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001853 @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001854 public void testPref64Option() throws Exception {
Lorenzo Colitti75aac042020-04-24 17:01:37 +09001855 assumeTrue(ConstantsShim.VERSION > Build.VERSION_CODES.Q);
1856
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001857 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1858 .withoutIpReachabilityMonitor()
1859 .withoutIPv4()
1860 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00001861 startIpClientProvisioning(config);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001862
1863 final String dnsServer = "2001:4860:4860::64";
1864 final IpPrefix prefix = new IpPrefix("64:ff9b::/96");
1865 final IpPrefix otherPrefix = new IpPrefix("2001:db8:64::/96");
1866
1867 final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64");
1868 ByteBuffer rdnss = buildRdnssOption(600, dnsServer);
1869 ByteBuffer pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer();
1870 ByteBuffer ra = buildRaPacket(pio, rdnss, pref64);
1871
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001872 // The NAT64 prefix might be detected before or after provisioning success.
1873 // Don't test order between these two events.
Lorenzo Colittic84530f2020-04-27 10:15:29 +09001874 LinkProperties lp = doIpv6OnlyProvisioning(null /*inOrder*/, ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001875 expectAlarmSet(null /*inOrder*/, "PREF64", 600);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001876
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001877 // From now on expect events in order.
1878 InOrder inOrder = inOrder(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001879 if (lp.getNat64Prefix() != null) {
1880 assertEquals(prefix, lp.getNat64Prefix());
1881 } else {
1882 expectNat64PrefixUpdate(inOrder, prefix);
1883 }
1884
1885 // Increase the lifetime and expect the prefix not to change.
1886 pref64 = new StructNdOptPref64(prefix, 1800).toByteBuffer();
1887 ra = buildRaPacket(pio, rdnss, pref64);
1888 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001889 OnAlarmListener pref64Alarm = expectAlarmSet(inOrder, "PREF64", 1800);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001890 expectNoNat64PrefixUpdate(inOrder, prefix);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001891 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001892
Lorenzo Colitti21957512020-04-24 01:06:55 +09001893 // Reduce the lifetime and expect to reschedule expiry.
1894 pref64 = new StructNdOptPref64(prefix, 1500).toByteBuffer();
1895 ra = buildRaPacket(pio, rdnss, pref64);
1896 mPacketReader.sendResponse(ra);
1897 pref64Alarm = expectAlarmSet(inOrder, "PREF64", 1496);
1898 expectNoNat64PrefixUpdate(inOrder, prefix);
1899 reset(mCb, mAlarm);
1900
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001901 // Withdraw the prefix and expect it to be set to null.
1902 pref64 = new StructNdOptPref64(prefix, 0).toByteBuffer();
1903 ra = buildRaPacket(pio, rdnss, pref64);
1904 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001905 expectAlarmCancelled(inOrder, pref64Alarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001906 expectNat64PrefixUpdate(inOrder, null);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001907 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001908
1909 // Re-announce the prefix.
1910 pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer();
1911 ra = buildRaPacket(pio, rdnss, pref64);
1912 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001913 expectAlarmSet(inOrder, "PREF64", 600);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001914 expectNat64PrefixUpdate(inOrder, prefix);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001915 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001916
1917 // Announce two prefixes. Don't expect any update because if there is already a NAT64
1918 // prefix, any new prefix is ignored.
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001919 ByteBuffer otherPref64 = new StructNdOptPref64(otherPrefix, 1200).toByteBuffer();
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001920 ra = buildRaPacket(pio, rdnss, pref64, otherPref64);
1921 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001922 expectAlarmSet(inOrder, "PREF64", 600);
1923 expectNoNat64PrefixUpdate(inOrder, prefix);
1924 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001925
Lorenzo Colitti21957512020-04-24 01:06:55 +09001926 // Withdraw the old prefix and continue to announce the new one. Expect a prefix change.
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001927 pref64 = new StructNdOptPref64(prefix, 0).toByteBuffer();
1928 ra = buildRaPacket(pio, rdnss, pref64, otherPref64);
1929 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001930 expectAlarmCancelled(inOrder, pref64Alarm);
1931 // Need a different OnAlarmListener local variable because posting it to the handler in the
1932 // lambda below requires it to be final.
1933 final OnAlarmListener lastAlarm = expectAlarmSet(inOrder, "PREF64", 1200);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001934 expectNat64PrefixUpdate(inOrder, otherPrefix);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001935 reset(mCb, mAlarm);
1936
1937 // Simulate prefix expiry.
1938 mIpc.getHandler().post(() -> lastAlarm.onAlarm());
1939 expectAlarmCancelled(inOrder, pref64Alarm);
1940 expectNat64PrefixUpdate(inOrder, null);
Lorenzo Colitti50862202020-05-04 13:27:37 +09001941
Lorenzo Colitti747f0d12020-05-06 23:27:45 +09001942 // Announce a non-/96 prefix and expect it to be ignored.
1943 IpPrefix invalidPrefix = new IpPrefix("64:ff9b::/64");
1944 pref64 = new StructNdOptPref64(invalidPrefix, 1200).toByteBuffer();
1945 ra = buildRaPacket(pio, rdnss, pref64);
1946 mPacketReader.sendResponse(ra);
1947 expectNoNat64PrefixUpdate(inOrder, invalidPrefix);
1948
Lorenzo Colitti50862202020-05-04 13:27:37 +09001949 // Re-announce the prefix.
1950 pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer();
1951 ra = buildRaPacket(pio, rdnss, pref64);
1952 mPacketReader.sendResponse(ra);
1953 final OnAlarmListener clearAlarm = expectAlarmSet(inOrder, "PREF64", 600);
1954 expectNat64PrefixUpdate(inOrder, prefix);
1955 reset(mCb, mAlarm);
1956
1957 // Check that the alarm is cancelled when IpClient is stopped.
1958 mIpc.stop();
Chalard Jean23a06302020-06-26 00:41:00 +09001959 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Lorenzo Colitti50862202020-05-04 13:27:37 +09001960 expectAlarmCancelled(inOrder, clearAlarm);
1961 expectNat64PrefixUpdate(inOrder, null);
1962
1963 // Check that even if the alarm was already in the message queue while it was cancelled, it
1964 // is safely ignored.
1965 mIpc.getHandler().post(() -> clearAlarm.onAlarm());
Chalard Jean23a06302020-06-26 00:41:00 +09001966 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001967 }
1968
Xiao Maebc22a82021-08-13 06:34:39 +00001969 private void waitForAddressViaNetworkObserver(final String iface, final String addr1,
1970 final String addr2, int prefixLength) throws Exception {
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001971 final CountDownLatch latch = new CountDownLatch(1);
1972
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001973 // Add two IPv4 addresses to the specified interface, and proceed when the NetworkObserver
1974 // has seen the second one. This ensures that every other NetworkObserver registered with
1975 // mNetworkObserverRegistry - in particular, IpClient's - has seen the addition of the first
1976 // address.
1977 final LinkAddress trigger = new LinkAddress(addr2 + "/" + prefixLength);
1978 NetworkObserver observer = new NetworkObserver() {
1979 @Override
1980 public void onInterfaceAddressUpdated(LinkAddress address, String ifName) {
1981 if (ifName.equals(iface) && address.isSameAddressAs(trigger)) {
1982 latch.countDown();
1983 }
1984 }
1985 };
1986
1987 mNetworkObserverRegistry.registerObserverForNonblockingCallback(observer);
1988 try {
1989 mNetd.interfaceAddAddress(iface, addr1, prefixLength);
1990 mNetd.interfaceAddAddress(iface, addr2, prefixLength);
1991 assertTrue("Trigger IP address " + addr2 + " not seen after " + TEST_TIMEOUT_MS + "ms",
1992 latch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
1993 } finally {
1994 mNetworkObserverRegistry.unregisterObserver(observer);
1995 }
Xiao Maebc22a82021-08-13 06:34:39 +00001996 }
1997
1998 private void addIpAddressAndWaitForIt(final String iface) throws Exception {
1999 final String addr1 = "192.0.2.99";
2000 final String addr2 = "192.0.2.3";
2001 final int prefixLength = 26;
2002
2003 if (!mIsNetlinkEventParseEnabled) {
2004 waitForAddressViaNetworkObserver(iface, addr1, addr2, prefixLength);
2005 } else {
2006 // IpClient gets IP addresses directly from netlink instead of from netd, unnecessary
2007 // to rely on the NetworkObserver callbacks to confirm new added address update. Just
2008 // add the addresses directly and wait to see if IpClient has seen the address
2009 mNetd.interfaceAddAddress(iface, addr1, prefixLength);
2010 mNetd.interfaceAddAddress(iface, addr2, prefixLength);
2011 }
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002012
2013 // Wait for IpClient to process the addition of the address.
Chalard Jean23a06302020-06-26 00:41:00 +09002014 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002015 }
2016
Xiao Ma15275d72020-06-15 18:59:27 +09002017 private void doIPv4OnlyProvisioningAndExitWithLeftAddress() throws Exception {
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002018 final long currentTime = System.currentTimeMillis();
2019 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002020 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09002021 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09002022 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002023 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2024
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002025 // Stop IpClient and expect a final LinkProperties callback with an empty LP.
Xiao Ma927a8912021-01-07 08:05:02 +00002026 mIIpClient.stop();
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002027 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat(
2028 x -> x.getAddresses().size() == 0
2029 && x.getRoutes().size() == 0
2030 && x.getDnsServers().size() == 0));
2031 reset(mCb);
2032
2033 // Pretend that something else (e.g., Tethering) used the interface and left an IP address
2034 // configured on it. When IpClient starts, it must clear this address before proceeding.
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002035 // The address must be noticed before startProvisioning is called, or IpClient will
2036 // immediately declare provisioning success due to the presence of an IPv4 address.
2037 // The address must be IPv4 because IpClient clears IPv6 addresses on startup.
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002038 addIpAddressAndWaitForIt(mIfaceName);
Xiao Ma15275d72020-06-15 18:59:27 +09002039 }
2040
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002041 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma15275d72020-06-15 18:59:27 +09002042 public void testIpClientClearingIpAddressState() throws Exception {
2043 doIPv4OnlyProvisioningAndExitWithLeftAddress();
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002044
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002045 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2046 .withoutIpReachabilityMonitor()
2047 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00002048 startIpClientProvisioning(config);
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002049
2050 sendBasicRouterAdvertisement(true /*waitForRs*/);
2051
2052 // Check that the IPv4 addresses configured earlier are not in LinkProperties...
2053 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
2054 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
2055 assertFalse(captor.getValue().hasIpv4Address());
2056
2057 // ... or configured on the interface.
2058 InterfaceConfigurationParcel cfg = mNetd.interfaceGetCfg(mIfaceName);
2059 assertEquals("0.0.0.0", cfg.ipv4Addr);
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002060 }
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002061
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002062 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma15275d72020-06-15 18:59:27 +09002063 public void testIpClientClearingIpAddressState_enablePreconnection() throws Exception {
2064 doIPv4OnlyProvisioningAndExitWithLeftAddress();
2065
2066 // Enter ClearingIpAddressesState to clear the remaining IPv4 addresses and transition to
2067 // PreconnectionState instead of RunningState.
2068 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
2069 false /* shouldReplyRapidCommitAck */, true /* isDhcpPreConnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002070 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Ma15275d72020-06-15 18:59:27 +09002071 assertDiscoverPacketOnPreconnectionStart();
2072
2073 // Force to enter RunningState.
2074 mIpc.notifyPreconnectionComplete(false /* abort */);
Chalard Jean23a06302020-06-26 00:41:00 +09002075 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma15275d72020-06-15 18:59:27 +09002076 }
2077
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002078 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002079 public void testDhcpClientPreconnection_success() throws Exception {
2080 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2081 false /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2082 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002083 }
2084
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002085 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002086 public void testDhcpClientPreconnection_SuccessWithoutRapidCommit() throws Exception {
2087 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2088 false /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2089 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002090 }
2091
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002092 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002093 public void testDhcpClientPreconnection_Abort() throws Exception {
2094 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2095 true /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2096 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002097 }
2098
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002099 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002100 public void testDhcpClientPreconnection_AbortWithoutRapiCommit() throws Exception {
2101 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2102 true /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2103 false /* timeoutBeforePreconnectionComplete */);
2104 }
2105
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002106 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002107 public void testDhcpClientPreconnection_TimeoutBeforeAbort() throws Exception {
2108 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2109 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2110 true /* timeoutBeforePreconnectionComplete */);
2111 }
2112
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002113 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002114 public void testDhcpClientPreconnection_TimeoutBeforeAbortWithoutRapidCommit()
2115 throws Exception {
2116 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2117 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2118 true /* timeoutBeforePreconnectionComplete */);
2119 }
2120
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002121 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002122 public void testDhcpClientPreconnection_TimeoutafterAbort() throws Exception {
2123 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2124 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2125 false /* timeoutBeforePreconnectionComplete */);
2126 }
2127
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002128 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002129 public void testDhcpClientPreconnection_TimeoutAfterAbortWithoutRapidCommit() throws Exception {
2130 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2131 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2132 false /* timeoutBeforePreconnectionComplete */);
2133 }
2134
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002135 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002136 public void testDhcpClientPreconnection_TimeoutBeforeSuccess() throws Exception {
2137 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2138 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2139 true /* timeoutBeforePreconnectionComplete */);
2140 }
2141
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002142 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002143 public void testDhcpClientPreconnection_TimeoutBeforeSuccessWithoutRapidCommit()
2144 throws Exception {
2145 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2146 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2147 true /* timeoutBeforePreconnectionComplete */);
2148 }
2149
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002150 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002151 public void testDhcpClientPreconnection_TimeoutAfterSuccess() throws Exception {
2152 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2153 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2154 false /* timeoutBeforePreconnectionComplete */);
2155 }
2156
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002157 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002158 public void testDhcpClientPreconnection_TimeoutAfterSuccessWithoutRapidCommit()
2159 throws Exception {
2160 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2161 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2162 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002163 }
Xiao Ma7d733952019-07-02 18:55:11 +09002164
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002165 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma96147b72020-05-06 19:09:38 +09002166 public void testDhcpClientPreconnection_WithoutLayer2InfoWhenStartingProv() throws Exception {
Chalard Jeanb2896832020-05-13 19:16:49 +09002167 // For FILS connection, current bssid (also l2key and cluster) is still null when
Xiao Ma96147b72020-05-06 19:09:38 +09002168 // starting provisioning since the L2 link hasn't been established yet. Ensure that
2169 // IpClient won't crash even if initializing an Layer2Info class with null members.
2170 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
2171 .withoutIpReachabilityMonitor()
2172 .withoutIPv6()
2173 .withPreconnection()
Chalard Jeanb2896832020-05-13 19:16:49 +09002174 .withLayer2Information(new Layer2Information(null /* l2key */, null /* cluster */,
Xiao Ma96147b72020-05-06 19:09:38 +09002175 null /* bssid */));
2176
Xiao Ma927a8912021-01-07 08:05:02 +00002177 startIpClientProvisioning(prov.build());
Xiao Ma96147b72020-05-06 19:09:38 +09002178 assertDiscoverPacketOnPreconnectionStart();
2179 verify(mCb).setNeighborDiscoveryOffload(true);
2180
2181 // Force IpClient transition to RunningState from PreconnectionState.
Xiao Ma927a8912021-01-07 08:05:02 +00002182 mIIpClient.notifyPreconnectionComplete(false /* success */);
Chalard Jean23a06302020-06-26 00:41:00 +09002183 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma96147b72020-05-06 19:09:38 +09002184 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
2185 }
2186
Xiao Ma927a8912021-01-07 08:05:02 +00002187 @Test
Xiao Ma39511682021-07-30 02:40:06 +00002188 @SignatureRequiredTest(reason = "needs mocked alarm and access to IpClient handler thread")
2189 public void testDhcpClientPreconnection_DelayedAbortAndTransitToStoppedState()
2190 throws Exception {
2191 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2192 .withoutIpReachabilityMonitor()
2193 .withPreconnection()
2194 .build();
2195 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
2196 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
2197 startIpClientProvisioning(config);
2198 assertDiscoverPacketOnPreconnectionStart();
2199
2200 // IpClient is in the PreconnectingState, simulate provisioning timeout event
2201 // and force IpClient state machine transit to StoppingState.
2202 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
2203 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 18,
2204 mIpc.getHandler());
2205 mIpc.getHandler().post(() -> alarm.onAlarm());
2206
2207 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
2208 final LinkProperties lp = captor.getValue();
2209 assertNotNull(lp);
2210 assertEquals(mIfaceName, lp.getInterfaceName());
2211 assertEquals(0, lp.getLinkAddresses().size());
2212 assertEquals(0, lp.getRoutes().size());
2213 assertEquals(0, lp.getMtu());
2214 assertEquals(0, lp.getDnsServers().size());
2215
2216 // Send preconnection abort message, but IpClient should ignore it at this moment and
2217 // transit to StoppedState finally.
2218 mIpc.notifyPreconnectionComplete(false /* abort */);
2219 mIpc.stop();
2220 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
2221
2222 reset(mCb);
2223
2224 // Start provisioning again to verify IpClient can process CMD_START correctly at
2225 // StoppedState.
2226 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
2227 false /* shouldReplyRapidCommitAck */, false /* isPreConnectionEnabled */,
2228 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
2229 final DhcpPacket discover = getNextDhcpPacket();
2230 assertTrue(discover instanceof DhcpDiscoverPacket);
2231 }
2232
2233 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002234 public void testDhcpDecline_conflictByArpReply() throws Exception {
2235 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002236 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002237 true /* shouldResponseArpReply */);
2238 }
2239
Xiao Ma927a8912021-01-07 08:05:02 +00002240 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002241 public void testDhcpDecline_conflictByArpProbe() throws Exception {
2242 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002243 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002244 false /* shouldResponseArpReply */);
2245 }
2246
Xiao Ma927a8912021-01-07 08:05:02 +00002247 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002248 public void testDhcpDecline_EnableFlagWithoutIpConflict() throws Exception {
2249 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002250 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002251 false /* shouldResponseArpReply */);
2252 }
2253
Xiao Ma927a8912021-01-07 08:05:02 +00002254 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002255 public void testDhcpDecline_WithoutIpConflict() throws Exception {
2256 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002257 false /* shouldReplyRapidCommitAck */, false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002258 false /* shouldResponseArpReply */);
2259 }
2260
Xiao Ma927a8912021-01-07 08:05:02 +00002261 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002262 public void testDhcpDecline_WithRapidCommitWithoutIpConflict() throws Exception {
2263 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002264 true /* shouldReplyRapidCommitAck */, false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002265 false /* shouldResponseArpReply */);
2266 }
2267
Xiao Ma927a8912021-01-07 08:05:02 +00002268 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002269 public void testDhcpDecline_WithRapidCommitConflictByArpReply() throws Exception {
2270 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002271 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002272 true /* shouldResponseArpReply */);
2273 }
2274
Xiao Ma927a8912021-01-07 08:05:02 +00002275 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002276 public void testDhcpDecline_WithRapidCommitConflictByArpProbe() throws Exception {
2277 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002278 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002279 false /* shouldResponseArpReply */);
2280 }
2281
Xiao Ma927a8912021-01-07 08:05:02 +00002282 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002283 public void testDhcpDecline_EnableFlagWithRapidCommitWithoutIpConflict() throws Exception {
2284 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002285 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002286 false /* shouldResponseArpReply */);
2287 }
Xiao Ma8bcd6732019-08-26 17:24:26 +09002288
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002289 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bcd6732019-08-26 17:24:26 +09002290 public void testHostname_enableConfig() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00002291 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */,
2292 TEST_HOST_NAME);
2293
Xiao Ma8bcd6732019-08-26 17:24:26 +09002294 final long currentTime = System.currentTimeMillis();
2295 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2296 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2297 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
Xiao Ma861fe422021-04-16 03:03:03 +00002298 false /* isDhcpIpConflictDetectEnabled */);
2299
Xiao Ma8bcd6732019-08-26 17:24:26 +09002300 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002301 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bcd6732019-08-26 17:24:26 +09002302 assertHostname(true, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets);
2303 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2304 }
2305
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002306 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bcd6732019-08-26 17:24:26 +09002307 public void testHostname_disableConfig() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00002308 mDependencies.setHostnameConfiguration(false /* isHostnameConfigurationEnabled */,
2309 TEST_HOST_NAME);
2310
Xiao Ma8bcd6732019-08-26 17:24:26 +09002311 final long currentTime = System.currentTimeMillis();
2312 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2313 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2314 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
Xiao Ma861fe422021-04-16 03:03:03 +00002315 false /* isDhcpIpConflictDetectEnabled */);
2316
Xiao Ma8bcd6732019-08-26 17:24:26 +09002317 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002318 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bcd6732019-08-26 17:24:26 +09002319 assertHostname(false, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets);
2320 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2321 }
2322
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002323 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bcd6732019-08-26 17:24:26 +09002324 public void testHostname_enableConfigWithNullHostname() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00002325 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */,
2326 null /* hostname */);
2327
Xiao Ma8bcd6732019-08-26 17:24:26 +09002328 final long currentTime = System.currentTimeMillis();
2329 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2330 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2331 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
Xiao Ma861fe422021-04-16 03:03:03 +00002332 false /* isDhcpIpConflictDetectEnabled */);
2333
Xiao Ma8bcd6732019-08-26 17:24:26 +09002334 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002335 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bcd6732019-08-26 17:24:26 +09002336 assertHostname(true, null /* hostname */, null /* hostnameAfterTransliteration */,
2337 sentPackets);
2338 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2339 }
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002340
Xiao Mac4fa89c2021-12-24 08:48:48 +00002341 private LinkProperties runDhcpClientCaptivePortalApiTest(boolean featureEnabled,
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002342 boolean serverSendsOption) throws Exception {
2343 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
2344 false /* shouldReplyRapidCommitAck */, false /* isPreConnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002345 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002346 final DhcpPacket discover = getNextDhcpPacket();
2347 assertTrue(discover instanceof DhcpDiscoverPacket);
2348 assertEquals(featureEnabled, discover.hasRequestedParam(DhcpPacket.DHCP_CAPTIVE_PORTAL));
2349
2350 // Send Offer and handle Request -> Ack
2351 final String serverSentUrl = serverSendsOption ? TEST_CAPTIVE_PORTAL_URL : null;
Xiao Ma6e2818b2020-06-22 01:18:22 +09002352 mPacketReader.sendResponse(buildDhcpOfferPacket(discover, CLIENT_ADDR,
2353 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, serverSentUrl));
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002354 final int testMtu = 1345;
2355 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma872b2362020-05-27 12:10:40 +09002356 false /* shouldReplyRapidCommitAck */, testMtu, serverSentUrl);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002357
2358 final Uri expectedUrl = featureEnabled && serverSendsOption
2359 ? Uri.parse(TEST_CAPTIVE_PORTAL_URL) : null;
Remi NGUYEN VAN5304b782020-09-01 09:40:41 +09002360 // LinkProperties will be updated multiple times. Wait for it to contain DHCP-obtained info,
2361 // such as MTU.
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +09002362 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
Remi NGUYEN VAN5304b782020-09-01 09:40:41 +09002363 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +09002364 argThat(lp -> lp.getMtu() == testMtu));
2365
2366 // Ensure that the URL was set as expected in the callbacks.
2367 // Can't verify the URL up to Q as there is no such attribute in LinkProperties.
Xiao Mac4fa89c2021-12-24 08:48:48 +00002368 if (!ShimUtils.isAtLeastR()) return null;
Remi NGUYEN VAN5304b782020-09-01 09:40:41 +09002369 verify(mCb, atLeastOnce()).onLinkPropertiesChange(captor.capture());
Xiao Mac4fa89c2021-12-24 08:48:48 +00002370 final LinkProperties expectedLp = captor.getAllValues().stream().findFirst().get();
2371 assertNotNull(expectedLp);
2372 assertEquals(expectedUrl, expectedLp.getCaptivePortalApiUrl());
2373 return expectedLp;
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002374 }
2375
Xiao Ma927a8912021-01-07 08:05:02 +00002376 @Test
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002377 public void testDhcpClientCaptivePortalApiEnabled() throws Exception {
2378 // Only run the test on platforms / builds where the API is enabled
2379 assumeTrue(CaptivePortalDataShimImpl.isSupported());
2380 runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, true /* serverSendsOption */);
2381 }
2382
Xiao Ma927a8912021-01-07 08:05:02 +00002383 @Test
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002384 public void testDhcpClientCaptivePortalApiEnabled_NoUrl() throws Exception {
2385 // Only run the test on platforms / builds where the API is enabled
2386 assumeTrue(CaptivePortalDataShimImpl.isSupported());
2387 runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, false /* serverSendsOption */);
2388 }
2389
Xiao Ma927a8912021-01-07 08:05:02 +00002390 @Test
Xiao Mac4fa89c2021-12-24 08:48:48 +00002391 public void testDhcpClientCaptivePortalApiEnabled_ParcelSensitiveFields() throws Exception {
2392 // Only run the test on platforms / builds where the API is enabled
2393 assumeTrue(CaptivePortalDataShimImpl.isSupported());
2394 LinkProperties lp = runDhcpClientCaptivePortalApiTest(true /* featureEnabled */,
2395 true /* serverSendsOption */);
2396
2397 // Integration test process runs in the same process with network stack module, there
2398 // won't be any IPC call happened on IpClientCallbacks, manually run parcelingRoundTrip
2399 // to parcel and unparcel the LinkProperties to simulate what happens during the binder
2400 // call. In this case lp should contain the senstive data but mParcelSensitiveFields is
2401 // false after round trip.
2402 if (useNetworkStackSignature()) {
2403 lp = parcelingRoundTrip(lp);
2404 }
2405 final Uri expectedUrl = Uri.parse(TEST_CAPTIVE_PORTAL_URL);
2406 assertEquals(expectedUrl, lp.getCaptivePortalApiUrl());
2407
2408 // Parcel and unparcel the captured LinkProperties, mParcelSensitiveFields is false,
2409 // CaptivePortalApiUrl should be null after parceling round trip.
2410 final LinkProperties unparceled = parcelingRoundTrip(lp);
2411 assertNull(unparceled.getCaptivePortalApiUrl());
2412 }
2413
2414 @Test
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002415 public void testDhcpClientCaptivePortalApiDisabled() throws Exception {
2416 // Only run the test on platforms / builds where the API is disabled
2417 assumeFalse(CaptivePortalDataShimImpl.isSupported());
2418 runDhcpClientCaptivePortalApiTest(false /* featureEnabled */, true /* serverSendsOption */);
2419 }
Xiao Ma562d2422019-12-16 13:20:59 +09002420
2421 private ScanResultInfo makeScanResultInfo(final int id, final String ssid,
Xiao Maf784d612020-04-02 23:16:04 +09002422 final String bssid, final byte[] oui, final byte type, final byte[] data) {
Xiao Ma562d2422019-12-16 13:20:59 +09002423 final ByteBuffer payload = ByteBuffer.allocate(4 + data.length);
2424 payload.put(oui);
2425 payload.put(type);
2426 payload.put(data);
2427 payload.flip();
2428 final ScanResultInfo.InformationElement ie =
2429 new ScanResultInfo.InformationElement(id /* IE id */, payload);
Xiao Maf784d612020-04-02 23:16:04 +09002430 return new ScanResultInfo(ssid, bssid, Collections.singletonList(ie));
Xiao Ma562d2422019-12-16 13:20:59 +09002431 }
2432
Xiao Mae31734e2020-12-10 21:09:26 +09002433 private ScanResultInfo makeScanResultInfo(final int id, final byte[] oui, final byte type) {
2434 byte[] data = new byte[10];
2435 new Random().nextBytes(data);
2436 return makeScanResultInfo(id, TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID, oui, type, data);
2437 }
2438
Xiao Ma8bbceb42019-10-08 16:21:07 +09002439 private ScanResultInfo makeScanResultInfo(final String ssid, final String bssid) {
2440 byte[] data = new byte[10];
2441 new Random().nextBytes(data);
2442 return makeScanResultInfo(0xdd, ssid, bssid, TEST_AP_OUI, (byte) 0x06, data);
2443 }
2444
Xiao Ma562d2422019-12-16 13:20:59 +09002445 private void doUpstreamHotspotDetectionTest(final int id, final String displayName,
Xiao Ma8bbceb42019-10-08 16:21:07 +09002446 final String ssid, final byte[] oui, final byte type, final byte[] data,
2447 final boolean expectMetered) throws Exception {
Xiao Maf784d612020-04-02 23:16:04 +09002448 final ScanResultInfo info = makeScanResultInfo(id, ssid, TEST_DEFAULT_BSSID, oui, type,
2449 data);
Xiao Ma562d2422019-12-16 13:20:59 +09002450 final long currentTime = System.currentTimeMillis();
2451 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2452 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2453 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
2454 false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002455 false /* isIPv6OnlyPreferredEnabled */,
Xiao Ma861fe422021-04-16 03:03:03 +00002456 null /* captivePortalApiUrl */, displayName, info /* scanResultInfo */,
2457 null /* layer2Info */);
Xiao Ma562d2422019-12-16 13:20:59 +09002458 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002459 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma562d2422019-12-16 13:20:59 +09002460
2461 ArgumentCaptor<DhcpResultsParcelable> captor =
2462 ArgumentCaptor.forClass(DhcpResultsParcelable.class);
2463 verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(captor.capture());
2464 DhcpResults lease = fromStableParcelable(captor.getValue());
2465 assertNotNull(lease);
2466 assertEquals(lease.getIpAddress().getAddress(), CLIENT_ADDR);
2467 assertEquals(lease.getGateway(), SERVER_ADDR);
2468 assertEquals(1, lease.getDnsServers().size());
2469 assertTrue(lease.getDnsServers().contains(SERVER_ADDR));
2470 assertEquals(lease.getServerAddress(), SERVER_ADDR);
2471 assertEquals(lease.getMtu(), TEST_DEFAULT_MTU);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002472
2473 if (expectMetered) {
Xiao Ma562d2422019-12-16 13:20:59 +09002474 assertEquals(lease.vendorInfo, DhcpPacket.VENDOR_INFO_ANDROID_METERED);
2475 } else {
2476 assertNull(lease.vendorInfo);
2477 }
2478
2479 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2480 }
2481
Xiao Ma927a8912021-01-07 08:05:02 +00002482 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002483 public void testUpstreamHotspotDetection() throws Exception {
2484 byte[] data = new byte[10];
2485 new Random().nextBytes(data);
2486 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002487 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2488 true /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002489 }
2490
Xiao Ma927a8912021-01-07 08:05:02 +00002491 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002492 public void testUpstreamHotspotDetection_incorrectIeId() throws Exception {
2493 byte[] data = new byte[10];
2494 new Random().nextBytes(data);
2495 doUpstreamHotspotDetectionTest(0xdc, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002496 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2497 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002498 }
2499
Xiao Ma927a8912021-01-07 08:05:02 +00002500 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002501 public void testUpstreamHotspotDetection_incorrectOUI() throws Exception {
2502 byte[] data = new byte[10];
2503 new Random().nextBytes(data);
2504 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002505 new byte[] { (byte) 0x00, (byte) 0x1A, (byte) 0x11 }, (byte) 0x06, data,
2506 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002507 }
2508
Xiao Ma927a8912021-01-07 08:05:02 +00002509 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002510 public void testUpstreamHotspotDetection_incorrectSsid() throws Exception {
2511 byte[] data = new byte[10];
2512 new Random().nextBytes(data);
2513 doUpstreamHotspotDetectionTest(0xdd, "\"another ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002514 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2515 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002516 }
2517
Xiao Ma927a8912021-01-07 08:05:02 +00002518 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002519 public void testUpstreamHotspotDetection_incorrectType() throws Exception {
2520 byte[] data = new byte[10];
2521 new Random().nextBytes(data);
2522 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002523 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x0a, data,
2524 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002525 }
2526
Xiao Ma927a8912021-01-07 08:05:02 +00002527 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002528 public void testUpstreamHotspotDetection_zeroLengthData() throws Exception {
2529 byte[] data = new byte[0];
2530 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002531 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2532 true /* expectMetered */);
2533 }
2534
Xiao Ma8a0b7672021-04-19 08:33:29 +00002535 private void forceLayer2Roaming() throws Exception {
2536 final Layer2InformationParcelable roamingInfo = new Layer2InformationParcelable();
2537 roamingInfo.bssid = MacAddress.fromString(TEST_DHCP_ROAM_BSSID);
2538 roamingInfo.l2Key = TEST_DHCP_ROAM_L2KEY;
2539 roamingInfo.cluster = TEST_DHCP_ROAM_CLUSTER;
2540 mIIpClient.updateLayer2Information(roamingInfo);
2541 }
2542
Xiao Ma8bbceb42019-10-08 16:21:07 +09002543 private void doDhcpRoamingTest(final boolean hasMismatchedIpAddress, final String displayName,
Xiao Ma780c09e2021-11-05 09:43:12 +00002544 final MacAddress bssid, final boolean expectRoaming,
2545 final boolean shouldReplyNakOnRoam) throws Exception {
Xiao Ma8bbceb42019-10-08 16:21:07 +09002546 long currentTime = System.currentTimeMillis();
Xiao Ma861fe422021-04-16 03:03:03 +00002547 final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER, bssid);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002548
2549 doAnswer(invocation -> {
2550 // we don't rely on the Init-Reboot state to renew previous cached IP lease.
2551 // Just return null and force state machine enter INIT state.
Lorenzo Colittibd2f2f22020-04-25 18:41:11 +09002552 final String l2Key = invocation.getArgument(0);
2553 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1))
2554 .onNetworkAttributesRetrieved(new Status(SUCCESS), l2Key, null);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002555 return null;
2556 }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any());
2557
Xiao Ma927a8912021-01-07 08:05:02 +00002558 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */,
2559 null /* hostname */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002560 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
2561 true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */,
2562 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002563 false /* isIPv6OnlyPreferredEnabled */,
Xiao Ma861fe422021-04-16 03:03:03 +00002564 null /* captivePortalApiUrl */, displayName, null /* scanResultInfo */,
2565 layer2Info);
Xiao Ma872b2362020-05-27 12:10:40 +09002566 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bbceb42019-10-08 16:21:07 +09002567 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2568
2569 // simulate the roaming by updating bssid.
Xiao Ma8a0b7672021-04-19 08:33:29 +00002570 forceLayer2Roaming();
Xiao Ma8bbceb42019-10-08 16:21:07 +09002571
2572 currentTime = System.currentTimeMillis();
2573 reset(mIpMemoryStore);
2574 reset(mCb);
2575 if (!expectRoaming) {
2576 assertIpMemoryNeverStoreNetworkAttributes();
2577 return;
2578 }
2579 // check DHCPREQUEST broadcast sent to renew IP address.
2580 DhcpPacket packet;
2581 packet = getNextDhcpPacket();
2582 assertTrue(packet instanceof DhcpRequestPacket);
2583 assertEquals(packet.mClientIp, CLIENT_ADDR); // client IP
2584 assertNull(packet.mRequestedIp); // requested IP option
2585 assertNull(packet.mServerIdentifier); // server ID
2586
Xiao Ma780c09e2021-11-05 09:43:12 +00002587 final ByteBuffer packetBuffer = shouldReplyNakOnRoam
2588 ? buildDhcpNakPacket(packet, "request IP on a wrong subnet")
2589 : buildDhcpAckPacket(packet,
2590 hasMismatchedIpAddress ? CLIENT_ADDR_NEW : CLIENT_ADDR,
2591 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU,
2592 false /* rapidCommit */, null /* captivePortalApiUrl */);
2593 mPacketReader.sendResponse(packetBuffer);
Chalard Jean23a06302020-06-26 00:41:00 +09002594 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma780c09e2021-11-05 09:43:12 +00002595
Xiao Ma33cc64a2021-11-03 09:31:35 +00002596 if (shouldReplyNakOnRoam) {
2597 ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor =
2598 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class);
2599 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityFailure(lossInfoCaptor.capture());
2600 assertEquals(ReachabilityLossReason.ROAM, lossInfoCaptor.getValue().reason);
2601
2602 // IPv4 address will be still deleted when DhcpClient state machine exits from
2603 // DhcpHaveLeaseState, a following onProvisioningFailure will be thrown then.
2604 // Also check DhcpClient won't send any DHCPDISCOVER packet.
2605 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
2606 assertNull(getNextDhcpPacket(TEST_TIMEOUT_MS));
2607 verify(mCb, never()).onNewDhcpResults(any());
2608 } else if (hasMismatchedIpAddress) {
2609 ArgumentCaptor<DhcpResultsParcelable> resultsCaptor =
Xiao Ma8bbceb42019-10-08 16:21:07 +09002610 ArgumentCaptor.forClass(DhcpResultsParcelable.class);
Xiao Ma33cc64a2021-11-03 09:31:35 +00002611 verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(resultsCaptor.capture());
2612 DhcpResults lease = fromStableParcelable(resultsCaptor.getValue());
Xiao Ma8bbceb42019-10-08 16:21:07 +09002613 assertNull(lease);
2614
Xiao Ma780c09e2021-11-05 09:43:12 +00002615 // DhcpClient rolls back to StoppedState instead of INIT state after calling
2616 // notifyFailure, DHCPDISCOVER should not be sent out.
2617 assertNull(getNextDhcpPacket(TEST_TIMEOUT_MS));
Xiao Ma8bbceb42019-10-08 16:21:07 +09002618 } else {
2619 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime,
2620 TEST_DEFAULT_MTU);
2621 }
2622 }
2623
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002624 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002625 public void testDhcpRoaming() throws Exception {
2626 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002627 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */,
2628 false /* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002629 }
2630
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002631 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002632 public void testDhcpRoaming_invalidBssid() throws Exception {
2633 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002634 MacAddress.fromString(TEST_DHCP_ROAM_BSSID), false /* expectRoaming */,
2635 false/* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002636 }
2637
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002638 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma861fe422021-04-16 03:03:03 +00002639 public void testDhcpRoaming_nullBssid() throws Exception {
Xiao Maad5d93e2020-07-31 17:19:42 +09002640 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002641 null /* BSSID */, false /* expectRoaming */, false /* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002642 }
2643
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002644 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002645 public void testDhcpRoaming_invalidDisplayName() throws Exception {
2646 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"test-ssid\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002647 MacAddress.fromString(TEST_DEFAULT_BSSID), false /* expectRoaming */,
2648 false /* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002649 }
2650
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002651 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002652 public void testDhcpRoaming_mismatchedLeasedIpAddress() throws Exception {
2653 doDhcpRoamingTest(true /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002654 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */,
2655 false /* shouldReplyNakOnRoam */);
2656 }
2657
2658 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
2659 public void testDhcpRoaming_failureLeaseOnNak() throws Exception {
2660 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
2661 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */,
2662 true /* shouldReplyNakOnRoam */);
Xiao Ma562d2422019-12-16 13:20:59 +09002663 }
Xiao Ma4edc4f62020-05-21 10:32:47 +09002664
Xiao Ma8a0b7672021-04-19 08:33:29 +00002665 private void performDualStackProvisioning() throws Exception {
Xiao Ma4edc4f62020-05-21 10:32:47 +09002666 final InOrder inOrder = inOrder(mCb);
2667 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>();
2668 final String dnsServer = "2001:4860:4860::64";
2669 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
2670 final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
Xiao Ma60175d22021-06-02 12:28:40 +00002671 final ByteBuffer slla = buildSllaOption();
2672 final ByteBuffer ra = buildRaPacket(pio, rdnss, slla);
Xiao Ma4edc4f62020-05-21 10:32:47 +09002673
2674 doIpv6OnlyProvisioning(inOrder, ra);
2675
2676 // Start IPv4 provisioning and wait until entire provisioning completes.
2677 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
2678 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */);
2679 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(argThat(x -> {
2680 if (!x.isIpv4Provisioned() || !x.isIpv6Provisioned()) return false;
2681 lpFuture.complete(x);
2682 return true;
2683 }));
2684
2685 final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2686 assertNotNull(lp);
2687 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
2688 assertTrue(lp.getDnsServers().contains(SERVER_ADDR));
2689
2690 reset(mCb);
2691 }
2692
Xiao Ma690e12e2021-05-11 11:11:45 +00002693 private void doDualStackProvisioning(boolean shouldDisableAcceptRa) throws Exception {
Xiao Ma8a0b7672021-04-19 08:33:29 +00002694 when(mCm.shouldAvoidBadWifi()).thenReturn(true);
2695
2696 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2697 .withoutIpReachabilityMonitor()
2698 .build();
Xiao Ma690e12e2021-05-11 11:11:45 +00002699
2700 setFeatureEnabled(NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION,
2701 shouldDisableAcceptRa);
Xiao Ma8a0b7672021-04-19 08:33:29 +00002702 // Enable rapid commit to accelerate DHCP handshake to shorten test duration,
2703 // not strictly necessary.
2704 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
2705 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
2706 mIpc.startProvisioning(config);
2707
2708 performDualStackProvisioning();
2709 }
2710
Xiao Ma690e12e2021-05-11 11:11:45 +00002711 @Test @SignatureRequiredTest(reason = "signature perms are required due to mocked callabck")
2712 public void testIgnoreIpv6ProvisioningLoss_disableIPv6Stack() throws Exception {
2713 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Xiao Ma4edc4f62020-05-21 10:32:47 +09002714
2715 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>();
2716
2717 // Send RA with 0-lifetime and wait until all IPv6-related default route and DNS servers
2718 // have been removed, then verify if there is IPv4-only info left in the LinkProperties.
2719 sendRouterAdvertisementWithZeroLifetime();
2720 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
2721 argThat(x -> {
2722 final boolean isOnlyIPv4Provisioned = (x.getLinkAddresses().size() == 1
2723 && x.getDnsServers().size() == 1
2724 && x.getAddresses().get(0) instanceof Inet4Address
2725 && x.getDnsServers().get(0) instanceof Inet4Address);
2726
2727 if (!isOnlyIPv4Provisioned) return false;
2728 lpFuture.complete(x);
2729 return true;
2730 }));
2731 final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2732 assertNotNull(lp);
2733 assertEquals(lp.getAddresses().get(0), CLIENT_ADDR);
2734 assertEquals(lp.getDnsServers().get(0), SERVER_ADDR);
lifrf9105de2021-05-06 15:31:04 +08002735
2736 final ArgumentCaptor<Integer> quirkEvent = ArgumentCaptor.forClass(Integer.class);
2737 verify(mNetworkQuirkMetricsDeps, timeout(TEST_TIMEOUT_MS)).writeStats(quirkEvent.capture());
2738 assertEquals((long) quirkEvent.getValue(),
2739 (long) NetworkQuirkEvent.QE_IPV6_PROVISIONING_ROUTER_LOST.ordinal());
Xiao Ma4edc4f62020-05-21 10:32:47 +09002740 }
2741
Xiao Ma78c89f42022-03-30 22:07:50 +09002742 private boolean hasRouteTo(@NonNull final LinkProperties lp, @NonNull final String prefix) {
2743 for (RouteInfo r : lp.getRoutes()) {
2744 if (r.getDestination().equals(new IpPrefix(prefix))) return true;
2745 }
2746 return false;
2747 }
2748
Xiao Ma690e12e2021-05-11 11:11:45 +00002749 @Test @SignatureRequiredTest(reason = "signature perms are required due to mocked callabck")
2750 public void testIgnoreIpv6ProvisioningLoss_disableAcceptRa() throws Exception {
2751 doDualStackProvisioning(true /* shouldDisableAcceptRa */);
2752
2753 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>();
2754
2755 // Send RA with 0-lifetime and wait until all global IPv6 addresses, IPv6-related default
2756 // route and DNS servers have been removed, then verify if there is IPv4-only, IPv6 link
2757 // local address and route to fe80::/64 info left in the LinkProperties.
2758 sendRouterAdvertisementWithZeroLifetime();
2759 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
2760 argThat(x -> {
2761 // Only IPv4 provisioned and IPv6 link-local address
2762 final boolean isIPv6LinkLocalAndIPv4OnlyProvisioned =
2763 (x.getLinkAddresses().size() == 2
Xiao Ma78c89f42022-03-30 22:07:50 +09002764 // fe80::/64, IPv4 default route, IPv4 subnet route
2765 && x.getRoutes().size() == 3
Xiao Ma690e12e2021-05-11 11:11:45 +00002766 && x.getDnsServers().size() == 1
2767 && x.getAddresses().get(0) instanceof Inet4Address
2768 && x.getDnsServers().get(0) instanceof Inet4Address);
2769
2770 if (!isIPv6LinkLocalAndIPv4OnlyProvisioned) return false;
2771 lpFuture.complete(x);
2772 return true;
2773 }));
2774 final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2775 assertNotNull(lp);
2776 assertEquals(lp.getAddresses().get(0), CLIENT_ADDR);
2777 assertEquals(lp.getDnsServers().get(0), SERVER_ADDR);
Xiao Ma78c89f42022-03-30 22:07:50 +09002778 assertEquals(3, lp.getRoutes().size());
2779 assertTrue(hasRouteTo(lp, IPV6_LINK_LOCAL_PREFIX)); // fe80::/64
2780 assertTrue(hasRouteTo(lp, IPV4_TEST_SUBNET_PREFIX)); // IPv4 directly-connected route
2781 assertTrue(hasRouteTo(lp, IPV4_ANY_ADDRESS_PREFIX)); // IPv4 default route
Xiao Ma690e12e2021-05-11 11:11:45 +00002782 assertTrue(lp.getAddresses().get(1).isLinkLocalAddress());
2783
2784 reset(mCb);
2785
Xiao Ma97a0eec2022-03-25 09:40:18 +00002786 // Send an RA to verify that global IPv6 addresses won't be configured on the interface.
Xiao Ma690e12e2021-05-11 11:11:45 +00002787 sendBasicRouterAdvertisement(false /* waitForRs */);
Xiao Ma97a0eec2022-03-25 09:40:18 +00002788 verify(mCb, timeout(TEST_TIMEOUT_MS).times(0)).onLinkPropertiesChange(any());
Xiao Ma690e12e2021-05-11 11:11:45 +00002789 }
2790
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002791 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma4edc4f62020-05-21 10:32:47 +09002792 public void testDualStackProvisioning() throws Exception {
Xiao Ma690e12e2021-05-11 11:11:45 +00002793 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Xiao Ma4edc4f62020-05-21 10:32:47 +09002794
2795 verify(mCb, never()).onProvisioningFailure(any());
2796 }
Xiao Ma6e2818b2020-06-22 01:18:22 +09002797
2798 private DhcpPacket verifyDhcpPacketRequestsIPv6OnlyPreferredOption(
2799 Class<? extends DhcpPacket> packetType) throws Exception {
2800 final DhcpPacket packet = getNextDhcpPacket();
2801 assertTrue(packetType.isInstance(packet));
2802 assertTrue(packet.hasRequestedParam(DHCP_IPV6_ONLY_PREFERRED));
2803 return packet;
2804 }
2805
2806 private void doIPv6OnlyPreferredOptionTest(final Integer ipv6OnlyWaitTime,
2807 final Inet4Address clientAddress) throws Exception {
2808 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2809 .withoutIpReachabilityMonitor()
2810 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00002811 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, false /* isRapidCommitEnabled */,
2812 false /* isDhcpIpConflictDetectEnabled */, true /* isIPv6OnlyPreferredEnabled */);
2813 startIpClientProvisioning(config);
Xiao Ma6e2818b2020-06-22 01:18:22 +09002814
2815 final DhcpPacket packet =
2816 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2817
2818 // Respond DHCPOFFER with IPv6-Only preferred option and offered address.
2819 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, clientAddress,
2820 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, null /* captivePortalUrl */,
2821 ipv6OnlyWaitTime));
2822 }
2823
2824 private void doDiscoverIPv6OnlyPreferredOptionTest(final int optionSecs,
2825 final long expectedWaitSecs) throws Exception {
2826 doIPv6OnlyPreferredOptionTest(optionSecs, CLIENT_ADDR);
2827 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT",
2828 expectedWaitSecs, mDependencies.mDhcpClient.getHandler());
2829 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm());
2830 // Implicitly check that the client never sent a DHCPREQUEST to request the offered address.
2831 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2832 }
2833
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002834 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002835 public void testDiscoverIPv6OnlyPreferredOption() throws Exception {
2836 doDiscoverIPv6OnlyPreferredOptionTest(TEST_IPV6_ONLY_WAIT_S, TEST_IPV6_ONLY_WAIT_S);
2837 }
2838
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002839 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002840 public void testDiscoverIPv6OnlyPreferredOption_LowerIPv6OnlyWait() throws Exception {
2841 doDiscoverIPv6OnlyPreferredOptionTest(TEST_LOWER_IPV6_ONLY_WAIT_S,
2842 TEST_LOWER_IPV6_ONLY_WAIT_S);
2843 }
2844
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002845 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002846 public void testDiscoverIPv6OnlyPreferredOption_ZeroIPv6OnlyWait() throws Exception {
2847 doDiscoverIPv6OnlyPreferredOptionTest(TEST_ZERO_IPV6_ONLY_WAIT_S,
2848 TEST_LOWER_IPV6_ONLY_WAIT_S);
2849 }
2850
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002851 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002852 public void testDiscoverIPv6OnlyPreferredOption_MaxIPv6OnlyWait() throws Exception {
2853 doDiscoverIPv6OnlyPreferredOptionTest((int) TEST_MAX_IPV6_ONLY_WAIT_S, 0xffffffffL);
2854 }
2855
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002856 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002857 public void testDiscoverIPv6OnlyPreferredOption_ZeroIPv6OnlyWaitWithOfferedAnyAddress()
2858 throws Exception {
2859 doIPv6OnlyPreferredOptionTest(TEST_ZERO_IPV6_ONLY_WAIT_S, IPV4_ADDR_ANY);
2860
2861 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 300,
2862 mDependencies.mDhcpClient.getHandler());
2863 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm());
2864
2865 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2866 }
2867
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002868 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002869 public void testDiscoverIPv6OnlyPreferredOption_enabledPreconnection() throws Exception {
2870 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2871 .withoutIpReachabilityMonitor()
2872 .withPreconnection()
2873 .build();
2874
Xiao Ma927a8912021-01-07 08:05:02 +00002875 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
2876 false /* isDhcpIpConflictDetectEnabled */, true /* isIPv6OnlyPreferredEnabled */);
2877 startIpClientProvisioning(config);
Xiao Ma6e2818b2020-06-22 01:18:22 +09002878
2879 final DhcpPacket packet = assertDiscoverPacketOnPreconnectionStart();
2880 verify(mCb).setNeighborDiscoveryOffload(true);
2881
2882 // Force IpClient transition to RunningState from PreconnectionState.
2883 mIpc.notifyPreconnectionComplete(true /* success */);
2884 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS);
2885 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
2886
2887 // DHCP server SHOULD NOT honor the Rapid-Commit option if the response would
2888 // contain the IPv6-only Preferred option to the client, instead respond with
2889 // a DHCPOFFER.
2890 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR, TEST_LEASE_DURATION_S,
2891 (short) TEST_DEFAULT_MTU, null /* captivePortalUrl */, TEST_IPV6_ONLY_WAIT_S));
2892
2893 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 1800,
2894 mDependencies.mDhcpClient.getHandler());
2895 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm());
2896
2897 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2898 }
2899
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002900 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002901 public void testDiscoverIPv6OnlyPreferredOption_NoIPv6OnlyPreferredOption() throws Exception {
2902 doIPv6OnlyPreferredOptionTest(null /* ipv6OnlyWaitTime */, CLIENT_ADDR);
2903
2904 // The IPv6-only Preferred option SHOULD be included in the Parameter Request List option
2905 // in DHCPREQUEST messages after receiving a DHCPOFFER without this option.
2906 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpRequestPacket.class);
2907 }
2908
Xiao Ma4ca906c2021-01-30 12:09:41 +00002909 private void setUpRetrievedNetworkAttributesForInitRebootState() {
2910 final NetworkAttributes na = new NetworkAttributes.Builder()
2911 .setAssignedV4Address(CLIENT_ADDR)
2912 .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid
2913 .setMtu(new Integer(TEST_DEFAULT_MTU))
2914 .setCluster(TEST_CLUSTER)
2915 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
2916 .build();
2917 storeNetworkAttributes(TEST_L2KEY, na);
2918 }
2919
Xiao Ma6e2818b2020-06-22 01:18:22 +09002920 private void startFromInitRebootStateWithIPv6OnlyPreferredOption(final Integer ipv6OnlyWaitTime,
2921 final long expectedWaitSecs) throws Exception {
Xiao Ma4ca906c2021-01-30 12:09:41 +00002922 setUpRetrievedNetworkAttributesForInitRebootState();
Xiao Ma6e2818b2020-06-22 01:18:22 +09002923
2924 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2925 .withoutIpReachabilityMonitor()
2926 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
2927 MacAddress.fromString(TEST_DEFAULT_BSSID)))
2928 .build();
2929
Xiao Ma927a8912021-01-07 08:05:02 +00002930 setDhcpFeatures(true /* isDhcpLeaseCacheEnabled */, false /* isRapidCommitEnabled */,
2931 false /* isDhcpIpConflictDetectEnabled */, true /* isIPv6OnlyPreferredEnabled */);
2932 startIpClientProvisioning(config);
Xiao Ma6e2818b2020-06-22 01:18:22 +09002933
2934 final DhcpPacket packet =
2935 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpRequestPacket.class);
2936
2937 // Respond DHCPACK with IPv6-Only preferred option.
2938 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR,
2939 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, false /* rapidcommit */,
2940 null /* captivePortalUrl */, ipv6OnlyWaitTime));
2941
2942 if (ipv6OnlyWaitTime != null) {
2943 expectAlarmSet(null /* inOrder */, "TIMEOUT", expectedWaitSecs,
2944 mDependencies.mDhcpClient.getHandler());
2945 }
2946 }
2947
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002948 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002949 public void testRequestIPv6OnlyPreferredOption() throws Exception {
2950 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_IPV6_ONLY_WAIT_S,
2951 TEST_IPV6_ONLY_WAIT_S);
2952
2953 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2954 // IPv6-Only preferred option(default value) in the DHCPACK packet.
2955 assertIpMemoryNeverStoreNetworkAttributes();
2956 }
2957
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002958 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002959 public void testRequestIPv6OnlyPreferredOption_LowerIPv6OnlyWait() throws Exception {
2960 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_LOWER_IPV6_ONLY_WAIT_S,
2961 TEST_LOWER_IPV6_ONLY_WAIT_S);
2962
2963 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2964 // IPv6-Only preferred option(less than MIN_V6ONLY_WAIT_MS) in the DHCPACK packet.
2965 assertIpMemoryNeverStoreNetworkAttributes();
2966 }
2967
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002968 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002969 public void testRequestIPv6OnlyPreferredOption_ZeroIPv6OnlyWait() throws Exception {
2970 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_ZERO_IPV6_ONLY_WAIT_S,
2971 TEST_LOWER_IPV6_ONLY_WAIT_S);
2972
2973 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2974 // IPv6-Only preferred option(0) in the DHCPACK packet.
2975 assertIpMemoryNeverStoreNetworkAttributes();
2976 }
2977
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002978 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002979 public void testRequestIPv6OnlyPreferredOption_MaxIPv6OnlyWait() throws Exception {
2980 startFromInitRebootStateWithIPv6OnlyPreferredOption((int) TEST_MAX_IPV6_ONLY_WAIT_S,
2981 0xffffffffL);
2982
2983 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2984 // IPv6-Only preferred option(MAX_UNSIGNED_INTEGER: 0xFFFFFFFF) in the DHCPACK packet.
2985 assertIpMemoryNeverStoreNetworkAttributes();
2986 }
2987
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002988 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002989 public void testRequestIPv6OnlyPreferredOption_NoIPv6OnlyPreferredOption() throws Exception {
2990 final long currentTime = System.currentTimeMillis();
2991 startFromInitRebootStateWithIPv6OnlyPreferredOption(null /* ipv6OnlyWaitTime */,
2992 0 /* expectedWaitSecs */);
2993
2994 // Client processes DHCPACK packet normally and transits to the ConfiguringInterfaceState
2995 // due to the null V6ONLY_WAIT.
2996 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2997 }
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09002998
2999 private static int getNumOpenFds() {
3000 return new File("/proc/" + Os.getpid() + "/fd").listFiles().length;
3001 }
3002
3003 private void shutdownAndRecreateIpClient() throws Exception {
3004 mIpc.shutdown();
3005 awaitIpClientShutdown();
3006 mIpc = makeIpClient();
3007 }
3008
Remi NGUYEN VAN0dc6d222020-12-21 07:05:41 +00003009 @Test @SignatureRequiredTest(reason = "Only counts FDs from the current process. TODO: fix")
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09003010 public void testNoFdLeaks() throws Exception {
3011 // Shut down and restart IpClient once to ensure that any fds that are opened the first
3012 // time it runs do not cause the test to fail.
Xiao Ma690e12e2021-05-11 11:11:45 +00003013 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09003014 shutdownAndRecreateIpClient();
3015
3016 // Unfortunately we cannot use a large number of iterations as it would make the test run
3017 // too slowly. On crosshatch-eng each iteration takes ~250ms.
3018 final int iterations = 10;
3019 final int before = getNumOpenFds();
3020 for (int i = 0; i < iterations; i++) {
Xiao Ma690e12e2021-05-11 11:11:45 +00003021 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09003022 shutdownAndRecreateIpClient();
3023 // The last time this loop runs, mIpc will be shut down in tearDown.
3024 }
3025 final int after = getNumOpenFds();
3026
3027 // Check that the number of open fds is the same as before.
3028 // If this exact match becomes flaky, we could add some tolerance here (e.g., allow 2-3
3029 // extra fds), since it's likely that any leak would at least leak one FD per loop.
3030 assertEquals("Fd leak after " + iterations + " iterations: ", before, after);
3031 }
Xiao Mae31734e2020-12-10 21:09:26 +09003032
3033 // TODO: delete when DhcpOption is @JavaOnlyImmutable.
3034 private static DhcpOption makeDhcpOption(final byte type, final byte[] value) {
3035 final DhcpOption opt = new DhcpOption();
3036 opt.type = type;
3037 opt.value = value;
3038 return opt;
3039 }
3040
3041 private static final List<DhcpOption> TEST_OEM_DHCP_OPTIONS = Arrays.asList(
3042 // DHCP_USER_CLASS
3043 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3044 // DHCP_VENDOR_CLASS_ID
3045 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes())
3046 );
3047
3048 private DhcpPacket doCustomizedDhcpOptionsTest(final List<DhcpOption> options,
Xiao Ma4ca906c2021-01-30 12:09:41 +00003049 final ScanResultInfo info, boolean isDhcpLeaseCacheEnabled) throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003050 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
3051 .withoutIpReachabilityMonitor()
3052 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
3053 MacAddress.fromString(TEST_DEFAULT_BSSID)))
3054 .withScanResultInfo(info)
3055 .withDhcpOptions(options)
3056 .withoutIPv6();
3057
Xiao Ma4ca906c2021-01-30 12:09:41 +00003058 setDhcpFeatures(isDhcpLeaseCacheEnabled, false /* isRapidCommitEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00003059 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003060
3061 startIpClientProvisioning(prov.build());
3062 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
3063 verify(mCb, never()).onProvisioningFailure(any());
3064
3065 return getNextDhcpPacket();
3066 }
3067
3068 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003069 public void testDiscoverCustomizedDhcpOptions() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003070 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3071 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003072 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3073 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003074
3075 assertTrue(packet instanceof DhcpDiscoverPacket);
3076 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3077 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3078 }
3079
3080 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003081 public void testDiscoverCustomizedDhcpOptions_nullDhcpOptions() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003082 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3083 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003084 final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info,
3085 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003086
3087 assertTrue(packet instanceof DhcpDiscoverPacket);
3088 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3089 assertNull(packet.mUserClass);
3090 }
3091
3092 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003093 public void testDiscoverCustomizedDhcpOptions_nullScanResultInfo() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003094 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS,
Xiao Ma4ca906c2021-01-30 12:09:41 +00003095 null /* scanResultInfo */, false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003096
3097 assertTrue(packet instanceof DhcpDiscoverPacket);
3098 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3099 assertNull(packet.mUserClass);
3100 }
3101
3102 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003103 public void testDiscoverCustomizedDhcpOptions_disallowedOui() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003104 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */,
3105 new byte[]{ 0x00, 0x11, 0x22} /* oui */, (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003106 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3107 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003108
3109 assertTrue(packet instanceof DhcpDiscoverPacket);
3110 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3111 assertNull(packet.mUserClass);
3112 }
3113
3114 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003115 public void testDiscoverCustomizedDhcpOptions_invalidIeId() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003116 final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specificIE */, TEST_OEM_OUI,
3117 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003118 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3119 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003120
3121 assertTrue(packet instanceof DhcpDiscoverPacket);
3122 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3123 assertNull(packet.mUserClass);
3124 }
3125
3126 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003127 public void testDiscoverCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003128 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3129 (byte) 0x10 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003130 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3131 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003132
3133 assertTrue(packet instanceof DhcpDiscoverPacket);
3134 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3135 assertNull(packet.mUserClass);
3136 }
3137
3138 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003139 public void testDisoverCustomizedDhcpOptions_disallowedOption() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003140 final List<DhcpOption> options = Arrays.asList(
3141 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3142 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
Xiao Ma45676f02021-04-20 09:15:42 +00003143 // Option 26: MTU
3144 makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU)));
Xiao Mae31734e2020-12-10 21:09:26 +09003145 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3146 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003147 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3148 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003149
3150 assertTrue(packet instanceof DhcpDiscoverPacket);
3151 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3152 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
Xiao Ma45676f02021-04-20 09:15:42 +00003153 assertNull(packet.mMtu);
Xiao Mae31734e2020-12-10 21:09:26 +09003154 }
3155
3156 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003157 public void testDiscoverCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003158 final List<DhcpOption> options = Arrays.asList(
3159 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3160 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3161 // NTP_SERVER
3162 makeDhcpOption((byte) 42, null));
3163 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3164 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003165 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3166 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003167
3168 assertTrue(packet instanceof DhcpDiscoverPacket);
3169 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3170 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3171 assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */));
3172 }
Xiao Ma002dd5a2020-12-22 01:14:49 +00003173
Xiao Ma4ca906c2021-01-30 12:09:41 +00003174 @Test
3175 public void testDiscoverCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception {
3176 final List<DhcpOption> options = Arrays.asList(
3177 // DHCP_USER_CLASS
3178 makeDhcpOption((byte) 77, null));
3179 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3180 (byte) 0x17 /* vendor-specific IE type */);
3181 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3182 false /* isDhcpLeaseCacheEnabled */);
3183
3184 assertTrue(packet instanceof DhcpDiscoverPacket);
3185 assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */));
3186 assertNull(packet.mUserClass);
3187 }
3188
3189 @Test
3190 public void testRequestCustomizedDhcpOptions() throws Exception {
3191 setUpRetrievedNetworkAttributesForInitRebootState();
3192
3193 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3194 (byte) 0x17 /* vendor-specific IE type */);
3195 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3196 true /* isDhcpLeaseCacheEnabled */);
3197
3198 assertTrue(packet instanceof DhcpRequestPacket);
3199 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3200 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3201 }
3202
3203 @Test
3204 public void testRequestCustomizedDhcpOptions_nullDhcpOptions() throws Exception {
3205 setUpRetrievedNetworkAttributesForInitRebootState();
3206
3207 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3208 (byte) 0x17 /* vendor-specific IE type */);
3209 final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info,
3210 true /* isDhcpLeaseCacheEnabled */);
3211
3212 assertTrue(packet instanceof DhcpRequestPacket);
3213 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3214 assertNull(packet.mUserClass);
3215 }
3216
3217 @Test
3218 public void testRequestCustomizedDhcpOptions_nullScanResultInfo() throws Exception {
3219 setUpRetrievedNetworkAttributesForInitRebootState();
3220
3221 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS,
3222 null /* scanResultInfo */, true /* isDhcpLeaseCacheEnabled */);
3223
3224 assertTrue(packet instanceof DhcpRequestPacket);
3225 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3226 assertNull(packet.mUserClass);
3227 }
3228
3229 @Test
3230 public void testRequestCustomizedDhcpOptions_disallowedOui() throws Exception {
3231 setUpRetrievedNetworkAttributesForInitRebootState();
3232
3233 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */,
3234 new byte[]{ 0x00, 0x11, 0x22} /* oui */, (byte) 0x17 /* vendor-specific IE type */);
3235 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3236 true /* isDhcpLeaseCacheEnabled */);
3237
3238 assertTrue(packet instanceof DhcpRequestPacket);
3239 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3240 assertNull(packet.mUserClass);
3241 }
3242
3243 @Test
3244 public void testRequestCustomizedDhcpOptions_invalidIeId() throws Exception {
3245 setUpRetrievedNetworkAttributesForInitRebootState();
3246
3247 final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specificIE */, TEST_OEM_OUI,
3248 (byte) 0x17 /* vendor-specific IE type */);
3249 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3250 true /* isDhcpLeaseCacheEnabled */);
3251
3252 assertTrue(packet instanceof DhcpRequestPacket);
3253 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3254 assertNull(packet.mUserClass);
3255 }
3256
3257 @Test
3258 public void testRequestCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception {
3259 setUpRetrievedNetworkAttributesForInitRebootState();
3260
3261 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3262 (byte) 0x10 /* vendor-specific IE type */);
3263 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3264 true /* isDhcpLeaseCacheEnabled */);
3265
3266 assertTrue(packet instanceof DhcpRequestPacket);
3267 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3268 assertNull(packet.mUserClass);
3269 }
3270
3271 @Test
3272 public void testRequestCustomizedDhcpOptions_disallowedOption() throws Exception {
3273 setUpRetrievedNetworkAttributesForInitRebootState();
3274
3275 final List<DhcpOption> options = Arrays.asList(
3276 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3277 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3278 // Option 26: MTU
3279 makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU)));
3280 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3281 (byte) 0x17 /* vendor-specific IE type */);
3282 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3283 true /* isDhcpLeaseCacheEnabled */);
3284
3285 assertTrue(packet instanceof DhcpRequestPacket);
3286 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3287 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3288 assertNull(packet.mMtu);
3289 }
3290
3291 @Test
3292 public void testRequestCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception {
3293 setUpRetrievedNetworkAttributesForInitRebootState();
3294
3295 final List<DhcpOption> options = Arrays.asList(
3296 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3297 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3298 // NTP_SERVER
3299 makeDhcpOption((byte) 42, null));
3300 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3301 (byte) 0x17 /* vendor-specific IE type */);
3302 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3303 true /* isDhcpLeaseCacheEnabled */);
3304
3305 assertTrue(packet instanceof DhcpRequestPacket);
3306 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3307 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3308 assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */));
3309 }
3310
3311 @Test
3312 public void testRequestCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception {
3313 setUpRetrievedNetworkAttributesForInitRebootState();
3314
3315 final List<DhcpOption> options = Arrays.asList(
3316 // DHCP_USER_CLASS
3317 makeDhcpOption((byte) 77, null));
3318 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3319 (byte) 0x17 /* vendor-specific IE type */);
3320 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3321 true /* isDhcpLeaseCacheEnabled */);
3322
3323 assertTrue(packet instanceof DhcpRequestPacket);
3324 assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */));
3325 assertNull(packet.mUserClass);
3326 }
3327
Xiao Ma002dd5a2020-12-22 01:14:49 +00003328 private void assertGratuitousNa(final NeighborAdvertisement na) throws Exception {
3329 final MacAddress etherMulticast =
3330 NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST);
3331 final LinkAddress target = new LinkAddress(na.naHdr.target, 64);
3332
3333 assertEquals(etherMulticast, na.ethHdr.dstMac);
3334 assertEquals(ETH_P_IPV6, na.ethHdr.etherType);
3335 assertEquals(IPPROTO_ICMPV6, na.ipv6Hdr.nextHeader);
3336 assertEquals(0xff, na.ipv6Hdr.hopLimit);
3337 assertTrue(na.ipv6Hdr.srcIp.isLinkLocalAddress());
3338 assertEquals(IPV6_ADDR_ALL_ROUTERS_MULTICAST, na.ipv6Hdr.dstIp);
3339 assertEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, na.icmpv6Hdr.type);
3340 assertEquals(0, na.icmpv6Hdr.code);
3341 assertEquals(0, na.naHdr.flags);
3342 assertTrue(target.isGlobalPreferred());
3343 }
3344
3345 @Test
Xiao Ma8a0b7672021-04-19 08:33:29 +00003346 public void testGratuitousNaForNewGlobalUnicastAddresses() throws Exception {
Xiao Ma002dd5a2020-12-22 01:14:49 +00003347 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3348 .withoutIpReachabilityMonitor()
3349 .withoutIPv4()
3350 .build();
3351
3352 setFeatureEnabled(NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION,
3353 true /* isGratuitousNaEnabled */);
3354 assertTrue(isFeatureEnabled(NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION, false));
3355 startIpClientProvisioning(config);
3356
Xiao Ma8a0b7672021-04-19 08:33:29 +00003357 doIpv6OnlyProvisioning();
Xiao Ma002dd5a2020-12-22 01:14:49 +00003358
3359 final List<NeighborAdvertisement> naList = new ArrayList<>();
3360 NeighborAdvertisement packet;
3361 while ((packet = getNextNeighborAdvertisement()) != null) {
3362 assertGratuitousNa(packet);
3363 naList.add(packet);
3364 }
3365 assertEquals(2, naList.size()); // privacy address and stable privacy address
3366 }
Xiao Ma8a0b7672021-04-19 08:33:29 +00003367
3368 private void startGratuitousArpAndNaAfterRoamingTest(boolean isGratuitousArpNaRoamingEnabled,
3369 boolean hasIpv4, boolean hasIpv6) throws Exception {
Xiao Ma861fe422021-04-16 03:03:03 +00003370 final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
3371 MacAddress.fromString(TEST_DEFAULT_BSSID));
Xiao Ma8a0b7672021-04-19 08:33:29 +00003372 final ScanResultInfo scanResultInfo =
3373 makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID);
3374 final ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
3375 .withoutIpReachabilityMonitor()
Xiao Ma861fe422021-04-16 03:03:03 +00003376 .withLayer2Information(layer2Info)
Xiao Ma8a0b7672021-04-19 08:33:29 +00003377 .withScanResultInfo(scanResultInfo)
3378 .withDisplayName("ssid");
3379 if (!hasIpv4) prov.withoutIPv4();
3380 if (!hasIpv6) prov.withoutIPv6();
3381
3382 // Enable rapid commit to accelerate DHCP handshake to shorten test duration,
3383 // not strictly necessary.
3384 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
3385 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
3386 if (isGratuitousArpNaRoamingEnabled) {
3387 setFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, true);
3388 assertTrue(isFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, false));
3389 }
3390 startIpClientProvisioning(prov.build());
3391 }
3392
3393 private void waitForGratuitousArpAndNaPacket(final List<ArpPacket> arpList,
3394 final List<NeighborAdvertisement> naList) throws Exception {
3395 NeighborAdvertisement na;
3396 ArpPacket garp;
3397 do {
3398 na = getNextNeighborAdvertisement();
3399 if (na != null) {
3400 assertGratuitousNa(na);
3401 naList.add(na);
3402 }
3403 garp = getNextArpPacket(TEST_TIMEOUT_MS);
3404 if (garp != null) {
3405 assertGratuitousARP(garp);
3406 arpList.add(garp);
3407 }
3408 } while (na != null || garp != null);
3409 }
3410
3411 @Test
3412 public void testGratuitousArpAndNaAfterRoaming() throws Exception {
3413 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
3414 true /* hasIpv4 */, true /* hasIpv6 */);
3415 performDualStackProvisioning();
3416 forceLayer2Roaming();
3417
3418 final List<ArpPacket> arpList = new ArrayList<>();
3419 final List<NeighborAdvertisement> naList = new ArrayList<>();
3420 waitForGratuitousArpAndNaPacket(arpList, naList);
3421 assertEquals(2, naList.size()); // privacy address and stable privacy address
3422 assertEquals(1, arpList.size()); // IPv4 address
3423 }
3424
3425 @Test
3426 public void testGratuitousArpAndNaAfterRoaming_disableExpFlag() throws Exception {
3427 startGratuitousArpAndNaAfterRoamingTest(false /* isGratuitousArpNaRoamingEnabled */,
Xiao Ma60175d22021-06-02 12:28:40 +00003428 true /* hasIpv4 */, true /* hasIpv6 */);
Xiao Ma8a0b7672021-04-19 08:33:29 +00003429 performDualStackProvisioning();
3430 forceLayer2Roaming();
3431
3432 final List<ArpPacket> arpList = new ArrayList<>();
3433 final List<NeighborAdvertisement> naList = new ArrayList<>();
3434 waitForGratuitousArpAndNaPacket(arpList, naList);
3435 assertEquals(0, naList.size());
3436 assertEquals(0, arpList.size());
3437 }
3438
3439 @Test
3440 public void testGratuitousArpAndNaAfterRoaming_IPv6OnlyNetwork() throws Exception {
3441 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
3442 false /* hasIpv4 */, true /* hasIpv6 */);
3443 doIpv6OnlyProvisioning();
3444 forceLayer2Roaming();
3445
3446 final List<ArpPacket> arpList = new ArrayList<>();
3447 final List<NeighborAdvertisement> naList = new ArrayList<>();
3448 waitForGratuitousArpAndNaPacket(arpList, naList);
3449 assertEquals(2, naList.size());
3450 assertEquals(0, arpList.size());
3451 }
3452
3453 @Test
3454 public void testGratuitousArpAndNaAfterRoaming_IPv4OnlyNetwork() throws Exception {
3455 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
3456 true /* hasIpv4 */, false /* hasIpv6 */);
3457
3458 // Start IPv4 provisioning and wait until entire provisioning completes.
3459 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
3460 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */);
3461 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
3462 forceLayer2Roaming();
3463
3464 final List<ArpPacket> arpList = new ArrayList<>();
3465 final List<NeighborAdvertisement> naList = new ArrayList<>();
3466 waitForGratuitousArpAndNaPacket(arpList, naList);
3467 assertEquals(0, naList.size());
3468 assertEquals(1, arpList.size());
3469 }
Xiao Ma60175d22021-06-02 12:28:40 +00003470
3471 private void assertNeighborSolicitation(final NeighborSolicitation ns,
3472 final Inet6Address target) {
3473 assertEquals(ETH_P_IPV6, ns.ethHdr.etherType);
3474 assertEquals(IPPROTO_ICMPV6, ns.ipv6Hdr.nextHeader);
3475 assertEquals(0xff, ns.ipv6Hdr.hopLimit);
3476 assertTrue(ns.ipv6Hdr.srcIp.isLinkLocalAddress());
3477 assertEquals(ICMPV6_NEIGHBOR_SOLICITATION, ns.icmpv6Hdr.type);
3478 assertEquals(0, ns.icmpv6Hdr.code);
3479 assertEquals(0, ns.nsHdr.reserved);
3480 assertEquals(target, ns.nsHdr.target);
3481 assertEquals(ns.slla.linkLayerAddress, ns.ethHdr.srcMac);
3482 }
3483
3484 private void assertUnicastNeighborSolicitation(final NeighborSolicitation ns,
3485 final MacAddress dstMac, final Inet6Address dstIp, final Inet6Address target) {
3486 assertEquals(dstMac, ns.ethHdr.dstMac);
3487 assertEquals(dstIp, ns.ipv6Hdr.dstIp);
3488 assertNeighborSolicitation(ns, target);
3489 }
3490
Xiao Ma69a936a2021-04-21 08:14:44 +00003491 private void assertMulticastNeighborSolicitation(final NeighborSolicitation ns,
3492 final Inet6Address target) {
3493 final MacAddress etherMulticast =
3494 NetworkStackUtils.ipv6MulticastToEthernetMulticast(ns.ipv6Hdr.dstIp);
3495 assertEquals(etherMulticast, ns.ethHdr.dstMac);
3496 assertTrue(ns.ipv6Hdr.dstIp.isMulticastAddress());
3497 assertNeighborSolicitation(ns, target);
3498 }
3499
3500 private NeighborSolicitation waitForUnicastNeighborSolicitation(final MacAddress dstMac,
3501 final Inet6Address dstIp, final Inet6Address targetIp) throws Exception {
3502 NeighborSolicitation ns;
3503 while ((ns = getNextNeighborSolicitation()) != null) {
3504 // Filter out the NSes used for duplicate address detetction, the target address
3505 // is the global IPv6 address inside these NSes.
3506 if (ns.nsHdr.target.isLinkLocalAddress()) break;
3507 }
3508 assertNotNull("No unicast Neighbor solicitation received on interface within timeout", ns);
3509 assertUnicastNeighborSolicitation(ns, dstMac, dstIp, targetIp);
3510 return ns;
3511 }
3512
3513 private List<NeighborSolicitation> waitForMultipleNeighborSolicitations() throws Exception {
3514 NeighborSolicitation ns;
3515 final List<NeighborSolicitation> nsList = new ArrayList<NeighborSolicitation>();
3516 while ((ns = getNextNeighborSolicitation()) != null) {
3517 // Filter out the NSes used for duplicate address detetction, the target address
3518 // is the global IPv6 address inside these NSes.
3519 if (ns.nsHdr.target.isLinkLocalAddress()) {
3520 nsList.add(ns);
3521 }
3522 }
3523 assertFalse(nsList.isEmpty());
3524 return nsList;
3525 }
3526
3527 // Override this function with disabled experiment flag by default, in order not to
3528 // affect those tests which are just related to basic IpReachabilityMonitor infra.
Xiao Ma60175d22021-06-02 12:28:40 +00003529 private void prepareIpReachabilityMonitorTest() throws Exception {
Xiao Ma69a936a2021-04-21 08:14:44 +00003530 prepareIpReachabilityMonitorTest(false /* isMulticastResolicitEnabled */);
3531 }
3532
Xiao Ma374387c2021-11-02 02:25:55 +00003533 private void assertNotifyNeighborLost(Inet6Address targetIp, NudEventType eventType)
3534 throws Exception {
3535 // For root test suite, rely on the IIpClient aidl interface version constant defined in
3536 // {@link IpClientRootTest.BinderCbWrapper}; for privileged integration test suite that
3537 // requires signature permission, use the mocked aidl version defined in {@link setUpMocks},
3538 // which results in only new callbacks are verified. And add separate test cases to test the
3539 // legacy callbacks explicitly as well.
3540 assertNeighborReachabilityLoss(targetIp, eventType,
3541 useNetworkStackSignature()
3542 ? IpClient.VERSION_ADDED_REACHABILITY_FAILURE
3543 : mIIpClient.getInterfaceVersion());
3544 }
3545
3546 private void assertNeighborReachabilityLoss(Inet6Address targetIp, NudEventType eventType,
3547 int targetAidlVersion) throws Exception {
3548 if (targetAidlVersion >= IpClient.VERSION_ADDED_REACHABILITY_FAILURE) {
3549 final ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor =
3550 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class);
3551 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityFailure(lossInfoCaptor.capture());
3552 assertEquals(nudEventTypeToInt(eventType), lossInfoCaptor.getValue().reason);
3553 verify(mCb, never()).onReachabilityLost(any());
3554 } else {
3555 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any());
3556 verify(mCb, never()).onReachabilityFailure(any());
3557 }
3558 }
3559
3560 private void assertNeverNotifyNeighborLost() throws Exception {
3561 verify(mCb, never()).onReachabilityFailure(any());
3562 verify(mCb, never()).onReachabilityLost(any());
3563 }
3564
Xiao Ma69a936a2021-04-21 08:14:44 +00003565 private void prepareIpReachabilityMonitorTest(boolean isMulticastResolicitEnabled)
3566 throws Exception {
Xiao Ma60175d22021-06-02 12:28:40 +00003567 final ScanResultInfo info = makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID);
3568 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3569 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
3570 MacAddress.fromString(TEST_DEFAULT_BSSID)))
3571 .withScanResultInfo(info)
3572 .withDisplayName(TEST_DEFAULT_SSID)
3573 .withoutIPv4()
3574 .build();
Xiao Ma69a936a2021-04-21 08:14:44 +00003575 setFeatureEnabled(NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION,
3576 isMulticastResolicitEnabled);
Xiao Ma60175d22021-06-02 12:28:40 +00003577 startIpClientProvisioning(config);
3578 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
3579 doIpv6OnlyProvisioning();
3580
3581 // Simulate the roaming.
3582 forceLayer2Roaming();
3583 }
3584
Xiao Ma374387c2021-11-02 02:25:55 +00003585 private void runIpReachabilityMonitorProbeFailedTest() throws Exception {
Xiao Ma60175d22021-06-02 12:28:40 +00003586 prepareIpReachabilityMonitorTest();
3587
Xiao Ma69a936a2021-04-21 08:14:44 +00003588 final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations();
3589 assertEquals(MIN_NUD_SOLICIT_NUM, nsList.size());
Xiao Ma60175d22021-06-02 12:28:40 +00003590 for (NeighborSolicitation ns : nsList) {
3591 assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
3592 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3593 }
Xiao Ma374387c2021-11-02 02:25:55 +00003594 }
3595
3596 @Test
3597 public void testIpReachabilityMonitor_probeFailed() throws Exception {
3598 runIpReachabilityMonitorProbeFailedTest();
3599 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */,
3600 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL);
3601 }
3602
3603 @Test @SignatureRequiredTest(reason = "requires mock callback object")
3604 public void testIpReachabilityMonitor_probeFailed_legacyCallback() throws Exception {
3605 when(mCb.getInterfaceVersion()).thenReturn(12 /* assign an older interface aidl version */);
3606
3607 runIpReachabilityMonitorProbeFailedTest();
3608 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any());
3609 verify(mCb, never()).onReachabilityFailure(any());
Xiao Ma60175d22021-06-02 12:28:40 +00003610 }
3611
3612 @Test
3613 public void testIpReachabilityMonitor_probeReachable() throws Exception {
3614 prepareIpReachabilityMonitorTest();
3615
Xiao Ma69a936a2021-04-21 08:14:44 +00003616 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
Xiao Ma60175d22021-06-02 12:28:40 +00003617 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3618
3619 // Reply Neighbor Advertisement and check notifyLost callback won't be triggered.
3620 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
3621 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */,
3622 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
3623 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
3624 mPacketReader.sendResponse(na);
3625 assertNeverNotifyNeighborLost();
3626 }
Xiao Ma69a936a2021-04-21 08:14:44 +00003627
Xiao Ma374387c2021-11-02 02:25:55 +00003628 private void runIpReachabilityMonitorMcastResolicitProbeFailedTest() throws Exception {
Xiao Ma69a936a2021-04-21 08:14:44 +00003629 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
3630
3631 final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations();
3632 int expectedSize = MIN_NUD_SOLICIT_NUM + NUD_MCAST_RESOLICIT_NUM;
3633 assertEquals(expectedSize, nsList.size()); // 5 unicast NSes + 3 multicast NSes
3634 for (NeighborSolicitation ns : nsList.subList(0, MIN_NUD_SOLICIT_NUM)) {
3635 assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
3636 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3637 }
3638 for (NeighborSolicitation ns : nsList.subList(MIN_NUD_SOLICIT_NUM, nsList.size())) {
3639 assertMulticastNeighborSolicitation(ns, ROUTER_LINK_LOCAL /* targetIp */);
3640 }
Xiao Ma69a936a2021-04-21 08:14:44 +00003641 }
3642
3643 @Test
Xiao Ma374387c2021-11-02 02:25:55 +00003644 public void testIpReachabilityMonitor_mcastResolicitProbeFailed() throws Exception {
3645 runIpReachabilityMonitorMcastResolicitProbeFailedTest();
3646 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */,
3647 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL);
3648 }
3649
3650 @Test @SignatureRequiredTest(reason = "requires mock callback object")
3651 public void testIpReachabilityMonitor_mcastResolicitProbeFailed_legacyCallback()
3652 throws Exception {
3653 when(mCb.getInterfaceVersion()).thenReturn(12 /* assign an older interface aidl version */);
3654
3655 runIpReachabilityMonitorMcastResolicitProbeFailedTest();
3656 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any());
3657 verify(mCb, never()).onReachabilityFailure(any());
3658 }
3659
3660 @Test
3661 public void testIpReachabilityMonitor_mcastResolicitProbeReachableWithSameLinkLayerAddress()
Xiao Ma69a936a2021-04-21 08:14:44 +00003662 throws Exception {
3663 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
3664
3665 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
3666 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3667
3668 // Reply Neighbor Advertisement and check notifyLost callback won't be triggered.
3669 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
3670 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */,
3671 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
3672 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
3673 mPacketReader.sendResponse(na);
3674 assertNeverNotifyNeighborLost();
3675 }
3676
3677 @Test
Xiao Ma374387c2021-11-02 02:25:55 +00003678 public void testIpReachabilityMonitor_mcastResolicitProbeReachableWithDiffLinkLayerAddress()
Xiao Ma69a936a2021-04-21 08:14:44 +00003679 throws Exception {
3680 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
3681
3682 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
3683 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3684
3685 // Reply Neighbor Advertisement with a different link-layer address and check notifyLost
3686 // callback will be triggered. Override flag must be set, which indicates that the
3687 // advertisement should override an existing cache entry and update the cached link-layer
3688 // address, otherwise, kernel won't transit to REACHABLE state with a different link-layer
3689 // address.
3690 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
3691 | NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE;
3692 final MacAddress newMac = MacAddress.fromString("00:1a:11:22:33:55");
3693 final ByteBuffer na = NeighborAdvertisement.build(newMac /* srcMac */,
3694 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
3695 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
3696 mPacketReader.sendResponse(na);
Xiao Ma374387c2021-11-02 02:25:55 +00003697 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */,
3698 NudEventType.NUD_POST_ROAMING_MAC_ADDRESS_CHANGED);
Xiao Ma69a936a2021-04-21 08:14:44 +00003699 }
Xiao Ma326820d2020-11-24 16:21:04 +09003700
3701 @Test
3702 public void testIPv6LinkLocalOnly() throws Exception {
3703 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3704 .withoutIPv4()
3705 .withIpv6LinkLocalOnly()
3706 .withRandomMacAddress()
3707 .build();
3708 startIpClientProvisioning(config);
3709
3710 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
3711 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
3712 final LinkProperties lp = captor.getValue();
3713 assertNotNull(lp);
3714 assertEquals(0, lp.getDnsServers().size());
3715 final List<LinkAddress> addresses = lp.getLinkAddresses();
3716 assertEquals(1, addresses.size());
3717 assertTrue(addresses.get(0).getAddress().isLinkLocalAddress());
3718 assertEquals(1, lp.getRoutes().size());
3719 final RouteInfo route = lp.getRoutes().get(0);
3720 assertNotNull(route);
3721 assertTrue(route.getDestination().equals(new IpPrefix("fe80::/64")));
3722 assertTrue(route.getGateway().isAnyLocalAddress());
Lorenzo Colitti8b93f292021-10-12 16:58:56 +09003723
3724 // Check that if an RA is received, no IP addresses, routes, or DNS servers are configured.
3725 // Instead of waiting some period of time for the RA to be received and checking the
3726 // LinkProperties after that, tear down the interface and wait for it to go down. Then check
3727 // that no LinkProperties updates ever contained non-link-local information.
3728 sendBasicRouterAdvertisement(false /* waitForRs */);
3729 teardownTapInterface();
3730 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
3731 verify(mCb, never()).onLinkPropertiesChange(argThat(newLp ->
3732 newLp.getDnsServers().size() != 0
3733 || newLp.getRoutes().size() > 1
3734 || newLp.hasIpv6DefaultRoute()
3735 || newLp.hasGlobalIpv6Address()
3736 ));
3737 }
3738
3739 @Test
3740 public void testIPv6LinkLocalOnlyAndThenGlobal() throws Exception {
3741 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3742 .withoutIPv4()
3743 .withIpv6LinkLocalOnly()
3744 .withRandomMacAddress()
3745 .build();
3746 startIpClientProvisioning(config);
3747 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any());
3748 mIIpClient.stop();
3749 verifyAfterIpClientShutdown();
3750 reset(mCb);
3751
3752 // Speed up provisioning by enabling rapid commit. TODO: why is this necessary?
3753 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
3754 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
3755 config = new ProvisioningConfiguration.Builder()
3756 .build();
3757 startIpClientProvisioning(config);
3758 performDualStackProvisioning();
3759 // No exceptions? Dual-stack provisioning worked.
Xiao Ma326820d2020-11-24 16:21:04 +09003760 }
3761
3762 @Test
3763 public void testIPv6LinkLocalOnly_enableBothIPv4andIPv6LinkLocalOnly() throws Exception {
3764 assertThrows(IllegalArgumentException.class,
3765 () -> new ProvisioningConfiguration.Builder()
3766 .withoutIpReachabilityMonitor()
3767 .withIpv6LinkLocalOnly()
3768 .withRandomMacAddress()
3769 .build()
3770 );
3771 }
Xiao Maac371ef2021-09-15 03:37:41 +00003772
3773 @Test
3774 public void testIpClientLinkObserver_onClatInterfaceStateUpdate() throws Exception {
3775 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3776 .withoutIPv4()
3777 .build();
3778 startIpClientProvisioning(config);
3779 doIpv6OnlyProvisioning();
3780
3781 reset(mCb);
3782
3783 // Add the clat interface and check the callback.
3784 final TestNetworkInterface clatIface = setUpClatInterface(mIfaceName);
3785 assertNotNull(clatIface);
3786 assertTrue(clatIface.getInterfaceName().equals(CLAT_PREFIX + mIfaceName));
3787 verify(mCb, timeout(TEST_TIMEOUT_MS)).setNeighborDiscoveryOffload(false);
3788
3789 // Remove the clat interface and check the callback.
3790 removeTestInterface(clatIface.getFileDescriptor().getFileDescriptor());
3791 verify(mCb, timeout(TEST_TIMEOUT_MS)).setNeighborDiscoveryOffload(true);
3792 }
Xiao Mad83a6a82022-06-09 14:39:25 +09003793
3794 @Test @SignatureRequiredTest(reason = "requires mock callback object")
3795 public void testNetlinkSocketReceiveENOBUFS() throws Exception {
3796 if (!mIsNetlinkEventParseEnabled) return;
3797
3798 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3799 .withoutIPv4()
3800 .build();
3801 startIpClientProvisioning(config);
3802 doIpv6OnlyProvisioning();
3803 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
3804
3805 // Block IpClient handler.
3806 final CountDownLatch latch = new CountDownLatch(1);
3807 mIpc.getHandler().post(() -> {
3808 try {
3809 latch.await(10_000L /* 10s */, TimeUnit.MILLISECONDS);
3810 } catch (InterruptedException e) {
3811 // do nothing
3812 }
3813 });
3814
3815 // Send large amount of RAs to overflow the netlink socket receive buffer.
3816 for (int i = 0; i < 100; i++) {
3817 sendBasicRouterAdvertisement(false /* waitRs */);
3818 }
3819
3820 // Unblock the IpClient handler.
3821 latch.countDown();
3822 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
3823
3824 reset(mCb);
3825
3826 // Send RA with 0 router lifetime to see if IpClient can see the loss of IPv6 default route.
Xiao Ma148f5742022-06-06 11:20:33 +09003827 // Due to ignoring the ENOBUFS and wait until handler gets idle, IpClient should be still
3828 // able to see the RA with 0 router lifetime and the IPv6 default route will be removed.
Xiao Mad83a6a82022-06-09 14:39:25 +09003829 sendRouterAdvertisementWithZeroLifetime();
Xiao Ma148f5742022-06-06 11:20:33 +09003830 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
3831 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
3832 final LinkProperties lp = captor.getValue();
3833 assertFalse(lp.hasIpv6DefaultRoute());
Xiao Mad83a6a82022-06-09 14:39:25 +09003834 }
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09003835}