blob: 2f3987cebfa70fc318bf33f2702acdeb9dfa5267 [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;
Xiao Mad1c55452022-06-10 09:10:13 +0900189import org.junit.Ignore;
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +0900190import org.junit.Rule;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900191import org.junit.Test;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900192import org.junit.rules.TestName;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900193import org.junit.runner.RunWith;
Xiao Ma93533832021-09-13 04:14:33 +0000194import org.junit.runners.Parameterized;
Xiao Mac00a7932019-06-03 10:30:04 +0900195import org.mockito.ArgumentCaptor;
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +0900196import org.mockito.InOrder;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900197import org.mockito.Mock;
198import org.mockito.MockitoAnnotations;
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900199import org.mockito.Spy;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900200
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900201import java.io.BufferedReader;
Lorenzo Colitti675e0f52020-08-18 22:13:24 +0900202import java.io.File;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900203import java.io.FileDescriptor;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900204import java.io.FileReader;
Xiao Mac00a7932019-06-03 10:30:04 +0900205import java.io.IOException;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900206import java.lang.annotation.ElementType;
207import java.lang.annotation.Retention;
208import java.lang.annotation.RetentionPolicy;
209import java.lang.annotation.Target;
210import java.lang.reflect.Method;
Xiao Mac00a7932019-06-03 10:30:04 +0900211import java.net.Inet4Address;
Xiao Maaf321442021-02-05 09:04:42 +0000212import java.net.Inet6Address;
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +0900213import java.net.InetAddress;
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900214import java.net.NetworkInterface;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900215import java.nio.ByteBuffer;
Xiao Ma7d733952019-07-02 18:55:11 +0900216import java.util.ArrayList;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900217import java.util.Arrays;
Xiao Ma16b21ef2020-01-22 17:51:26 +0900218import java.util.Collection;
Xiao Mac00a7932019-06-03 10:30:04 +0900219import java.util.Collections;
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900220import java.util.HashMap;
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900221import java.util.List;
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +0900222import java.util.Objects;
Xiao Ma562d2422019-12-16 13:20:59 +0900223import java.util.Random;
Xiao Ma4edc4f62020-05-21 10:32:47 +0900224import java.util.concurrent.CompletableFuture;
Lorenzo Colitti58da4e32020-04-24 21:57:22 +0900225import java.util.concurrent.CountDownLatch;
226import java.util.concurrent.TimeUnit;
Lorenzo Colitti5e384442020-04-26 20:18:04 +0900227import java.util.concurrent.atomic.AtomicReference;
228import java.util.function.Predicate;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900229
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900230import kotlin.Lazy;
231import kotlin.LazyKt;
232
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900233/**
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900234 * Base class for IpClient tests.
235 *
236 * Tests in this class can either be run with signature permissions, or with root access.
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900237 */
Xiao Ma93533832021-09-13 04:14:33 +0000238@RunWith(Parameterized.class)
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900239@SmallTest
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900240public abstract class IpClientIntegrationTestCommon {
Xiao Mac00a7932019-06-03 10:30:04 +0900241 private static final int DATA_BUFFER_LEN = 4096;
242 private static final int PACKET_TIMEOUT_MS = 5_000;
Chalard Jeanb2896832020-05-13 19:16:49 +0900243 private static final String TEST_CLUSTER = "some cluster";
Xiao Mac00a7932019-06-03 10:30:04 +0900244 private static final int TEST_LEASE_DURATION_S = 3_600; // 1 hour
Xiao Ma6e2818b2020-06-22 01:18:22 +0900245 private static final int TEST_IPV6_ONLY_WAIT_S = 1_800; // 30 min
246 private static final int TEST_LOWER_IPV6_ONLY_WAIT_S = (int) (MIN_V6ONLY_WAIT_MS / 1000 - 1);
247 private static final int TEST_ZERO_IPV6_ONLY_WAIT_S = 0;
248 private static final long TEST_MAX_IPV6_ONLY_WAIT_S = 0xffffffffL;
Xiao Ma927a8912021-01-07 08:05:02 +0000249 protected static final String TEST_L2KEY = "some l2key";
Xiao Mac00a7932019-06-03 10:30:04 +0900250
Lorenzo Colitti558eb962020-04-27 11:43:23 +0900251 // TODO: move to NetlinkConstants, NetworkStackConstants, or OsConstants.
252 private static final int IFA_F_STABLE_PRIVACY = 0x800;
253
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900254 protected static final long TEST_TIMEOUT_MS = 2_000L;
255
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +0900256 @Rule
257 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900258 @Rule
259 public final TestName mTestNameRule = new TestName();
260
Xiao Ma93533832021-09-13 04:14:33 +0000261 // Indicate whether the flag of parsing netlink event is enabled or not. If it's disabled,
262 // integration test still covers the old codepath(i.e. using NetworkObserver), otherwise,
263 // test goes through the new codepath(i.e. processRtNetlinkxxx).
264 @Parameterized.Parameter(0)
265 public boolean mIsNetlinkEventParseEnabled;
266
267 @Parameterized.Parameters
268 public static Iterable<? extends Object> data() {
Xiao Maebc22a82021-08-13 06:34:39 +0000269 return Arrays.asList(Boolean.FALSE, Boolean.TRUE);
Xiao Ma93533832021-09-13 04:14:33 +0000270 }
271
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900272 /**
273 * Indicates that a test requires signature permissions to run.
274 *
275 * Such tests can only be run on devices that use known signing keys, so this annotation must be
276 * avoided as much as possible. Consider whether the test can be written to use shell and root
277 * shell permissions, and run against the NetworkStack AIDL interface (IIpClient) instead.
278 */
279 @Retention(RetentionPolicy.RUNTIME)
280 @Target({ElementType.METHOD})
281 private @interface SignatureRequiredTest {
282 String reason();
283 }
284
285 /**** BEGIN signature required test members ****/
286 // Do not use unless the test *really* cannot be written to exercise IIpClient without mocks.
287 // Tests using the below members must be annotated with @SignatureRequiredTest (otherwise the
288 // members will be null), and can only be run on devices that use known signing keys.
289 // The members could technically be moved to the IpClientIntegrationTest subclass together with
290 // the tests requiring signature permissions, but this would make it harder to follow tests in
291 // multiple classes, and harder to migrate tests between signature required and not required.
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +0900292
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900293 @Mock private Context mContext;
294 @Mock private ConnectivityManager mCm;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900295 @Mock private Resources mResources;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900296 @Mock private AlarmManager mAlarm;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900297 @Mock private ContentResolver mContentResolver;
Xiao Mac00a7932019-06-03 10:30:04 +0900298 @Mock private NetworkStackServiceManager mNetworkStackServiceManager;
Xiao Mac00a7932019-06-03 10:30:04 +0900299 @Mock private IpMemoryStoreService mIpMemoryStoreService;
Xiao Ma7d733952019-07-02 18:55:11 +0900300 @Mock private PowerManager.WakeLock mTimeoutWakeLock;
Xiao Ma927a8912021-01-07 08:05:02 +0000301 @Mock protected NetworkStackIpMemoryStore mIpMemoryStore;
lifrf9105de2021-05-06 15:31:04 +0800302 @Mock private NetworkQuirkMetrics.Dependencies mNetworkQuirkMetricsDeps;
Xiao Mad9d3bcc2020-12-14 01:25:50 +0000303 @Mock private IpReachabilityMonitorMetrics mIpReachabilityMonitorMetrics;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900304
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900305 @Spy private INetd mNetd;
Lorenzo Colitti58da4e32020-04-24 21:57:22 +0900306 private NetworkObserverRegistry mNetworkObserverRegistry;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900307
308 protected IpClient mIpc;
309 protected Dependencies mDependencies;
310
311 /***** END signature required test members *****/
312
Xiao Ma60175d22021-06-02 12:28:40 +0000313 protected IIpClientCallbacks mCb;
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900314 private IIpClient mIIpClient;
315 private String mIfaceName;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900316 private HandlerThread mPacketReaderThread;
Xiao Mac66d5d02019-09-03 10:41:58 +0900317 private Handler mHandler;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900318 private TapPacketReader mPacketReader;
Lorenzo Colitti32215002020-03-13 19:40:32 +0900319 private FileDescriptor mTapFd;
Xiao Ma7d733952019-07-02 18:55:11 +0900320 private byte[] mClientMac;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900321
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900322 private boolean mIsSignatureRequiredTest;
323
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900324 // ReadHeads for various packet streams. Cannot be initialized in @Before because ReadHead is
325 // single-thread-only, and AndroidJUnitRunner runs @Before and @Test on different threads.
326 // While it looks like these are created only once per test, they are actually created once per
327 // test method because JUnit recreates a fresh test class instance before every test method.
328 private Lazy<ArrayTrackRecord<byte[]>.ReadHead> mDhcpPacketReadHead =
329 LazyKt.lazy(() -> mPacketReader.getReceivedPackets().newReadHead());
330 private Lazy<ArrayTrackRecord<byte[]>.ReadHead> mArpPacketReadHead =
331 LazyKt.lazy(() -> mPacketReader.getReceivedPackets().newReadHead());
332
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900333 // Ethernet header
334 private static final int ETH_HEADER_LEN = 14;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900335
336 // IP header
337 private static final int IPV4_HEADER_LEN = 20;
Xiao Mac00a7932019-06-03 10:30:04 +0900338 private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900339 private static final int IPV4_DST_ADDR_OFFSET = IPV4_SRC_ADDR_OFFSET + 4;
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900340
341 // UDP header
342 private static final int UDP_HEADER_LEN = 8;
343 private static final int UDP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
344 private static final int UDP_SRC_PORT_OFFSET = UDP_HEADER_OFFSET + 0;
345
346 // DHCP header
347 private static final int DHCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN
348 + UDP_HEADER_LEN;
349 private static final int DHCP_MESSAGE_OP_CODE_OFFSET = DHCP_HEADER_OFFSET + 0;
350 private static final int DHCP_TRANSACTION_ID_OFFSET = DHCP_HEADER_OFFSET + 4;
351 private static final int DHCP_OPTION_MAGIC_COOKIE_OFFSET = DHCP_HEADER_OFFSET + 236;
Xiao Mac00a7932019-06-03 10:30:04 +0900352
353 private static final Inet4Address SERVER_ADDR =
354 (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.100");
355 private static final Inet4Address CLIENT_ADDR =
356 (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.2");
Xiao Ma8bbceb42019-10-08 16:21:07 +0900357 private static final Inet4Address CLIENT_ADDR_NEW =
358 (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.3");
Xiao Mac00a7932019-06-03 10:30:04 +0900359 private static final Inet4Address INADDR_ANY =
360 (Inet4Address) InetAddresses.parseNumericAddress("0.0.0.0");
361 private static final int PREFIX_LENGTH = 24;
362 private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH);
363 private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
364 SERVER_ADDR, PREFIX_LENGTH);
Xiao Ma78c89f42022-03-30 22:07:50 +0900365 private static final String IPV6_LINK_LOCAL_PREFIX = "fe80::/64";
366 private static final String IPV4_TEST_SUBNET_PREFIX = "192.168.1.0/24";
367 private static final String IPV4_ANY_ADDRESS_PREFIX = "0.0.0.0/0";
Xiao Mac00a7932019-06-03 10:30:04 +0900368 private static final String HOSTNAME = "testhostname";
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900369 private static final int TEST_DEFAULT_MTU = 1500;
370 private static final int TEST_MIN_MTU = 1280;
Xiao Ma60175d22021-06-02 12:28:40 +0000371 private static final MacAddress ROUTER_MAC = MacAddress.fromString("00:1A:11:22:33:44");
372 private static final byte[] ROUTER_MAC_BYTES = ROUTER_MAC.toByteArray();
373 private static final Inet6Address ROUTER_LINK_LOCAL =
374 (Inet6Address) InetAddresses.parseNumericAddress("fe80::1");
Xiao Ma8bcd6732019-08-26 17:24:26 +0900375 private static final String TEST_HOST_NAME = "AOSP on Crosshatch";
376 private static final String TEST_HOST_NAME_TRANSLITERATION = "AOSP-on-Crosshatch";
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +0900377 private static final String TEST_CAPTIVE_PORTAL_URL = "https://example.com/capportapi";
Xiao Ma562d2422019-12-16 13:20:59 +0900378 private static final byte[] TEST_HOTSPOT_OUI = new byte[] {
379 (byte) 0x00, (byte) 0x17, (byte) 0xF2
380 };
381 private static final byte TEST_VENDOR_SPECIFIC_TYPE = 0x06;
Xiao Ma8bbceb42019-10-08 16:21:07 +0900382
383 private static final String TEST_DEFAULT_SSID = "test_ssid";
Xiao Maf784d612020-04-02 23:16:04 +0900384 private static final String TEST_DEFAULT_BSSID = "00:11:22:33:44:55";
Xiao Ma8bbceb42019-10-08 16:21:07 +0900385 private static final String TEST_DHCP_ROAM_SSID = "0001docomo";
386 private static final String TEST_DHCP_ROAM_BSSID = "00:4e:35:17:98:55";
387 private static final String TEST_DHCP_ROAM_L2KEY = "roaming_l2key";
Chalard Jeanb2896832020-05-13 19:16:49 +0900388 private static final String TEST_DHCP_ROAM_CLUSTER = "roaming_cluster";
Xiao Ma8bbceb42019-10-08 16:21:07 +0900389 private static final byte[] TEST_AP_OUI = new byte[] { 0x00, 0x1A, 0x11 };
Xiao Mae31734e2020-12-10 21:09:26 +0900390 private static final byte[] TEST_OEM_OUI = new byte[] {(byte) 0x00, (byte) 0x17, (byte) 0xc3};
391 private static final String TEST_OEM_VENDOR_ID = "vendor-class-identifier";
392 private static final byte[] TEST_OEM_USER_CLASS_INFO = new byte[] {
393 // Instance of User Class: [0]
394 (byte) 0x03, /* UC_Len_0 */ (byte) 0x11, (byte) 0x22, (byte) 0x33,
395 // Instance of User Class: [1]
396 (byte) 0x03, /* UC_Len_1 */ (byte) 0x44, (byte) 0x55, (byte) 0x66,
397 };
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900398
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900399 protected class Dependencies extends IpClient.Dependencies {
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900400 // Can't use SparseIntArray, it doesn't have an easy way to know if a key is not present.
401 private HashMap<String, Integer> mIntConfigProperties = new HashMap<>();
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900402 private DhcpClient mDhcpClient;
Xiao Ma8bcd6732019-08-26 17:24:26 +0900403 private boolean mIsHostnameConfigurationEnabled;
404 private String mHostname;
Xiao Ma7dc8ef82020-08-13 15:25:06 +0900405 private boolean mIsInterfaceRecovered;
Xiao Ma6e2818b2020-06-22 01:18:22 +0900406
Xiao Ma8bcd6732019-08-26 17:24:26 +0900407 public void setHostnameConfiguration(final boolean enable, final String hostname) {
408 mIsHostnameConfigurationEnabled = enable;
409 mHostname = hostname;
410 }
411
Xiao Ma7dc8ef82020-08-13 15:25:06 +0900412 // Enable this flag to simulate the interface has been added back after removing
413 // on the provisioning start. However, the actual tap interface has been removed,
414 // interface parameters query will get null when attempting to restore Interface
415 // MTU. Create a new InterfaceParams instance and return instead just for interface
416 // toggling test case.
417 public void simulateInterfaceRecover() {
418 mIsInterfaceRecovered = true;
419 }
420
421 @Override
422 public InterfaceParams getInterfaceParams(String ifname) {
423 return mIsInterfaceRecovered
424 ? new InterfaceParams(ifname, 1 /* index */,
425 MacAddress.fromString("00:11:22:33:44:55"))
426 : super.getInterfaceParams(ifname);
427 }
428
Xiao Mac00a7932019-06-03 10:30:04 +0900429 @Override
430 public INetd getNetd(Context context) {
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900431 return mNetd;
Xiao Mac00a7932019-06-03 10:30:04 +0900432 }
433
434 @Override
435 public NetworkStackIpMemoryStore getIpMemoryStore(Context context,
436 NetworkStackServiceManager nssManager) {
437 return mIpMemoryStore;
438 }
439
440 @Override
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900441 public DhcpClient makeDhcpClient(Context context, StateMachine controller,
442 InterfaceParams ifParams, DhcpClient.Dependencies deps) {
443 mDhcpClient = DhcpClient.makeDhcpClient(context, controller, ifParams, deps);
444 return mDhcpClient;
445 }
446
Xiao Ma002dd5a2020-12-22 01:14:49 +0000447 @Override
Xiao Ma60175d22021-06-02 12:28:40 +0000448 public IpReachabilityMonitor getIpReachabilityMonitor(Context context,
449 InterfaceParams ifParams, Handler h, SharedLog log,
450 IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker,
451 IpReachabilityMonitor.Dependencies deps, final INetd netd) {
Xiao Ma374387c2021-11-02 02:25:55 +0000452 return new IpReachabilityMonitor(context, ifParams, h, log, callback,
Xiao Ma60175d22021-06-02 12:28:40 +0000453 usingMultinetworkPolicyTracker, deps, netd);
454 }
455
456 @Override
Xiao Maeb15c5e2021-03-09 08:40:50 +0000457 public boolean isFeatureEnabled(final Context context, final String name,
458 final boolean defaultEnabled) {
459 return IpClientIntegrationTestCommon.this.isFeatureEnabled(name, defaultEnabled);
460 }
461
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900462 @Override
Xiao Mac00a7932019-06-03 10:30:04 +0900463 public DhcpClient.Dependencies getDhcpClientDependencies(
lifr342cb2c2020-05-18 00:56:23 +0800464 NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics) {
465 return new DhcpClient.Dependencies(ipMemoryStore, metrics) {
Xiao Mac00a7932019-06-03 10:30:04 +0900466 @Override
Xiao Mafa33d492020-05-15 21:59:00 +0900467 public boolean isFeatureEnabled(final Context context, final String name,
468 final boolean defaultEnabled) {
Xiao Maeb15c5e2021-03-09 08:40:50 +0000469 return Dependencies.this.isFeatureEnabled(context, name, defaultEnabled);
Xiao Mac00a7932019-06-03 10:30:04 +0900470 }
Xiao Ma7d733952019-07-02 18:55:11 +0900471
472 @Override
Xiao Mad64f58e2019-12-10 15:56:41 +0900473 public int getIntDeviceConfig(final String name, int minimumValue,
474 int maximumValue, int defaultValue) {
Xiao Ma7d733952019-07-02 18:55:11 +0900475 return getDeviceConfigPropertyInt(name, 0 /* default value */);
476 }
477
478 @Override
479 public PowerManager.WakeLock getWakeLock(final PowerManager powerManager) {
480 return mTimeoutWakeLock;
481 }
Xiao Ma8bcd6732019-08-26 17:24:26 +0900482
483 @Override
484 public boolean getSendHostnameOption(final Context context) {
485 return mIsHostnameConfigurationEnabled;
486 }
487
488 @Override
489 public String getDeviceName(final Context context) {
490 return mIsHostnameConfigurationEnabled ? mHostname : null;
491 }
Xiao Mac00a7932019-06-03 10:30:04 +0900492 };
493 }
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900494
495 @Override
Xiao Ma60175d22021-06-02 12:28:40 +0000496 public IpReachabilityMonitor.Dependencies getIpReachabilityMonitorDeps(Context context,
497 String name) {
498 return new IpReachabilityMonitor.Dependencies() {
499 public void acquireWakeLock(long durationMs) {
500 // It doesn't matter for the integration test app on whether the wake lock
501 // is acquired or not.
502 return;
503 }
504
505 public IpNeighborMonitor makeIpNeighborMonitor(Handler h, SharedLog log,
506 NeighborEventConsumer cb) {
507 return new IpNeighborMonitor(h, log, cb);
508 }
Xiao Ma69a936a2021-04-21 08:14:44 +0000509
510 public boolean isFeatureEnabled(final Context context, final String name,
511 boolean defaultEnabled) {
512 return Dependencies.this.isFeatureEnabled(context, name, defaultEnabled);
513 }
Xiao Mad9d3bcc2020-12-14 01:25:50 +0000514
515 public IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics() {
516 return mIpReachabilityMonitorMetrics;
517 }
Xiao Ma60175d22021-06-02 12:28:40 +0000518 };
519 }
520
521 @Override
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900522 public int getDeviceConfigPropertyInt(String name, int defaultValue) {
523 Integer value = mIntConfigProperties.get(name);
524 if (value == null) {
525 throw new IllegalStateException("Non-mocked device config property " + name);
526 }
527 return value;
528 }
529
530 public void setDeviceConfigProperty(String name, int value) {
531 mIntConfigProperties.put(name, value);
532 }
lifrf9105de2021-05-06 15:31:04 +0800533
534 @Override
535 public NetworkQuirkMetrics getNetworkQuirkMetrics() {
536 return new NetworkQuirkMetrics(mNetworkQuirkMetricsDeps);
537 }
Xiao Mac00a7932019-06-03 10:30:04 +0900538 }
539
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900540 @NonNull
541 protected abstract IIpClient makeIIpClient(
542 @NonNull String ifaceName, @NonNull IIpClientCallbacks cb);
543
Xiao Maeb15c5e2021-03-09 08:40:50 +0000544 protected abstract void setFeatureEnabled(String name, boolean enabled);
545
546 protected abstract boolean isFeatureEnabled(String name, boolean defaultEnabled);
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900547
548 protected abstract boolean useNetworkStackSignature();
549
Xiao Ma927a8912021-01-07 08:05:02 +0000550 protected abstract NetworkAttributes getStoredNetworkAttributes(String l2Key, long timeout);
551
Xiao Ma4ca906c2021-01-30 12:09:41 +0000552 protected abstract void storeNetworkAttributes(String l2Key, NetworkAttributes na);
553
Xiao Ma927a8912021-01-07 08:05:02 +0000554 protected abstract void assertIpMemoryNeverStoreNetworkAttributes(String l2Key, long timeout);
555
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900556 protected final boolean testSkipped() {
557 // TODO: split out a test suite for root tests, and fail hard instead of skipping the test
558 // if it is run on devices where TestNetworkStackServiceClient is not supported
559 return !useNetworkStackSignature()
560 && (mIsSignatureRequiredTest || !TestNetworkStackServiceClient.isSupported());
561 }
562
Xiao Maeb15c5e2021-03-09 08:40:50 +0000563 protected void setDhcpFeatures(final boolean isDhcpLeaseCacheEnabled,
564 final boolean isRapidCommitEnabled, final boolean isDhcpIpConflictDetectEnabled,
565 final boolean isIPv6OnlyPreferredEnabled) {
566 setFeatureEnabled(NetworkStackUtils.DHCP_INIT_REBOOT_VERSION, isDhcpLeaseCacheEnabled);
567 setFeatureEnabled(NetworkStackUtils.DHCP_RAPID_COMMIT_VERSION, isRapidCommitEnabled);
568 setFeatureEnabled(NetworkStackUtils.DHCP_IP_CONFLICT_DETECT_VERSION,
569 isDhcpIpConflictDetectEnabled);
570 setFeatureEnabled(NetworkStackUtils.DHCP_IPV6_ONLY_PREFERRED_VERSION,
571 isIPv6OnlyPreferredEnabled);
572 }
573
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900574 @Before
575 public void setUp() throws Exception {
Xiao Ma93533832021-09-13 04:14:33 +0000576 // Suffix "[0]" or "[1]" is added to the end of test method name after running with
577 // Parameterized.class, that's intended behavior, to iterate each test method with the
578 // parameterize value. However, Class#getMethod() throws NoSuchMethodException when
579 // searching the target test method name due to this change. Just keep the original test
580 // method name to fix NoSuchMethodException, and find the correct annotation associated
581 // to test method.
582 final String testMethodName = mTestNameRule.getMethodName().split("\\[")[0];
583 final Method testMethod = IpClientIntegrationTestCommon.class.getMethod(testMethodName);
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900584 mIsSignatureRequiredTest = testMethod.getAnnotation(SignatureRequiredTest.class) != null;
585 assumeFalse(testSkipped());
586
Xiao Maebc22a82021-08-13 06:34:39 +0000587 // Depend on the parameterized value to enable/disable netlink message refactor flag.
588 // Make sure both of the old codepath(rely on the INetdUnsolicitedEventListener aidl)
589 // and new codepath(parse netlink event from kernel) will be executed.
590 //
591 // Note this must be called before making IpClient instance since MyNetlinkMontior ctor
592 // in IpClientLinkObserver will use mIsNetlinkEventParseEnabled to decide the proper
593 // bindGroups, otherwise, the parameterized value got from ArrayMap(integration test) is
594 // always false.
595 setFeatureEnabled(NetworkStackUtils.IPCLIENT_PARSE_NETLINK_EVENTS_VERSION,
596 mIsNetlinkEventParseEnabled /* default value */);
597
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900598 setUpTapInterface();
599 mCb = mock(IIpClientCallbacks.class);
600
601 if (useNetworkStackSignature()) {
602 setUpMocks();
603 setUpIpClient();
Xiao Ma7ae2ec32021-09-29 06:07:15 +0000604 // Enable packet retransmit alarm in DhcpClient.
605 enableRealAlarm("DhcpClient." + mIfaceName + ".KICK");
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900606 }
607
608 mIIpClient = makeIIpClient(mIfaceName, mCb);
609 }
610
611 protected void setUpMocks() throws Exception {
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900612 MockitoAnnotations.initMocks(this);
613
Xiao Mac00a7932019-06-03 10:30:04 +0900614 mDependencies = new Dependencies();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900615 when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
616 when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
617 when(mContext.getResources()).thenReturn(mResources);
Xiao Ma9661f0b2021-12-13 12:56:32 +0000618 when(mResources.getInteger(eq(R.integer.config_nud_postroaming_solicit_num))).thenReturn(5);
619 when(mResources.getInteger(eq(R.integer.config_nud_postroaming_solicit_interval)))
620 .thenReturn(750);
621 when(mResources.getInteger(eq(R.integer.config_nud_steadystate_solicit_num)))
622 .thenReturn(10);
623 when(mResources.getInteger(eq(R.integer.config_nud_steadystate_solicit_interval)))
624 .thenReturn(750);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900625 when(mContext.getContentResolver()).thenReturn(mContentResolver);
Xiao Mac00a7932019-06-03 10:30:04 +0900626 when(mNetworkStackServiceManager.getIpMemoryStoreService())
627 .thenReturn(mIpMemoryStoreService);
Xiao Ma374387c2021-11-02 02:25:55 +0000628 when(mCb.getInterfaceVersion()).thenReturn(IpClient.VERSION_ADDED_REACHABILITY_FAILURE);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900629
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +0900630 mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67);
Xiao Ma7d733952019-07-02 18:55:11 +0900631 mDependencies.setDeviceConfigProperty(DhcpClient.DHCP_RESTART_CONFIG_DELAY, 10);
632 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_FIRST_PROBE_DELAY_MS, 10);
633 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_PROBE_MIN_MS, 10);
634 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_PROBE_MAX_MS, 20);
635 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_FIRST_ANNOUNCE_DELAY_MS, 10);
636 mDependencies.setDeviceConfigProperty(DhcpClient.ARP_ANNOUNCE_INTERVAL_MS, 10);
Xiao Ma148f5742022-06-06 11:20:33 +0900637
638 // Set the initial netlink socket receive buffer size to a minimum of 10KB to ensure test
639 // cases are still working, meanwhile in order to easily overflow the receive buffer by
640 // sending as few RAs as possible for test case where it's used to verify ENOBUFS.
641 mDependencies.setDeviceConfigProperty(CONFIG_SOCKET_RECV_BUFSIZE, 10 * 1024);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900642 }
643
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900644 private void awaitIpClientShutdown() throws Exception {
645 verify(mCb, timeout(TEST_TIMEOUT_MS)).onQuit();
646 }
647
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900648 @After
649 public void tearDown() throws Exception {
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900650 if (testSkipped()) return;
Lorenzo Colitti8b93f292021-10-12 16:58:56 +0900651 teardownTapInterface();
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900652 mIIpClient.shutdown();
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900653 awaitIpClientShutdown();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900654 }
655
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900656 private void setUpTapInterface() throws Exception {
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900657 final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
Lorenzo Colittid17b7282022-01-25 17:57:39 +0900658 final TestNetworkInterface iface = runAsShell(MANAGE_TEST_NETWORKS, () -> {
659 final TestNetworkManager tnm =
660 inst.getContext().getSystemService(TestNetworkManager.class);
661 return tnm.createTapInterface();
662 });
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900663 mIfaceName = iface.getInterfaceName();
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900664 mClientMac = getIfaceMacAddr(mIfaceName).toByteArray();
665 mPacketReaderThread = new HandlerThread(
666 IpClientIntegrationTestCommon.class.getSimpleName());
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900667 mPacketReaderThread.start();
Xiao Mac66d5d02019-09-03 10:41:58 +0900668 mHandler = mPacketReaderThread.getThreadHandler();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900669
Lorenzo Colitti097a6d22020-04-17 23:22:50 +0900670 // Detach the FileDescriptor from the ParcelFileDescriptor.
671 // Otherwise, the garbage collector might call the ParcelFileDescriptor's finalizer, which
672 // closes the FileDescriptor and destroys our tap interface. An alternative would be to
673 // make the ParcelFileDescriptor or the TestNetworkInterface a class member so they never
674 // go out of scope.
675 mTapFd = new FileDescriptor();
676 mTapFd.setInt$(iface.getFileDescriptor().detachFd());
Lorenzo Colitti32215002020-03-13 19:40:32 +0900677 mPacketReader = new TapPacketReader(mHandler, mTapFd, DATA_BUFFER_LEN);
Xiao Mac66d5d02019-09-03 10:41:58 +0900678 mHandler.post(() -> mPacketReader.start());
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900679 }
680
Xiao Maac371ef2021-09-15 03:37:41 +0000681 private TestNetworkInterface setUpClatInterface(@NonNull String baseIface) throws Exception {
682 final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
683 final TestNetworkInterface iface = runAsShell(MANAGE_TEST_NETWORKS, () -> {
684 final TestNetworkManager tnm =
685 inst.getContext().getSystemService(TestNetworkManager.class);
686 return tnm.createTapInterface(false /* bringUp */, CLAT_PREFIX + baseIface);
687 });
688 return iface;
689 }
690
Lorenzo Colitti8b93f292021-10-12 16:58:56 +0900691 private void teardownTapInterface() {
692 if (mPacketReader != null) {
693 mHandler.post(() -> mPacketReader.stop()); // Also closes the socket
694 mTapFd = null;
695 }
696 if (mPacketReaderThread != null) {
697 mPacketReaderThread.quitSafely();
698 }
699 }
700
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900701 private MacAddress getIfaceMacAddr(String ifaceName) throws IOException {
702 // InterfaceParams.getByName requires CAP_NET_ADMIN: read the mac address with the shell
703 final String strMacAddr = getOneLineCommandOutput(
704 "su root cat /sys/class/net/" + ifaceName + "/address");
705 return MacAddress.fromString(strMacAddr);
706 }
707
708 private String getOneLineCommandOutput(String cmd) throws IOException {
709 try (ParcelFileDescriptor fd = InstrumentationRegistry.getInstrumentation()
710 .getUiAutomation().executeShellCommand(cmd);
711 BufferedReader reader = new BufferedReader(new FileReader(fd.getFileDescriptor()))) {
712 return reader.readLine();
713 }
714 }
715
Xiao Ma7ae2ec32021-09-29 06:07:15 +0000716 private void enableRealAlarm(String cmdName) {
717 doAnswer((inv) -> {
718 final Context context = InstrumentationRegistry.getTargetContext();
719 final AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
720 alarmManager.setExact(inv.getArgument(0), inv.getArgument(1), inv.getArgument(2),
721 inv.getArgument(3), inv.getArgument(4));
722 return null;
723 }).when(mAlarm).setExact(anyInt(), anyLong(), eq(cmdName), any(OnAlarmListener.class),
724 any(Handler.class));
725 }
726
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900727 private IpClient makeIpClient() throws Exception {
728 IpClient ipc = new IpClient(mContext, mIfaceName, mCb, mNetworkObserverRegistry,
729 mNetworkStackServiceManager, mDependencies);
730 // Wait for IpClient to enter its initial state. Otherwise, additional setup steps or tests
731 // that mock IpClient's dependencies might interact with those mocks while IpClient is
732 // starting. This would cause UnfinishedStubbingExceptions as mocks cannot be interacted
733 // with while they are being stubbed.
734 HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
735 return ipc;
736 }
737
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900738 private void setUpIpClient() throws Exception {
739 final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
740 final IBinder netdIBinder =
741 (IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE);
Lorenzo Colitti1e868b32019-11-29 16:17:58 +0900742 mNetd = spy(INetd.Stub.asInterface(netdIBinder));
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900743 when(mContext.getSystemService(eq(Context.NETD_SERVICE))).thenReturn(netdIBinder);
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900744 assertNotNull(mNetd);
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900745
Lorenzo Colitti58da4e32020-04-24 21:57:22 +0900746 mNetworkObserverRegistry = new NetworkObserverRegistry();
747 mNetworkObserverRegistry.register(mNetd);
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900748 mIpc = makeIpClient();
Lorenzo Colittibd919742020-04-24 23:16:49 +0900749
750 // Tell the IpMemoryStore immediately to answer any question about network attributes with a
751 // null response. Otherwise, the DHCP client will wait for two seconds before starting,
752 // while its query to the IpMemoryStore times out.
753 // This does not affect any test that makes the mock memory store return results, because
754 // unlike when(), it is documented that doAnswer() can be called more than once, to change
755 // the behaviour of a mock in the middle of a test.
756 doAnswer(invocation -> {
757 final String l2Key = invocation.getArgument(0);
758 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1))
759 .onNetworkAttributesRetrieved(new Status(SUCCESS), l2Key, null);
760 return null;
761 }).when(mIpMemoryStore).retrieveNetworkAttributes(any(), any());
762
763 disableIpv6ProvisioningDelays();
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900764 }
765
Lorenzo Colitti5e384442020-04-26 20:18:04 +0900766 private <T> T verifyWithTimeout(InOrder inOrder, T t) {
767 if (inOrder != null) {
768 return inOrder.verify(t, timeout(TEST_TIMEOUT_MS));
769 } else {
770 return verify(t, timeout(TEST_TIMEOUT_MS));
771 }
772 }
773
Lorenzo Colitti31c7a512020-04-22 16:03:41 +0900774 private void expectAlarmCancelled(InOrder inOrder, OnAlarmListener listener) {
775 inOrder.verify(mAlarm, timeout(TEST_TIMEOUT_MS)).cancel(eq(listener));
776 }
777
Xiao Ma6e2818b2020-06-22 01:18:22 +0900778 private OnAlarmListener expectAlarmSet(InOrder inOrder, String tagMatch, long afterSeconds,
779 Handler handler) {
Lorenzo Colitti31c7a512020-04-22 16:03:41 +0900780 // Allow +/- 3 seconds to prevent flaky tests.
781 final long when = SystemClock.elapsedRealtime() + afterSeconds * 1000;
782 final long min = when - 3 * 1000;
783 final long max = when + 3 * 1000;
784 ArgumentCaptor<OnAlarmListener> captor = ArgumentCaptor.forClass(OnAlarmListener.class);
Lorenzo Colitti5e384442020-04-26 20:18:04 +0900785 verifyWithTimeout(inOrder, mAlarm).setExact(
786 anyInt(), longThat(x -> x >= min && x <= max),
Xiao Ma6e2818b2020-06-22 01:18:22 +0900787 contains(tagMatch), captor.capture(), eq(handler));
Lorenzo Colitti31c7a512020-04-22 16:03:41 +0900788 return captor.getValue();
789 }
790
Xiao Ma6e2818b2020-06-22 01:18:22 +0900791 private OnAlarmListener expectAlarmSet(InOrder inOrder, String tagMatch, int afterSeconds) {
792 return expectAlarmSet(inOrder, tagMatch, (long) afterSeconds, mIpc.getHandler());
793 }
794
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900795 private boolean packetContainsExpectedField(final byte[] packet, final int offset,
796 final byte[] expected) {
797 if (packet.length < offset + expected.length) return false;
798 for (int i = 0; i < expected.length; ++i) {
799 if (packet[offset + i] != expected[i]) return false;
800 }
801 return true;
802 }
803
804 private boolean isDhcpPacket(final byte[] packet) {
805 final ByteBuffer buffer = ByteBuffer.wrap(packet);
806
807 // check the packet length
808 if (packet.length < DHCP_HEADER_OFFSET) return false;
809
810 // check the source port and dest port in UDP header
811 buffer.position(UDP_SRC_PORT_OFFSET);
812 final short udpSrcPort = buffer.getShort();
813 final short udpDstPort = buffer.getShort();
814 if (udpSrcPort != DHCP_CLIENT || udpDstPort != DHCP_SERVER) return false;
815
816 // check DHCP message type
817 buffer.position(DHCP_MESSAGE_OP_CODE_OFFSET);
818 final byte dhcpOpCode = buffer.get();
819 if (dhcpOpCode != DHCP_BOOTREQUEST) return false;
820
821 // check DHCP magic cookie
822 buffer.position(DHCP_OPTION_MAGIC_COOKIE_OFFSET);
823 final int dhcpMagicCookie = buffer.getInt();
824 if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) return false;
825
826 return true;
827 }
828
Xiao Ma7d733952019-07-02 18:55:11 +0900829 private ArpPacket parseArpPacketOrNull(final byte[] packet) {
830 try {
831 return ArpPacket.parseArpPacket(packet, packet.length);
832 } catch (ArpPacket.ParseException e) {
833 return null;
834 }
835 }
836
Xiao Ma002dd5a2020-12-22 01:14:49 +0000837 private NeighborAdvertisement parseNeighborAdvertisementOrNull(final byte[] packet) {
838 try {
839 return NeighborAdvertisement.parse(packet, packet.length);
840 } catch (NeighborAdvertisement.ParseException e) {
841 return null;
842 }
843 }
844
Xiao Ma60175d22021-06-02 12:28:40 +0000845 private NeighborSolicitation parseNeighborSolicitationOrNull(final byte[] packet) {
846 try {
847 return NeighborSolicitation.parse(packet, packet.length);
848 } catch (NeighborSolicitation.ParseException e) {
849 return null;
850 }
851 }
852
Xiao Mac00a7932019-06-03 10:30:04 +0900853 private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900854 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
855 final String captivePortalUrl, final Integer ipv6OnlyWaitTime) {
Xiao Mac00a7932019-06-03 10:30:04 +0900856 return DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
857 false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900858 clientAddress /* yourIp */, packet.getClientMac(), leaseTimeSec,
Xiao Mac00a7932019-06-03 10:30:04 +0900859 NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */,
860 Collections.singletonList(SERVER_ADDR) /* gateways */,
861 Collections.singletonList(SERVER_ADDR) /* dnsServers */,
862 SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900863 false /* metered */, mtu, captivePortalUrl, ipv6OnlyWaitTime);
864 }
865
866 private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet,
867 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
868 final String captivePortalUrl) {
869 return buildDhcpOfferPacket(packet, clientAddress, leaseTimeSec, mtu, captivePortalUrl,
870 null /* ipv6OnlyWaitTime */);
Xiao Mac00a7932019-06-03 10:30:04 +0900871 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +0900872
Xiao Mac00a7932019-06-03 10:30:04 +0900873 private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet,
Xiao Ma8bbceb42019-10-08 16:21:07 +0900874 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900875 final boolean rapidCommit, final String captivePortalApiUrl,
876 final Integer ipv6OnlyWaitTime) {
Xiao Mac00a7932019-06-03 10:30:04 +0900877 return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
878 false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
Xiao Ma8bbceb42019-10-08 16:21:07 +0900879 clientAddress /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(),
Xiao Mac00a7932019-06-03 10:30:04 +0900880 leaseTimeSec, NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */,
881 Collections.singletonList(SERVER_ADDR) /* gateways */,
882 Collections.singletonList(SERVER_ADDR) /* dnsServers */,
883 SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME,
Xiao Ma6e2818b2020-06-22 01:18:22 +0900884 false /* metered */, mtu, rapidCommit, captivePortalApiUrl, ipv6OnlyWaitTime);
885 }
886
887 private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet,
888 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
889 final boolean rapidCommit, final String captivePortalApiUrl) {
890 return buildDhcpAckPacket(packet, clientAddress, leaseTimeSec, mtu, rapidCommit,
891 captivePortalApiUrl, null /* ipv6OnlyWaitTime */);
Xiao Mac00a7932019-06-03 10:30:04 +0900892 }
893
Xiao Ma780c09e2021-11-05 09:43:12 +0000894 private static ByteBuffer buildDhcpNakPacket(final DhcpPacket packet, final String message) {
Xiao Mac00a7932019-06-03 10:30:04 +0900895 return DhcpPacket.buildNakPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
896 SERVER_ADDR /* serverIp */, INADDR_ANY /* relayIp */, packet.getClientMac(),
Xiao Ma780c09e2021-11-05 09:43:12 +0000897 false /* broadcast */, message);
Xiao Mac00a7932019-06-03 10:30:04 +0900898 }
899
Xiao Ma7d733952019-07-02 18:55:11 +0900900 private void sendArpReply(final byte[] clientMac) throws IOException {
901 final ByteBuffer packet = ArpPacket.buildArpPacket(clientMac /* dst */,
Xiao Ma60175d22021-06-02 12:28:40 +0000902 ROUTER_MAC_BYTES /* srcMac */, INADDR_ANY.getAddress() /* target IP */,
Xiao Ma7d733952019-07-02 18:55:11 +0900903 clientMac /* target HW address */, CLIENT_ADDR.getAddress() /* sender IP */,
904 (short) ARP_REPLY);
Lorenzo Colitti32215002020-03-13 19:40:32 +0900905 mPacketReader.sendResponse(packet);
Xiao Ma7d733952019-07-02 18:55:11 +0900906 }
907
908 private void sendArpProbe() throws IOException {
909 final ByteBuffer packet = ArpPacket.buildArpPacket(DhcpPacket.ETHER_BROADCAST /* dst */,
Xiao Ma60175d22021-06-02 12:28:40 +0000910 ROUTER_MAC_BYTES /* srcMac */, CLIENT_ADDR.getAddress() /* target IP */,
Xiao Ma7d733952019-07-02 18:55:11 +0900911 new byte[ETHER_ADDR_LEN] /* target HW address */,
912 INADDR_ANY.getAddress() /* sender IP */, (short) ARP_REQUEST);
Lorenzo Colitti32215002020-03-13 19:40:32 +0900913 mPacketReader.sendResponse(packet);
Xiao Ma7d733952019-07-02 18:55:11 +0900914 }
915
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900916 private void startIpClientProvisioning(final ProvisioningConfiguration cfg) throws Exception {
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900917 mIIpClient.startProvisioning(cfg.toStableParcelable());
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900918 }
919
Xiao Mac00a7932019-06-03 10:30:04 +0900920 private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled,
Xiao Ma7b60bfa2019-12-09 10:23:32 +0900921 final boolean shouldReplyRapidCommitAck, final boolean isPreconnectionEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +0000922 final boolean isDhcpIpConflictDetectEnabled, final boolean isIPv6OnlyPreferredEnabled,
Xiao Ma861fe422021-04-16 03:03:03 +0000923 final String displayName, final ScanResultInfo scanResultInfo,
924 final Layer2Information layer2Info) throws Exception {
Xiao Mab5721cc2020-04-16 16:20:25 +0900925 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
Xiao Mac00a7932019-06-03 10:30:04 +0900926 .withoutIpReachabilityMonitor()
Xiao Ma861fe422021-04-16 03:03:03 +0000927 .withLayer2Information(layer2Info == null
928 ? new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
929 MacAddress.fromString(TEST_DEFAULT_BSSID))
930 : layer2Info)
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900931 .withoutIPv6();
Xiao Mab5721cc2020-04-16 16:20:25 +0900932 if (isPreconnectionEnabled) prov.withPreconnection();
933 if (displayName != null) prov.withDisplayName(displayName);
934 if (scanResultInfo != null) prov.withScanResultInfo(scanResultInfo);
Xiao Mac00a7932019-06-03 10:30:04 +0900935
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900936 setDhcpFeatures(isDhcpLeaseCacheEnabled, shouldReplyRapidCommitAck,
Xiao Ma927a8912021-01-07 08:05:02 +0000937 isDhcpIpConflictDetectEnabled, isIPv6OnlyPreferredEnabled);
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +0900938
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +0900939 startIpClientProvisioning(prov.build());
Xiao Ma4a8d1d42019-07-19 10:39:06 +0900940 if (!isPreconnectionEnabled) {
941 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
942 }
Xiao Mac00a7932019-06-03 10:30:04 +0900943 verify(mCb, never()).onProvisioningFailure(any());
944 }
945
Xiao Ma8bcd6732019-08-26 17:24:26 +0900946 private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled,
947 final boolean isDhcpRapidCommitEnabled, final boolean isPreconnectionEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +0000948 final boolean isDhcpIpConflictDetectEnabled, final boolean isIPv6OnlyPreferredEnabled)
949 throws Exception {
Xiao Ma8bcd6732019-08-26 17:24:26 +0900950 startIpClientProvisioning(isDhcpLeaseCacheEnabled, isDhcpRapidCommitEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +0000951 isPreconnectionEnabled, isDhcpIpConflictDetectEnabled, isIPv6OnlyPreferredEnabled,
Xiao Ma861fe422021-04-16 03:03:03 +0000952 null /* displayName */, null /* ScanResultInfo */, null /* layer2Info */);
Xiao Ma8bcd6732019-08-26 17:24:26 +0900953 }
954
Xiao Mac00a7932019-06-03 10:30:04 +0900955 private void assertIpMemoryStoreNetworkAttributes(final Integer leaseTimeSec,
Xiao Ma1ef8fd82019-07-16 19:16:39 +0900956 final long startTime, final int mtu) {
Xiao Ma927a8912021-01-07 08:05:02 +0000957 final NetworkAttributes na = getStoredNetworkAttributes(TEST_L2KEY, TEST_TIMEOUT_MS);
958 assertNotNull(na);
959 assertEquals(CLIENT_ADDR, na.assignedV4Address);
Xiao Mac00a7932019-06-03 10:30:04 +0900960 if (leaseTimeSec == null || leaseTimeSec.intValue() == DhcpPacket.INFINITE_LEASE) {
Xiao Ma927a8912021-01-07 08:05:02 +0000961 assertEquals(Long.MAX_VALUE, na.assignedV4AddressExpiry.longValue());
Xiao Mac00a7932019-06-03 10:30:04 +0900962 } else {
963 // check the lease expiry's scope
964 final long upperBound = startTime + 7_200_000; // start timestamp + 2h
965 final long lowerBound = startTime + 3_600_000; // start timestamp + 1h
Xiao Ma927a8912021-01-07 08:05:02 +0000966 final long expiry = na.assignedV4AddressExpiry;
Xiao Mac00a7932019-06-03 10:30:04 +0900967 assertTrue(upperBound > expiry);
968 assertTrue(lowerBound < expiry);
969 }
Xiao Ma927a8912021-01-07 08:05:02 +0000970 assertEquals(Collections.singletonList(SERVER_ADDR), na.dnsAddresses);
971 assertEquals(new Integer(mtu), na.mtu);
Xiao Mac00a7932019-06-03 10:30:04 +0900972 }
973
974 private void assertIpMemoryNeverStoreNetworkAttributes() {
Xiao Ma927a8912021-01-07 08:05:02 +0000975 assertIpMemoryNeverStoreNetworkAttributes(TEST_L2KEY, TEST_TIMEOUT_MS);
Xiao Mac00a7932019-06-03 10:30:04 +0900976 }
977
Xiao Ma8bcd6732019-08-26 17:24:26 +0900978 private void assertHostname(final boolean isHostnameConfigurationEnabled,
979 final String hostname, final String hostnameAfterTransliteration,
980 final List<DhcpPacket> packetList) throws Exception {
981 for (DhcpPacket packet : packetList) {
982 if (!isHostnameConfigurationEnabled || hostname == null) {
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900983 assertNoHostname(packet.getHostname());
Xiao Ma8bcd6732019-08-26 17:24:26 +0900984 } else {
985 assertEquals(packet.getHostname(), hostnameAfterTransliteration);
986 }
987 }
988 }
989
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900990 private void assertNoHostname(String hostname) {
Lorenzo Colitti0d08b442020-04-27 11:49:39 +0900991 if (ShimUtils.isAtLeastR()) {
Remi NGUYEN VANc16cae12020-02-05 23:36:23 +0900992 assertNull(hostname);
993 } else {
994 // Until Q, if no hostname is set, the device falls back to the hostname set via
995 // system property, to avoid breaking Q devices already launched with that setup.
996 assertEquals(SystemProperties.get("net.hostname"), hostname);
997 }
998 }
999
Xiao Mac00a7932019-06-03 10:30:04 +09001000 // Helper method to complete DHCP 2-way or 4-way handshake
Xiao Ma8bcd6732019-08-26 17:24:26 +09001001 private List<DhcpPacket> performDhcpHandshake(final boolean isSuccessLease,
Xiao Mac00a7932019-06-03 10:30:04 +09001002 final Integer leaseTimeSec, final boolean isDhcpLeaseCacheEnabled,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001003 final boolean shouldReplyRapidCommitAck, final int mtu,
Xiao Ma8bcd6732019-08-26 17:24:26 +09001004 final boolean isDhcpIpConflictDetectEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +00001005 final boolean isIPv6OnlyPreferredEnabled,
Xiao Ma562d2422019-12-16 13:20:59 +09001006 final String captivePortalApiUrl, final String displayName,
Xiao Ma861fe422021-04-16 03:03:03 +00001007 final ScanResultInfo scanResultInfo, final Layer2Information layer2Info)
1008 throws Exception {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001009 startIpClientProvisioning(isDhcpLeaseCacheEnabled, shouldReplyRapidCommitAck,
Xiao Ma8bcd6732019-08-26 17:24:26 +09001010 false /* isPreconnectionEnabled */, isDhcpIpConflictDetectEnabled,
Xiao Ma861fe422021-04-16 03:03:03 +00001011 isIPv6OnlyPreferredEnabled, displayName, scanResultInfo, layer2Info);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001012 return handleDhcpPackets(isSuccessLease, leaseTimeSec, shouldReplyRapidCommitAck, mtu,
Xiao Ma872b2362020-05-27 12:10:40 +09001013 captivePortalApiUrl);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001014 }
Xiao Mac00a7932019-06-03 10:30:04 +09001015
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001016 private List<DhcpPacket> handleDhcpPackets(final boolean isSuccessLease,
1017 final Integer leaseTimeSec, final boolean shouldReplyRapidCommitAck, final int mtu,
Xiao Ma872b2362020-05-27 12:10:40 +09001018 final String captivePortalApiUrl) throws Exception {
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001019 final List<DhcpPacket> packetList = new ArrayList<>();
Xiao Mac00a7932019-06-03 10:30:04 +09001020 DhcpPacket packet;
1021 while ((packet = getNextDhcpPacket()) != null) {
Xiao Ma8bcd6732019-08-26 17:24:26 +09001022 packetList.add(packet);
Xiao Mac00a7932019-06-03 10:30:04 +09001023 if (packet instanceof DhcpDiscoverPacket) {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001024 if (shouldReplyRapidCommitAck) {
Xiao Ma8bbceb42019-10-08 16:21:07 +09001025 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec,
1026 (short) mtu, true /* rapidCommit */, captivePortalApiUrl));
Xiao Mac00a7932019-06-03 10:30:04 +09001027 } else {
Xiao Ma6e2818b2020-06-22 01:18:22 +09001028 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR,
1029 leaseTimeSec, (short) mtu, captivePortalApiUrl));
Xiao Mac00a7932019-06-03 10:30:04 +09001030 }
1031 } else if (packet instanceof DhcpRequestPacket) {
1032 final ByteBuffer byteBuffer = isSuccessLease
Xiao Ma8bbceb42019-10-08 16:21:07 +09001033 ? buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec, (short) mtu,
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09001034 false /* rapidCommit */, captivePortalApiUrl)
Xiao Ma780c09e2021-11-05 09:43:12 +00001035 : buildDhcpNakPacket(packet, "duplicated request IP address");
Lorenzo Colitti32215002020-03-13 19:40:32 +09001036 mPacketReader.sendResponse(byteBuffer);
Xiao Mac00a7932019-06-03 10:30:04 +09001037 } else {
1038 fail("invalid DHCP packet");
1039 }
Xiao Ma16b21ef2020-01-22 17:51:26 +09001040
Xiao Mac00a7932019-06-03 10:30:04 +09001041 // wait for reply to DHCPOFFER packet if disabling rapid commit option
Xiao Ma8bcd6732019-08-26 17:24:26 +09001042 if (shouldReplyRapidCommitAck || !(packet instanceof DhcpDiscoverPacket)) {
1043 return packetList;
1044 }
Xiao Mac00a7932019-06-03 10:30:04 +09001045 }
1046 fail("No DHCPREQUEST received on interface");
Xiao Ma8bcd6732019-08-26 17:24:26 +09001047 return packetList;
1048 }
1049
1050 private List<DhcpPacket> performDhcpHandshake(final boolean isSuccessLease,
1051 final Integer leaseTimeSec, final boolean isDhcpLeaseCacheEnabled,
1052 final boolean isDhcpRapidCommitEnabled, final int mtu,
1053 final boolean isDhcpIpConflictDetectEnabled) throws Exception {
1054 return performDhcpHandshake(isSuccessLease, leaseTimeSec, isDhcpLeaseCacheEnabled,
1055 isDhcpRapidCommitEnabled, mtu, isDhcpIpConflictDetectEnabled,
Xiao Ma927a8912021-01-07 08:05:02 +00001056 false /* isIPv6OnlyPreferredEnabled */,
Xiao Ma861fe422021-04-16 03:03:03 +00001057 null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */,
1058 null /* layer2Info */);
Xiao Mac00a7932019-06-03 10:30:04 +09001059 }
1060
Lorenzo Colitti46a78742020-04-02 20:21:16 +09001061 private List<DhcpPacket> performDhcpHandshake() throws Exception {
1062 return performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
1063 false /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
1064 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
1065 }
1066
Xiao Ma861fe422021-04-16 03:03:03 +00001067 private DhcpPacket getNextDhcpPacket(final long timeout) throws Exception {
1068 byte[] packet;
1069 while ((packet = mDhcpPacketReadHead.getValue()
1070 .poll(timeout, this::isDhcpPacket)) != null) {
1071 final DhcpPacket dhcpPacket = DhcpPacket.decodeFullPacket(packet, packet.length,
1072 ENCAP_L2);
1073 if (dhcpPacket != null) return dhcpPacket;
1074 }
1075 return null;
1076 }
1077
1078 private DhcpPacket getNextDhcpPacket() throws Exception {
1079 final DhcpPacket packet = getNextDhcpPacket(PACKET_TIMEOUT_MS);
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001080 assertNotNull("No expected DHCP packet received on interface within timeout", packet);
Xiao Ma861fe422021-04-16 03:03:03 +00001081 return packet;
Xiao Mac00a7932019-06-03 10:30:04 +09001082 }
1083
1084 private DhcpPacket getReplyFromDhcpLease(final NetworkAttributes na, boolean timeout)
1085 throws Exception {
1086 doAnswer(invocation -> {
1087 if (timeout) return null;
1088 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1))
1089 .onNetworkAttributesRetrieved(new Status(SUCCESS), TEST_L2KEY, na);
1090 return null;
1091 }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any());
1092 startIpClientProvisioning(true /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001093 false /* shouldReplyRapidCommitAck */, false /* isPreconnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001094 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mac00a7932019-06-03 10:30:04 +09001095 return getNextDhcpPacket();
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001096 }
1097
Xiao Maac371ef2021-09-15 03:37:41 +00001098 private void removeTestInterface(final FileDescriptor fd) {
Xiao Ma619c28c2019-08-23 16:47:22 +09001099 try {
1100 Os.close(fd);
1101 } catch (ErrnoException e) {
1102 fail("Fail to close file descriptor: " + e);
1103 }
1104 }
1105
1106 private void verifyAfterIpClientShutdown() throws RemoteException {
1107 final LinkProperties emptyLp = new LinkProperties();
1108 emptyLp.setInterfaceName(mIfaceName);
1109 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(emptyLp);
1110 }
1111
Xiao Ma872b2362020-05-27 12:10:40 +09001112 // Verify IPv4-only provisioning success. No need to verify IPv4 provisioning when below cases
1113 // happen:
1114 // 1. if there's a failure lease, onProvisioningSuccess() won't be called;
1115 // 2. if duplicated IPv4 address detection is enabled, verify TIMEOUT will affect ARP packets
1116 // capture running in other test cases.
1117 // 3. if IPv6 is enabled, e.g. withoutIPv6() isn't called when starting provisioning.
1118 private void verifyIPv4OnlyProvisioningSuccess(final Collection<InetAddress> addresses)
1119 throws Exception {
1120 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
Xiao Ma16b21ef2020-01-22 17:51:26 +09001121 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
1122 LinkProperties lp = captor.getValue();
1123 assertNotNull(lp);
1124 assertNotEquals(0, lp.getDnsServers().size());
1125 assertEquals(addresses.size(), lp.getAddresses().size());
1126 assertTrue(lp.getAddresses().containsAll(addresses));
1127 }
1128
Xiao Ma619c28c2019-08-23 16:47:22 +09001129 private void doRestoreInitialMtuTest(final boolean shouldChangeMtu,
Xiao Maac371ef2021-09-15 03:37:41 +00001130 final boolean shouldRemoveTestInterface) throws Exception {
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001131 final long currentTime = System.currentTimeMillis();
1132 int mtu = TEST_DEFAULT_MTU;
1133
1134 if (shouldChangeMtu) mtu = TEST_MIN_MTU;
1135 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001136 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001137 mtu, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001138 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001139 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, mtu);
1140
1141 if (shouldChangeMtu) {
1142 // Pretend that ConnectivityService set the MTU.
1143 mNetd.interfaceSetMtu(mIfaceName, mtu);
1144 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), mtu);
1145 }
1146
Xiao Ma5c110212020-03-29 16:11:47 +09001147 // Sometimes, IpClient receives an update with an empty LinkProperties during startup,
1148 // when the link-local address is deleted after interface bringup. Reset expectations
1149 // here to ensure that verifyAfterIpClientShutdown does not fail because it sees two
1150 // empty LinkProperties changes instead of one.
1151 reset(mCb);
1152
Xiao Maac371ef2021-09-15 03:37:41 +00001153 if (shouldRemoveTestInterface) removeTestInterface(mTapFd);
Xiao Ma619c28c2019-08-23 16:47:22 +09001154 try {
1155 mIpc.shutdown();
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001156 awaitIpClientShutdown();
Xiao Maac371ef2021-09-15 03:37:41 +00001157 if (shouldRemoveTestInterface) {
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001158 verify(mNetd, never()).interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU);
Xiao Ma619c28c2019-08-23 16:47:22 +09001159 } else {
1160 // Verify that MTU indeed has been restored or not.
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001161 verify(mNetd, times(shouldChangeMtu ? 1 : 0))
Xiao Ma619c28c2019-08-23 16:47:22 +09001162 .interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU);
1163 }
1164 verifyAfterIpClientShutdown();
1165 } catch (Exception e) {
1166 fail("Exception should not have been thrown after shutdown: " + e);
1167 }
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001168 }
1169
Xiao Ma96147b72020-05-06 19:09:38 +09001170 private DhcpPacket assertDiscoverPacketOnPreconnectionStart() throws Exception {
1171 final ArgumentCaptor<List<Layer2PacketParcelable>> l2PacketList =
1172 ArgumentCaptor.forClass(List.class);
1173
1174 verify(mCb, timeout(TEST_TIMEOUT_MS)).onPreconnectionStart(l2PacketList.capture());
1175 final byte[] payload = l2PacketList.getValue().get(0).payload;
1176 DhcpPacket packet = DhcpPacket.decodeFullPacket(payload, payload.length, ENCAP_L2);
1177 assertTrue(packet instanceof DhcpDiscoverPacket);
1178 assertArrayEquals(INADDR_BROADCAST.getAddress(),
1179 Arrays.copyOfRange(payload, IPV4_DST_ADDR_OFFSET, IPV4_DST_ADDR_OFFSET + 4));
1180 return packet;
1181 }
1182
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001183 private void doIpClientProvisioningWithPreconnectionTest(
1184 final boolean shouldReplyRapidCommitAck, final boolean shouldAbortPreconnection,
1185 final boolean shouldFirePreconnectionTimeout,
1186 final boolean timeoutBeforePreconnectionComplete) throws Exception {
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001187 final long currentTime = System.currentTimeMillis();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001188 final ArgumentCaptor<InterfaceConfigurationParcel> ifConfig =
1189 ArgumentCaptor.forClass(InterfaceConfigurationParcel.class);
1190
1191 startIpClientProvisioning(true /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001192 shouldReplyRapidCommitAck, true /* isDhcpPreConnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001193 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Ma96147b72020-05-06 19:09:38 +09001194 DhcpPacket packet = assertDiscoverPacketOnPreconnectionStart();
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001195 final int preconnDiscoverTransId = packet.getTransactionId();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001196
1197 if (shouldAbortPreconnection) {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001198 if (shouldFirePreconnectionTimeout && timeoutBeforePreconnectionComplete) {
1199 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1200 }
1201
1202 mIpc.notifyPreconnectionComplete(false /* abort */);
Chalard Jean23a06302020-06-26 00:41:00 +09001203 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001204
1205 if (shouldFirePreconnectionTimeout && !timeoutBeforePreconnectionComplete) {
1206 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1207 }
1208
1209 // Either way should get DhcpClient go back to INIT state, and broadcast
1210 // DISCOVER with new transaction ID.
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001211 packet = getNextDhcpPacket();
1212 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001213 assertTrue(packet.getTransactionId() != preconnDiscoverTransId);
1214 } else if (shouldFirePreconnectionTimeout && timeoutBeforePreconnectionComplete) {
1215 // If timeout fires before success preconnection, DhcpClient will go back to INIT state,
1216 // and broadcast DISCOVER with new transaction ID.
1217 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1218 packet = getNextDhcpPacket();
1219 assertTrue(packet instanceof DhcpDiscoverPacket);
1220 assertTrue(packet.getTransactionId() != preconnDiscoverTransId);
1221 // any old response would be ignored due to mismatched transaction ID.
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001222 }
1223
1224 final short mtu = (short) TEST_DEFAULT_MTU;
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001225 if (!shouldReplyRapidCommitAck) {
Xiao Ma6e2818b2020-06-22 01:18:22 +09001226 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR,
1227 TEST_LEASE_DURATION_S, mtu, null /* captivePortalUrl */));
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001228 packet = getNextDhcpPacket();
1229 assertTrue(packet instanceof DhcpRequestPacket);
1230 }
Xiao Ma8bbceb42019-10-08 16:21:07 +09001231 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, TEST_LEASE_DURATION_S,
1232 mtu, shouldReplyRapidCommitAck, null /* captivePortalUrl */));
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001233
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001234 if (!shouldAbortPreconnection) {
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001235 mIpc.notifyPreconnectionComplete(true /* success */);
Chalard Jean23a06302020-06-26 00:41:00 +09001236 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001237
1238 // If timeout fires after successful preconnection, right now DhcpClient will have
1239 // already entered BOUND state, the delayed CMD_TIMEOUT command would be ignored. So
1240 // this case should be very rare, because the timeout alarm is cancelled when state
1241 // machine exits from Preconnecting state.
1242 if (shouldFirePreconnectionTimeout && !timeoutBeforePreconnectionComplete) {
1243 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT);
1244 }
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001245 }
1246 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
1247
1248 final LinkAddress ipAddress = new LinkAddress(CLIENT_ADDR, PREFIX_LENGTH);
1249 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetCfg(ifConfig.capture());
1250 assertEquals(ifConfig.getValue().ifName, mIfaceName);
1251 assertEquals(ifConfig.getValue().ipv4Addr, ipAddress.getAddress().getHostAddress());
1252 assertEquals(ifConfig.getValue().prefixLength, PREFIX_LENGTH);
1253 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
1254 }
1255
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001256 private ArpPacket getNextArpPacket(final long timeout) throws Exception {
Xiao Ma7d733952019-07-02 18:55:11 +09001257 byte[] packet;
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001258 while ((packet = mArpPacketReadHead.getValue().poll(timeout, p -> true)) != null) {
Xiao Ma7d733952019-07-02 18:55:11 +09001259 final ArpPacket arpPacket = parseArpPacketOrNull(packet);
1260 if (arpPacket != null) return arpPacket;
1261 }
1262 return null;
1263 }
1264
1265 private ArpPacket getNextArpPacket() throws Exception {
1266 final ArpPacket packet = getNextArpPacket(PACKET_TIMEOUT_MS);
1267 assertNotNull("No expected ARP packet received on interface within timeout", packet);
1268 return packet;
1269 }
1270
1271 private void assertArpPacket(final ArpPacket packet) {
1272 assertEquals(packet.opCode, ARP_REQUEST);
1273 assertEquals(packet.targetIp, CLIENT_ADDR);
1274 assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac));
1275 }
1276
1277 private void assertArpProbe(final ArpPacket packet) {
1278 assertArpPacket(packet);
1279 assertEquals(packet.senderIp, INADDR_ANY);
1280 }
1281
1282 private void assertArpAnnounce(final ArpPacket packet) {
1283 assertArpPacket(packet);
1284 assertEquals(packet.senderIp, CLIENT_ADDR);
1285 }
1286
Xiao Ma8a0b7672021-04-19 08:33:29 +00001287 private void assertGratuitousARP(final ArpPacket packet) {
1288 assertEquals(packet.opCode, ARP_REPLY);
1289 assertEquals(packet.senderIp, CLIENT_ADDR);
1290 assertEquals(packet.targetIp, CLIENT_ADDR);
1291 assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac));
1292 assertTrue(Arrays.equals(packet.targetHwAddress.toByteArray(), ETHER_BROADCAST));
1293 }
1294
Xiao Ma7d733952019-07-02 18:55:11 +09001295 private void doIpAddressConflictDetectionTest(final boolean causeIpAddressConflict,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001296 final boolean shouldReplyRapidCommitAck, final boolean isDhcpIpConflictDetectEnabled,
Xiao Ma7d733952019-07-02 18:55:11 +09001297 final boolean shouldResponseArpReply) throws Exception {
1298 final long currentTime = System.currentTimeMillis();
1299
1300 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001301 true /* isDhcpLeaseCacheEnabled */, shouldReplyRapidCommitAck,
Xiao Ma7d733952019-07-02 18:55:11 +09001302 TEST_DEFAULT_MTU, isDhcpIpConflictDetectEnabled);
1303
1304 // If we receive an ARP packet here, it's guaranteed to be from IP conflict detection,
1305 // because at this time the test interface does not have an IP address and therefore
1306 // won't send ARP for anything.
1307 if (causeIpAddressConflict) {
1308 final ArpPacket arpProbe = getNextArpPacket();
1309 assertArpProbe(arpProbe);
1310
1311 if (shouldResponseArpReply) {
1312 sendArpReply(mClientMac);
1313 } else {
1314 sendArpProbe();
1315 }
1316 final DhcpPacket packet = getNextDhcpPacket();
1317 assertTrue(packet instanceof DhcpDeclinePacket);
1318 assertEquals(packet.mServerIdentifier, SERVER_ADDR);
1319 assertEquals(packet.mRequestedIp, CLIENT_ADDR);
Xiao Ma16b21ef2020-01-22 17:51:26 +09001320
1321 verify(mCb, never()).onProvisioningFailure(any());
Xiao Ma7d733952019-07-02 18:55:11 +09001322 assertIpMemoryNeverStoreNetworkAttributes();
1323 } else if (isDhcpIpConflictDetectEnabled) {
1324 int arpPacketCount = 0;
1325 final List<ArpPacket> packetList = new ArrayList<ArpPacket>();
1326 // Total sent ARP packets should be 5 (3 ARP Probes + 2 ARP Announcements)
1327 ArpPacket packet;
1328 while ((packet = getNextArpPacket(TEST_TIMEOUT_MS)) != null) {
1329 packetList.add(packet);
1330 }
1331 assertEquals(5, packetList.size());
1332 assertArpProbe(packetList.get(0));
1333 assertArpAnnounce(packetList.get(3));
Xiao Ma4edc4f62020-05-21 10:32:47 +09001334 } else {
Xiao Ma872b2362020-05-27 12:10:40 +09001335 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma7d733952019-07-02 18:55:11 +09001336 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime,
1337 TEST_DEFAULT_MTU);
1338 }
1339 }
1340
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001341 @Test @SignatureRequiredTest(reason = "InterfaceParams.getByName requires CAP_NET_ADMIN")
Lorenzo Colitti32336c92020-02-19 19:53:59 +09001342 public void testInterfaceParams() throws Exception {
1343 InterfaceParams params = InterfaceParams.getByName(mIfaceName);
1344 assertNotNull(params);
1345 assertEquals(mIfaceName, params.name);
1346 assertTrue(params.index > 0);
1347 assertNotNull(params.macAddr);
1348 assertTrue(params.hasMacAddress);
1349
Hongguang Chenebb78392020-07-28 15:34:05 -07001350 // Check interface "lo".
Lorenzo Colitti32336c92020-02-19 19:53:59 +09001351 params = InterfaceParams.getByName("lo");
1352 assertNotNull(params);
1353 assertEquals("lo", params.name);
1354 assertTrue(params.index > 0);
1355 assertNotNull(params.macAddr);
1356 assertFalse(params.hasMacAddress);
1357 }
1358
1359 @Test
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001360 public void testDhcpInit() throws Exception {
Xiao Mac00a7932019-06-03 10:30:04 +09001361 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001362 false /* shouldReplyRapidCommitAck */, false /* isPreconnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001363 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mac00a7932019-06-03 10:30:04 +09001364 final DhcpPacket packet = getNextDhcpPacket();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001365 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001366 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001367
Xiao Ma927a8912021-01-07 08:05:02 +00001368 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001369 public void testHandleSuccessDhcpLease() throws Exception {
1370 final long currentTime = System.currentTimeMillis();
1371 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001372 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001373 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001374 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001375 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001376 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001377
Xiao Ma927a8912021-01-07 08:05:02 +00001378 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001379 public void testHandleFailureDhcpLease() throws Exception {
1380 performDhcpHandshake(false /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001381 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001382 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma16b21ef2020-01-22 17:51:26 +09001383
1384 verify(mCb, never()).onProvisioningSuccess(any());
Xiao Mac00a7932019-06-03 10:30:04 +09001385 assertIpMemoryNeverStoreNetworkAttributes();
1386 }
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001387
Xiao Ma927a8912021-01-07 08:05:02 +00001388 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001389 public void testHandleInfiniteLease() throws Exception {
1390 final long currentTime = System.currentTimeMillis();
1391 performDhcpHandshake(true /* isSuccessLease */, INFINITE_LEASE,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001392 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001393 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001394 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001395 assertIpMemoryStoreNetworkAttributes(INFINITE_LEASE, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001396 }
1397
Xiao Ma927a8912021-01-07 08:05:02 +00001398 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001399 public void testHandleNoLease() throws Exception {
1400 final long currentTime = System.currentTimeMillis();
1401 performDhcpHandshake(true /* isSuccessLease */, null /* no lease time */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001402 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001403 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001404 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001405 assertIpMemoryStoreNetworkAttributes(null, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001406 }
1407
Xiao Mafa33d492020-05-15 21:59:00 +09001408 @Test @IgnoreAfter(Build.VERSION_CODES.Q) // INIT-REBOOT is enabled on R.
Xiao Mac00a7932019-06-03 10:30:04 +09001409 public void testHandleDisableInitRebootState() throws Exception {
1410 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001411 false /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001412 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001413 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Mac00a7932019-06-03 10:30:04 +09001414 assertIpMemoryNeverStoreNetworkAttributes();
1415 }
1416
Xiao Ma927a8912021-01-07 08:05:02 +00001417 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001418 public void testHandleRapidCommitOption() throws Exception {
Xiao Mac00a7932019-06-03 10:30:04 +09001419 final long currentTime = System.currentTimeMillis();
1420 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001421 true /* isDhcpLeaseCacheEnabled */, true /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09001422 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001423 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001424 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
Xiao Mac00a7932019-06-03 10:30:04 +09001425 }
1426
Xiao Ma8d645772022-03-15 01:19:16 +00001427 @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
Xiao Ma7ae2ec32021-09-29 06:07:15 +00001428 public void testRollbackFromRapidCommitOption() throws Exception {
1429 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
1430 true /* isDhcpRapidCommitEnabled */, false /* isPreConnectionEnabled */,
1431 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
1432
1433 final List<DhcpPacket> discoverList = new ArrayList<DhcpPacket>();
1434 DhcpPacket packet;
1435 do {
1436 packet = getNextDhcpPacket();
1437 assertTrue(packet instanceof DhcpDiscoverPacket);
1438 discoverList.add(packet);
1439 } while (discoverList.size() < 4);
1440
1441 // Check the only first 3 DHCPDISCOVERs take rapid commit option.
1442 assertTrue(discoverList.get(0).mRapidCommit);
1443 assertTrue(discoverList.get(1).mRapidCommit);
1444 assertTrue(discoverList.get(2).mRapidCommit);
1445 assertFalse(discoverList.get(3).mRapidCommit);
1446 }
1447
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001448 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001449 public void testDhcpClientStartWithCachedInfiniteLease() throws Exception {
1450 final DhcpPacket packet = getReplyFromDhcpLease(
1451 new NetworkAttributes.Builder()
1452 .setAssignedV4Address(CLIENT_ADDR)
1453 .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001454 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001455 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001456 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1457 .build(), false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001458 assertTrue(packet instanceof DhcpRequestPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001459 }
1460
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001461 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001462 public void testDhcpClientStartWithCachedExpiredLease() throws Exception {
1463 final DhcpPacket packet = getReplyFromDhcpLease(
1464 new NetworkAttributes.Builder()
1465 .setAssignedV4Address(CLIENT_ADDR)
1466 .setAssignedV4AddressExpiry(EXPIRED_LEASE)
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001467 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001468 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001469 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1470 .build(), false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001471 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001472 }
1473
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001474 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001475 public void testDhcpClientStartWithNullRetrieveNetworkAttributes() throws Exception {
1476 final DhcpPacket packet = getReplyFromDhcpLease(null /* na */, false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001477 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001478 }
1479
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001480 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001481 public void testDhcpClientStartWithTimeoutRetrieveNetworkAttributes() throws Exception {
1482 final DhcpPacket packet = getReplyFromDhcpLease(
1483 new NetworkAttributes.Builder()
1484 .setAssignedV4Address(CLIENT_ADDR)
1485 .setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000)
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001486 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001487 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001488 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1489 .build(), true /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001490 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001491 }
1492
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001493 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Mac00a7932019-06-03 10:30:04 +09001494 public void testDhcpClientStartWithCachedLeaseWithoutIPAddress() throws Exception {
1495 final DhcpPacket packet = getReplyFromDhcpLease(
1496 new NetworkAttributes.Builder()
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001497 .setMtu(new Integer(TEST_DEFAULT_MTU))
Chalard Jeanb2896832020-05-13 19:16:49 +09001498 .setCluster(TEST_CLUSTER)
Xiao Mac00a7932019-06-03 10:30:04 +09001499 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
1500 .build(), false /* timeout */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001501 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Mac00a7932019-06-03 10:30:04 +09001502 }
1503
Xiao Ma927a8912021-01-07 08:05:02 +00001504 @Test
Xiao Mac00a7932019-06-03 10:30:04 +09001505 public void testDhcpClientRapidCommitEnabled() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00001506 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09001507 true /* shouldReplyRapidCommitAck */, false /* isPreconnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00001508 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mac00a7932019-06-03 10:30:04 +09001509 final DhcpPacket packet = getNextDhcpPacket();
Xiao Ma4a8d1d42019-07-19 10:39:06 +09001510 assertTrue(packet instanceof DhcpDiscoverPacket);
Xiao Ma53ed1ac2019-06-03 15:48:39 +09001511 }
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001512
Lorenzo Colitti46a78742020-04-02 20:21:16 +09001513 @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
1514 public void testDhcpServerInLinkProperties() throws Exception {
Lorenzo Colitti75aac042020-04-24 17:01:37 +09001515 assumeTrue(ConstantsShim.VERSION > Build.VERSION_CODES.Q);
1516
Lorenzo Colitti46a78742020-04-02 20:21:16 +09001517 performDhcpHandshake();
1518 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
1519 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
1520 assertEquals(SERVER_ADDR, captor.getValue().getDhcpServerAddress());
1521 }
1522
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001523 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001524 public void testRestoreInitialInterfaceMtu() throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001525 doRestoreInitialMtuTest(true /* shouldChangeMtu */, false /* shouldRemoveTestInterface */);
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001526 }
1527
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001528 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma619c28c2019-08-23 16:47:22 +09001529 public void testRestoreInitialInterfaceMtu_WithoutMtuChange() throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001530 doRestoreInitialMtuTest(false /* shouldChangeMtu */, false /* shouldRemoveTestInterface */);
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001531 }
1532
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001533 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma619c28c2019-08-23 16:47:22 +09001534 public void testRestoreInitialInterfaceMtu_WithException() throws Exception {
Lorenzo Colitti1e868b32019-11-29 16:17:58 +09001535 doThrow(new RemoteException("NetdNativeService::interfaceSetMtu")).when(mNetd)
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001536 .interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU);
1537
Xiao Maac371ef2021-09-15 03:37:41 +00001538 doRestoreInitialMtuTest(true /* shouldChangeMtu */, false /* shouldRemoveTestInterface */);
Xiao Ma1ef8fd82019-07-16 19:16:39 +09001539 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_MIN_MTU);
1540 }
Xiao Ma619c28c2019-08-23 16:47:22 +09001541
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001542 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma619c28c2019-08-23 16:47:22 +09001543 public void testRestoreInitialInterfaceMtu_NotFoundInterfaceWhenStopping() throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001544 doRestoreInitialMtuTest(true /* shouldChangeMtu */, true /* shouldRemoveTestInterface */);
Xiao Ma619c28c2019-08-23 16:47:22 +09001545 }
1546
Xiao Ma927a8912021-01-07 08:05:02 +00001547 @Test
Xiao Ma619c28c2019-08-23 16:47:22 +09001548 public void testRestoreInitialInterfaceMtu_NotFoundInterfaceWhenStartingProvisioning()
1549 throws Exception {
Xiao Maac371ef2021-09-15 03:37:41 +00001550 removeTestInterface(mTapFd);
Xiao Ma619c28c2019-08-23 16:47:22 +09001551 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1552 .withoutIpReachabilityMonitor()
1553 .withoutIPv6()
1554 .build();
1555
Xiao Ma927a8912021-01-07 08:05:02 +00001556 startIpClientProvisioning(config);
Xiao Ma5c110212020-03-29 16:11:47 +09001557 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
Xiao Ma619c28c2019-08-23 16:47:22 +09001558 verify(mCb, never()).setNeighborDiscoveryOffload(true);
1559 }
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001560
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001561 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma5c110212020-03-29 16:11:47 +09001562 public void testRestoreInitialInterfaceMtu_stopIpClientAndRestart() throws Exception {
1563 long currentTime = System.currentTimeMillis();
1564
1565 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
1566 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
1567 TEST_MIN_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001568 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma5c110212020-03-29 16:11:47 +09001569 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_MIN_MTU);
1570
1571 // Pretend that ConnectivityService set the MTU.
1572 mNetd.interfaceSetMtu(mIfaceName, TEST_MIN_MTU);
1573 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_MIN_MTU);
1574
1575 reset(mCb);
1576 reset(mIpMemoryStore);
1577
1578 // Stop IpClient and then restart provisioning immediately.
1579 mIpc.stop();
1580 currentTime = System.currentTimeMillis();
1581 // Intend to set mtu option to 0, then verify that won't influence interface mtu restore.
1582 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
1583 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
1584 0 /* mtu */, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09001585 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma5c110212020-03-29 16:11:47 +09001586 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, 0 /* mtu */);
1587 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_DEFAULT_MTU);
1588 }
1589
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001590 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7dc8ef82020-08-13 15:25:06 +09001591 public void testRestoreInitialInterfaceMtu_removeInterfaceAndAddback() throws Exception {
1592 doAnswer(invocation -> {
1593 final LinkProperties lp = invocation.getArgument(0);
1594 assertEquals(lp.getInterfaceName(), mIfaceName);
1595 assertEquals(0, lp.getLinkAddresses().size());
1596 assertEquals(0, lp.getDnsServers().size());
1597
1598 mDependencies.simulateInterfaceRecover();
1599 return null;
1600 }).when(mCb).onProvisioningFailure(any());
1601
1602 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1603 .withoutIpReachabilityMonitor()
1604 .withoutIPv6()
1605 .build();
1606
1607 // Intend to remove the tap interface and force IpClient throw provisioning failure
1608 // due to that interface is not found.
Xiao Maac371ef2021-09-15 03:37:41 +00001609 removeTestInterface(mTapFd);
Xiao Ma7dc8ef82020-08-13 15:25:06 +09001610 assertNull(InterfaceParams.getByName(mIfaceName));
1611
Xiao Ma927a8912021-01-07 08:05:02 +00001612 startIpClientProvisioning(config);
Xiao Ma7dc8ef82020-08-13 15:25:06 +09001613 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
1614
1615 // Make sure everything queued by this test was processed (e.g. transition to StoppingState
1616 // from ClearingIpAddressState) and tearDown will check if IpClient exits normally or crash.
1617 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
1618 }
1619
Xiao Ma60175d22021-06-02 12:28:40 +00001620 private boolean isIcmpv6PacketOfType(final byte[] packetBytes, int type) {
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001621 ByteBuffer packet = ByteBuffer.wrap(packetBytes);
1622 return packet.getShort(ETHER_TYPE_OFFSET) == (short) ETH_P_IPV6
1623 && packet.get(ETHER_HEADER_LEN + IPV6_PROTOCOL_OFFSET) == (byte) IPPROTO_ICMPV6
Xiao Ma60175d22021-06-02 12:28:40 +00001624 && packet.get(ETHER_HEADER_LEN + IPV6_HEADER_LEN) == (byte) type;
1625 }
1626
1627 private boolean isRouterSolicitation(final byte[] packetBytes) {
1628 return isIcmpv6PacketOfType(packetBytes, ICMPV6_ROUTER_SOLICITATION);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001629 }
1630
Xiao Ma002dd5a2020-12-22 01:14:49 +00001631 private boolean isNeighborAdvertisement(final byte[] packetBytes) {
Xiao Ma60175d22021-06-02 12:28:40 +00001632 return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_ADVERTISEMENT);
1633 }
1634
1635 private boolean isNeighborSolicitation(final byte[] packetBytes) {
1636 return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_SOLICITATION);
Xiao Ma002dd5a2020-12-22 01:14:49 +00001637 }
1638
1639 private NeighborAdvertisement getNextNeighborAdvertisement() throws ParseException {
1640 final byte[] packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS,
1641 this::isNeighborAdvertisement);
1642 if (packet == null) return null;
1643
1644 final NeighborAdvertisement na = parseNeighborAdvertisementOrNull(packet);
1645 assertNotNull("Invalid neighbour advertisement received", na);
1646 return na;
1647 }
1648
Xiao Ma60175d22021-06-02 12:28:40 +00001649 private NeighborSolicitation getNextNeighborSolicitation() throws ParseException {
1650 final byte[] packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS,
1651 this::isNeighborSolicitation);
1652 if (packet == null) return null;
1653
1654 final NeighborSolicitation ns = parseNeighborSolicitationOrNull(packet);
1655 assertNotNull("Invalid neighbour solicitation received", ns);
1656 return ns;
1657 }
1658
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001659 private void waitForRouterSolicitation() throws ParseException {
Remi NGUYEN VAN0a867502020-06-18 17:08:08 +09001660 assertNotNull("No router solicitation received on interface within timeout",
Lorenzo Colitti8eacfac2020-08-17 16:19:21 +09001661 mPacketReader.popPacket(PACKET_TIMEOUT_MS, this::isRouterSolicitation));
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001662 }
1663
Xiao Ma4edc4f62020-05-21 10:32:47 +09001664 private void sendRouterAdvertisement(boolean waitForRs, short lifetime) throws Exception {
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001665 final String dnsServer = "2001:4860:4860::64";
1666 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
1667 ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
Xiao Ma4edc4f62020-05-21 10:32:47 +09001668 ByteBuffer ra = buildRaPacket(lifetime, pio, rdnss);
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001669
1670 if (waitForRs) {
1671 waitForRouterSolicitation();
1672 }
1673
1674 mPacketReader.sendResponse(ra);
1675 }
1676
Xiao Ma4edc4f62020-05-21 10:32:47 +09001677 private void sendBasicRouterAdvertisement(boolean waitForRs) throws Exception {
1678 sendRouterAdvertisement(waitForRs, (short) 1800);
1679 }
1680
1681 private void sendRouterAdvertisementWithZeroLifetime() throws Exception {
1682 sendRouterAdvertisement(false /* waitForRs */, (short) 0);
1683 }
1684
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001685 // TODO: move this and the following method to a common location and use them in ApfTest.
1686 private static ByteBuffer buildPioOption(int valid, int preferred, String prefixString)
1687 throws Exception {
Xiao Maaf321442021-02-05 09:04:42 +00001688 return PrefixInformationOption.build(new IpPrefix(prefixString),
Xiao Ma002dd5a2020-12-22 01:14:49 +00001689 (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), valid, preferred);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001690 }
1691
1692 private static ByteBuffer buildRdnssOption(int lifetime, String... servers) throws Exception {
Xiao Maaf321442021-02-05 09:04:42 +00001693 return RdnssOption.build(lifetime, servers);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001694 }
1695
Xiao Ma60175d22021-06-02 12:28:40 +00001696 private static ByteBuffer buildSllaOption() throws Exception {
1697 return LlaOption.build((byte) ICMPV6_ND_OPTION_SLLA, ROUTER_MAC);
1698 }
1699
Xiao Ma4edc4f62020-05-21 10:32:47 +09001700 private static ByteBuffer buildRaPacket(short lifetime, ByteBuffer... options)
1701 throws Exception {
Xiao Ma60175d22021-06-02 12:28:40 +00001702 final MacAddress dstMac =
1703 NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST);
1704 return Ipv6Utils.buildRaPacket(ROUTER_MAC /* srcMac */, dstMac,
1705 ROUTER_LINK_LOCAL /* srcIp */, IPV6_ADDR_ALL_NODES_MULTICAST /* dstIp */,
1706 (byte) 0 /* M=0, O=0 */, lifetime, 0 /* Reachable time, unspecified */,
1707 100 /* Retrans time 100ms */, options);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001708 }
1709
Xiao Ma4edc4f62020-05-21 10:32:47 +09001710 private static ByteBuffer buildRaPacket(ByteBuffer... options) throws Exception {
1711 return buildRaPacket((short) 1800, options);
1712 }
1713
Lorenzo Colittibd919742020-04-24 23:16:49 +09001714 private void disableIpv6ProvisioningDelays() throws Exception {
1715 // Speed up the test by disabling DAD and removing router_solicitation_delay.
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001716 // We don't need to restore the default value because the interface is removed in tearDown.
Lorenzo Colittibd919742020-04-24 23:16:49 +09001717 // TODO: speed up further by not waiting for RS but keying off first IPv6 packet.
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001718 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "router_solicitation_delay", "0");
Lorenzo Colittibd919742020-04-24 23:16:49 +09001719 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits", "0");
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001720 }
1721
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001722 private void assertHasAddressThat(String msg, LinkProperties lp,
1723 Predicate<LinkAddress> condition) {
1724 for (LinkAddress addr : lp.getLinkAddresses()) {
1725 if (condition.test(addr)) {
1726 return;
1727 }
1728 }
1729 fail(msg + " not found in: " + lp);
1730 }
1731
1732 private boolean hasFlag(LinkAddress addr, int flag) {
1733 return (addr.getFlags() & flag) == flag;
1734 }
1735
1736 private boolean isPrivacyAddress(LinkAddress addr) {
1737 return addr.isGlobalPreferred() && hasFlag(addr, IFA_F_TEMPORARY);
1738 }
1739
1740 private boolean isStablePrivacyAddress(LinkAddress addr) {
Xiao Maebc22a82021-08-13 06:34:39 +00001741 // The Q netd does not understand the IFA_F_STABLE_PRIVACY flag.
1742 // See r.android.com/1295670.
1743 final int flag = (mIsNetlinkEventParseEnabled || ShimUtils.isAtLeastR())
1744 ? IFA_F_STABLE_PRIVACY : 0;
Lorenzo Colitti558eb962020-04-27 11:43:23 +09001745 return addr.isGlobalPreferred() && hasFlag(addr, flag);
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001746 }
1747
Xiao Ma8a0b7672021-04-19 08:33:29 +00001748 private LinkProperties doIpv6OnlyProvisioning() throws Exception {
1749 final InOrder inOrder = inOrder(mCb);
1750 final String dnsServer = "2001:4860:4860::64";
1751 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
1752 final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
Xiao Ma60175d22021-06-02 12:28:40 +00001753 final ByteBuffer slla = buildSllaOption();
1754 final ByteBuffer ra = buildRaPacket(pio, rdnss, slla);
Xiao Ma8a0b7672021-04-19 08:33:29 +00001755
1756 return doIpv6OnlyProvisioning(inOrder, ra);
1757 }
1758
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001759 private LinkProperties doIpv6OnlyProvisioning(InOrder inOrder, ByteBuffer ra) throws Exception {
1760 waitForRouterSolicitation();
1761 mPacketReader.sendResponse(ra);
1762
1763 // The lambda below needs to write a LinkProperties to a local variable, but lambdas cannot
1764 // write to non-final local variables. So declare a final variable to write to.
1765 final AtomicReference<LinkProperties> lpRef = new AtomicReference<>();
1766
1767 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
1768 verifyWithTimeout(inOrder, mCb).onProvisioningSuccess(captor.capture());
1769 lpRef.set(captor.getValue());
1770
1771 // Sometimes provisioning completes as soon as the link-local and the stable address appear,
1772 // before the privacy address appears. If so, wait here for the LinkProperties update that
1773 // contains all three address. Otherwise, future calls to verify() might get confused.
1774 if (captor.getValue().getLinkAddresses().size() == 2) {
1775 verifyWithTimeout(inOrder, mCb).onLinkPropertiesChange(argThat(lp -> {
1776 lpRef.set(lp);
1777 return lp.getLinkAddresses().size() == 3;
1778 }));
1779 }
1780
1781 LinkProperties lp = lpRef.get();
1782 assertEquals("Should have 3 IPv6 addresses after provisioning: " + lp,
1783 3, lp.getLinkAddresses().size());
1784 assertHasAddressThat("link-local address", lp, x -> x.getAddress().isLinkLocalAddress());
1785 assertHasAddressThat("privacy address", lp, this::isPrivacyAddress);
1786 assertHasAddressThat("stable privacy address", lp, this::isStablePrivacyAddress);
1787
1788 return lp;
1789 }
1790
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001791 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001792 public void testRaRdnss() throws Exception {
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001793 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1794 .withoutIpReachabilityMonitor()
1795 .withoutIPv4()
1796 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00001797 startIpClientProvisioning(config);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001798
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001799 InOrder inOrder = inOrder(mCb);
1800 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
1801
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001802 final String dnsServer = "2001:4860:4860::64";
1803 final String lowlifeDnsServer = "2001:4860:4860::6464";
1804
1805 final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64");
1806 ByteBuffer rdnss1 = buildRdnssOption(60, lowlifeDnsServer);
1807 ByteBuffer rdnss2 = buildRdnssOption(600, dnsServer);
1808 ByteBuffer ra = buildRaPacket(pio, rdnss1, rdnss2);
1809
Lorenzo Colitti5e384442020-04-26 20:18:04 +09001810 LinkProperties lp = doIpv6OnlyProvisioning(inOrder, ra);
Lorenzo Colitti2cdb76a2020-04-25 01:11:50 +09001811
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +09001812 // Expect that DNS servers with lifetimes below CONFIG_MIN_RDNSS_LIFETIME are not accepted.
1813 assertNotNull(lp);
1814 assertEquals(1, lp.getDnsServers().size());
1815 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +09001816
1817 // If the RDNSS lifetime is above the minimum, the DNS server is accepted.
1818 rdnss1 = buildRdnssOption(68, lowlifeDnsServer);
1819 ra = buildRaPacket(pio, rdnss1, rdnss2);
Lorenzo Colitti32215002020-03-13 19:40:32 +09001820 mPacketReader.sendResponse(ra);
Lorenzo Colitti2cdb76a2020-04-25 01:11:50 +09001821 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(captor.capture());
Lorenzo Colitti7d5191f2019-09-26 00:18:25 +09001822 lp = captor.getValue();
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001823 assertNotNull(lp);
1824 assertEquals(2, lp.getDnsServers().size());
1825 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
1826 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(lowlifeDnsServer)));
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001827
1828 // Expect that setting RDNSS lifetime of 0 causes loss of provisioning.
1829 rdnss1 = buildRdnssOption(0, dnsServer);
1830 rdnss2 = buildRdnssOption(0, lowlifeDnsServer);
1831 ra = buildRaPacket(pio, rdnss1, rdnss2);
Lorenzo Colitti32215002020-03-13 19:40:32 +09001832 mPacketReader.sendResponse(ra);
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001833
Lorenzo Colitti2cdb76a2020-04-25 01:11:50 +09001834 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
Lorenzo Colitti82a3cf62019-11-02 23:36:41 +09001835 lp = captor.getValue();
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09001836 assertNotNull(lp);
1837 assertEquals(0, lp.getDnsServers().size());
1838 reset(mCb);
1839 }
1840
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001841 private void expectNat64PrefixUpdate(InOrder inOrder, IpPrefix expected) throws Exception {
1842 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(
1843 argThat(lp -> Objects.equals(expected, lp.getNat64Prefix())));
1844
1845 }
1846
1847 private void expectNoNat64PrefixUpdate(InOrder inOrder, IpPrefix unchanged) throws Exception {
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001848 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS).times(0)).onLinkPropertiesChange(argThat(
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001849 lp -> !Objects.equals(unchanged, lp.getNat64Prefix())));
1850
1851 }
1852
1853 @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09001854 @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001855 public void testPref64Option() throws Exception {
Lorenzo Colitti75aac042020-04-24 17:01:37 +09001856 assumeTrue(ConstantsShim.VERSION > Build.VERSION_CODES.Q);
1857
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001858 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
1859 .withoutIpReachabilityMonitor()
1860 .withoutIPv4()
1861 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00001862 startIpClientProvisioning(config);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001863
1864 final String dnsServer = "2001:4860:4860::64";
1865 final IpPrefix prefix = new IpPrefix("64:ff9b::/96");
1866 final IpPrefix otherPrefix = new IpPrefix("2001:db8:64::/96");
1867
1868 final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64");
1869 ByteBuffer rdnss = buildRdnssOption(600, dnsServer);
1870 ByteBuffer pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer();
1871 ByteBuffer ra = buildRaPacket(pio, rdnss, pref64);
1872
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001873 // The NAT64 prefix might be detected before or after provisioning success.
1874 // Don't test order between these two events.
Lorenzo Colittic84530f2020-04-27 10:15:29 +09001875 LinkProperties lp = doIpv6OnlyProvisioning(null /*inOrder*/, ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001876 expectAlarmSet(null /*inOrder*/, "PREF64", 600);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001877
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001878 // From now on expect events in order.
1879 InOrder inOrder = inOrder(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001880 if (lp.getNat64Prefix() != null) {
1881 assertEquals(prefix, lp.getNat64Prefix());
1882 } else {
1883 expectNat64PrefixUpdate(inOrder, prefix);
1884 }
1885
1886 // Increase the lifetime and expect the prefix not to change.
1887 pref64 = new StructNdOptPref64(prefix, 1800).toByteBuffer();
1888 ra = buildRaPacket(pio, rdnss, pref64);
1889 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001890 OnAlarmListener pref64Alarm = expectAlarmSet(inOrder, "PREF64", 1800);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001891 expectNoNat64PrefixUpdate(inOrder, prefix);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001892 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001893
Lorenzo Colitti21957512020-04-24 01:06:55 +09001894 // Reduce the lifetime and expect to reschedule expiry.
1895 pref64 = new StructNdOptPref64(prefix, 1500).toByteBuffer();
1896 ra = buildRaPacket(pio, rdnss, pref64);
1897 mPacketReader.sendResponse(ra);
1898 pref64Alarm = expectAlarmSet(inOrder, "PREF64", 1496);
1899 expectNoNat64PrefixUpdate(inOrder, prefix);
1900 reset(mCb, mAlarm);
1901
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001902 // Withdraw the prefix and expect it to be set to null.
1903 pref64 = new StructNdOptPref64(prefix, 0).toByteBuffer();
1904 ra = buildRaPacket(pio, rdnss, pref64);
1905 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001906 expectAlarmCancelled(inOrder, pref64Alarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001907 expectNat64PrefixUpdate(inOrder, null);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001908 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001909
1910 // Re-announce the prefix.
1911 pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer();
1912 ra = buildRaPacket(pio, rdnss, pref64);
1913 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001914 expectAlarmSet(inOrder, "PREF64", 600);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001915 expectNat64PrefixUpdate(inOrder, prefix);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001916 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001917
1918 // Announce two prefixes. Don't expect any update because if there is already a NAT64
1919 // prefix, any new prefix is ignored.
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001920 ByteBuffer otherPref64 = new StructNdOptPref64(otherPrefix, 1200).toByteBuffer();
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001921 ra = buildRaPacket(pio, rdnss, pref64, otherPref64);
1922 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001923 expectAlarmSet(inOrder, "PREF64", 600);
1924 expectNoNat64PrefixUpdate(inOrder, prefix);
1925 reset(mCb, mAlarm);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001926
Lorenzo Colitti21957512020-04-24 01:06:55 +09001927 // Withdraw the old prefix and continue to announce the new one. Expect a prefix change.
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001928 pref64 = new StructNdOptPref64(prefix, 0).toByteBuffer();
1929 ra = buildRaPacket(pio, rdnss, pref64, otherPref64);
1930 mPacketReader.sendResponse(ra);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001931 expectAlarmCancelled(inOrder, pref64Alarm);
1932 // Need a different OnAlarmListener local variable because posting it to the handler in the
1933 // lambda below requires it to be final.
1934 final OnAlarmListener lastAlarm = expectAlarmSet(inOrder, "PREF64", 1200);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001935 expectNat64PrefixUpdate(inOrder, otherPrefix);
Lorenzo Colitti31c7a512020-04-22 16:03:41 +09001936 reset(mCb, mAlarm);
1937
1938 // Simulate prefix expiry.
1939 mIpc.getHandler().post(() -> lastAlarm.onAlarm());
1940 expectAlarmCancelled(inOrder, pref64Alarm);
1941 expectNat64PrefixUpdate(inOrder, null);
Lorenzo Colitti50862202020-05-04 13:27:37 +09001942
Lorenzo Colitti747f0d12020-05-06 23:27:45 +09001943 // Announce a non-/96 prefix and expect it to be ignored.
1944 IpPrefix invalidPrefix = new IpPrefix("64:ff9b::/64");
1945 pref64 = new StructNdOptPref64(invalidPrefix, 1200).toByteBuffer();
1946 ra = buildRaPacket(pio, rdnss, pref64);
1947 mPacketReader.sendResponse(ra);
1948 expectNoNat64PrefixUpdate(inOrder, invalidPrefix);
1949
Lorenzo Colitti50862202020-05-04 13:27:37 +09001950 // Re-announce the prefix.
1951 pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer();
1952 ra = buildRaPacket(pio, rdnss, pref64);
1953 mPacketReader.sendResponse(ra);
1954 final OnAlarmListener clearAlarm = expectAlarmSet(inOrder, "PREF64", 600);
1955 expectNat64PrefixUpdate(inOrder, prefix);
1956 reset(mCb, mAlarm);
1957
1958 // Check that the alarm is cancelled when IpClient is stopped.
1959 mIpc.stop();
Chalard Jean23a06302020-06-26 00:41:00 +09001960 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Lorenzo Colitti50862202020-05-04 13:27:37 +09001961 expectAlarmCancelled(inOrder, clearAlarm);
1962 expectNat64PrefixUpdate(inOrder, null);
1963
1964 // Check that even if the alarm was already in the message queue while it was cancelled, it
1965 // is safely ignored.
1966 mIpc.getHandler().post(() -> clearAlarm.onAlarm());
Chalard Jean23a06302020-06-26 00:41:00 +09001967 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Lorenzo Colitti70d7ffa2020-04-09 21:02:13 +09001968 }
1969
Xiao Maebc22a82021-08-13 06:34:39 +00001970 private void waitForAddressViaNetworkObserver(final String iface, final String addr1,
1971 final String addr2, int prefixLength) throws Exception {
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001972 final CountDownLatch latch = new CountDownLatch(1);
1973
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09001974 // Add two IPv4 addresses to the specified interface, and proceed when the NetworkObserver
1975 // has seen the second one. This ensures that every other NetworkObserver registered with
1976 // mNetworkObserverRegistry - in particular, IpClient's - has seen the addition of the first
1977 // address.
1978 final LinkAddress trigger = new LinkAddress(addr2 + "/" + prefixLength);
1979 NetworkObserver observer = new NetworkObserver() {
1980 @Override
1981 public void onInterfaceAddressUpdated(LinkAddress address, String ifName) {
1982 if (ifName.equals(iface) && address.isSameAddressAs(trigger)) {
1983 latch.countDown();
1984 }
1985 }
1986 };
1987
1988 mNetworkObserverRegistry.registerObserverForNonblockingCallback(observer);
1989 try {
1990 mNetd.interfaceAddAddress(iface, addr1, prefixLength);
1991 mNetd.interfaceAddAddress(iface, addr2, prefixLength);
1992 assertTrue("Trigger IP address " + addr2 + " not seen after " + TEST_TIMEOUT_MS + "ms",
1993 latch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
1994 } finally {
1995 mNetworkObserverRegistry.unregisterObserver(observer);
1996 }
Xiao Maebc22a82021-08-13 06:34:39 +00001997 }
1998
1999 private void addIpAddressAndWaitForIt(final String iface) throws Exception {
2000 final String addr1 = "192.0.2.99";
2001 final String addr2 = "192.0.2.3";
2002 final int prefixLength = 26;
2003
2004 if (!mIsNetlinkEventParseEnabled) {
2005 waitForAddressViaNetworkObserver(iface, addr1, addr2, prefixLength);
2006 } else {
2007 // IpClient gets IP addresses directly from netlink instead of from netd, unnecessary
2008 // to rely on the NetworkObserver callbacks to confirm new added address update. Just
2009 // add the addresses directly and wait to see if IpClient has seen the address
2010 mNetd.interfaceAddAddress(iface, addr1, prefixLength);
2011 mNetd.interfaceAddAddress(iface, addr2, prefixLength);
2012 }
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002013
2014 // Wait for IpClient to process the addition of the address.
Chalard Jean23a06302020-06-26 00:41:00 +09002015 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002016 }
2017
Xiao Ma15275d72020-06-15 18:59:27 +09002018 private void doIPv4OnlyProvisioningAndExitWithLeftAddress() throws Exception {
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002019 final long currentTime = System.currentTimeMillis();
2020 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002021 true /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
Xiao Ma7d733952019-07-02 18:55:11 +09002022 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */);
Xiao Ma872b2362020-05-27 12:10:40 +09002023 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002024 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2025
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002026 // Stop IpClient and expect a final LinkProperties callback with an empty LP.
Xiao Ma927a8912021-01-07 08:05:02 +00002027 mIIpClient.stop();
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002028 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat(
2029 x -> x.getAddresses().size() == 0
2030 && x.getRoutes().size() == 0
2031 && x.getDnsServers().size() == 0));
2032 reset(mCb);
2033
2034 // Pretend that something else (e.g., Tethering) used the interface and left an IP address
2035 // configured on it. When IpClient starts, it must clear this address before proceeding.
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002036 // The address must be noticed before startProvisioning is called, or IpClient will
2037 // immediately declare provisioning success due to the presence of an IPv4 address.
2038 // The address must be IPv4 because IpClient clears IPv6 addresses on startup.
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002039 addIpAddressAndWaitForIt(mIfaceName);
Xiao Ma15275d72020-06-15 18:59:27 +09002040 }
2041
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002042 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma15275d72020-06-15 18:59:27 +09002043 public void testIpClientClearingIpAddressState() throws Exception {
2044 doIPv4OnlyProvisioningAndExitWithLeftAddress();
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002045
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002046 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2047 .withoutIpReachabilityMonitor()
2048 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00002049 startIpClientProvisioning(config);
Lorenzo Colitti58da4e32020-04-24 21:57:22 +09002050
2051 sendBasicRouterAdvertisement(true /*waitForRs*/);
2052
2053 // Check that the IPv4 addresses configured earlier are not in LinkProperties...
2054 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
2055 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
2056 assertFalse(captor.getValue().hasIpv4Address());
2057
2058 // ... or configured on the interface.
2059 InterfaceConfigurationParcel cfg = mNetd.interfaceGetCfg(mIfaceName);
2060 assertEquals("0.0.0.0", cfg.ipv4Addr);
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09002061 }
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002062
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002063 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma15275d72020-06-15 18:59:27 +09002064 public void testIpClientClearingIpAddressState_enablePreconnection() throws Exception {
2065 doIPv4OnlyProvisioningAndExitWithLeftAddress();
2066
2067 // Enter ClearingIpAddressesState to clear the remaining IPv4 addresses and transition to
2068 // PreconnectionState instead of RunningState.
2069 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
2070 false /* shouldReplyRapidCommitAck */, true /* isDhcpPreConnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002071 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Ma15275d72020-06-15 18:59:27 +09002072 assertDiscoverPacketOnPreconnectionStart();
2073
2074 // Force to enter RunningState.
2075 mIpc.notifyPreconnectionComplete(false /* abort */);
Chalard Jean23a06302020-06-26 00:41:00 +09002076 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma15275d72020-06-15 18:59:27 +09002077 }
2078
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002079 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002080 public void testDhcpClientPreconnection_success() throws Exception {
2081 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2082 false /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2083 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002084 }
2085
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002086 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002087 public void testDhcpClientPreconnection_SuccessWithoutRapidCommit() throws Exception {
2088 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2089 false /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2090 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002091 }
2092
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002093 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002094 public void testDhcpClientPreconnection_Abort() throws Exception {
2095 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2096 true /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2097 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002098 }
2099
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002100 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002101 public void testDhcpClientPreconnection_AbortWithoutRapiCommit() throws Exception {
2102 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2103 true /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */,
2104 false /* timeoutBeforePreconnectionComplete */);
2105 }
2106
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002107 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002108 public void testDhcpClientPreconnection_TimeoutBeforeAbort() throws Exception {
2109 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2110 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2111 true /* timeoutBeforePreconnectionComplete */);
2112 }
2113
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002114 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002115 public void testDhcpClientPreconnection_TimeoutBeforeAbortWithoutRapidCommit()
2116 throws Exception {
2117 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2118 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2119 true /* timeoutBeforePreconnectionComplete */);
2120 }
2121
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002122 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002123 public void testDhcpClientPreconnection_TimeoutafterAbort() throws Exception {
2124 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2125 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2126 false /* timeoutBeforePreconnectionComplete */);
2127 }
2128
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002129 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002130 public void testDhcpClientPreconnection_TimeoutAfterAbortWithoutRapidCommit() throws Exception {
2131 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2132 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2133 false /* timeoutBeforePreconnectionComplete */);
2134 }
2135
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002136 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002137 public void testDhcpClientPreconnection_TimeoutBeforeSuccess() throws Exception {
2138 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2139 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2140 true /* timeoutBeforePreconnectionComplete */);
2141 }
2142
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002143 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002144 public void testDhcpClientPreconnection_TimeoutBeforeSuccessWithoutRapidCommit()
2145 throws Exception {
2146 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2147 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2148 true /* timeoutBeforePreconnectionComplete */);
2149 }
2150
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002151 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002152 public void testDhcpClientPreconnection_TimeoutAfterSuccess() throws Exception {
2153 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */,
2154 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2155 false /* timeoutBeforePreconnectionComplete */);
2156 }
2157
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002158 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002159 public void testDhcpClientPreconnection_TimeoutAfterSuccessWithoutRapidCommit()
2160 throws Exception {
2161 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */,
2162 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */,
2163 false /* timeoutBeforePreconnectionComplete */);
Xiao Ma4a8d1d42019-07-19 10:39:06 +09002164 }
Xiao Ma7d733952019-07-02 18:55:11 +09002165
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002166 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma96147b72020-05-06 19:09:38 +09002167 public void testDhcpClientPreconnection_WithoutLayer2InfoWhenStartingProv() throws Exception {
Chalard Jeanb2896832020-05-13 19:16:49 +09002168 // For FILS connection, current bssid (also l2key and cluster) is still null when
Xiao Ma96147b72020-05-06 19:09:38 +09002169 // starting provisioning since the L2 link hasn't been established yet. Ensure that
2170 // IpClient won't crash even if initializing an Layer2Info class with null members.
2171 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
2172 .withoutIpReachabilityMonitor()
2173 .withoutIPv6()
2174 .withPreconnection()
Chalard Jeanb2896832020-05-13 19:16:49 +09002175 .withLayer2Information(new Layer2Information(null /* l2key */, null /* cluster */,
Xiao Ma96147b72020-05-06 19:09:38 +09002176 null /* bssid */));
2177
Xiao Ma927a8912021-01-07 08:05:02 +00002178 startIpClientProvisioning(prov.build());
Xiao Ma96147b72020-05-06 19:09:38 +09002179 assertDiscoverPacketOnPreconnectionStart();
2180 verify(mCb).setNeighborDiscoveryOffload(true);
2181
2182 // Force IpClient transition to RunningState from PreconnectionState.
Xiao Ma927a8912021-01-07 08:05:02 +00002183 mIIpClient.notifyPreconnectionComplete(false /* success */);
Chalard Jean23a06302020-06-26 00:41:00 +09002184 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma96147b72020-05-06 19:09:38 +09002185 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
2186 }
2187
Xiao Ma927a8912021-01-07 08:05:02 +00002188 @Test
Xiao Ma39511682021-07-30 02:40:06 +00002189 @SignatureRequiredTest(reason = "needs mocked alarm and access to IpClient handler thread")
2190 public void testDhcpClientPreconnection_DelayedAbortAndTransitToStoppedState()
2191 throws Exception {
2192 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2193 .withoutIpReachabilityMonitor()
2194 .withPreconnection()
2195 .build();
2196 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
2197 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
2198 startIpClientProvisioning(config);
2199 assertDiscoverPacketOnPreconnectionStart();
2200
2201 // IpClient is in the PreconnectingState, simulate provisioning timeout event
2202 // and force IpClient state machine transit to StoppingState.
2203 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
2204 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 18,
2205 mIpc.getHandler());
2206 mIpc.getHandler().post(() -> alarm.onAlarm());
2207
2208 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
2209 final LinkProperties lp = captor.getValue();
2210 assertNotNull(lp);
2211 assertEquals(mIfaceName, lp.getInterfaceName());
2212 assertEquals(0, lp.getLinkAddresses().size());
2213 assertEquals(0, lp.getRoutes().size());
2214 assertEquals(0, lp.getMtu());
2215 assertEquals(0, lp.getDnsServers().size());
2216
2217 // Send preconnection abort message, but IpClient should ignore it at this moment and
2218 // transit to StoppedState finally.
2219 mIpc.notifyPreconnectionComplete(false /* abort */);
2220 mIpc.stop();
2221 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
2222
2223 reset(mCb);
2224
2225 // Start provisioning again to verify IpClient can process CMD_START correctly at
2226 // StoppedState.
2227 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
2228 false /* shouldReplyRapidCommitAck */, false /* isPreConnectionEnabled */,
2229 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
2230 final DhcpPacket discover = getNextDhcpPacket();
2231 assertTrue(discover instanceof DhcpDiscoverPacket);
2232 }
2233
2234 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002235 public void testDhcpDecline_conflictByArpReply() throws Exception {
2236 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002237 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002238 true /* shouldResponseArpReply */);
2239 }
2240
Xiao Ma927a8912021-01-07 08:05:02 +00002241 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002242 public void testDhcpDecline_conflictByArpProbe() throws Exception {
2243 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002244 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002245 false /* shouldResponseArpReply */);
2246 }
2247
Xiao Ma927a8912021-01-07 08:05:02 +00002248 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002249 public void testDhcpDecline_EnableFlagWithoutIpConflict() throws Exception {
2250 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002251 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002252 false /* shouldResponseArpReply */);
2253 }
2254
Xiao Ma927a8912021-01-07 08:05:02 +00002255 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002256 public void testDhcpDecline_WithoutIpConflict() throws Exception {
2257 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002258 false /* shouldReplyRapidCommitAck */, false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002259 false /* shouldResponseArpReply */);
2260 }
2261
Xiao Ma927a8912021-01-07 08:05:02 +00002262 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002263 public void testDhcpDecline_WithRapidCommitWithoutIpConflict() throws Exception {
2264 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002265 true /* shouldReplyRapidCommitAck */, false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002266 false /* shouldResponseArpReply */);
2267 }
2268
Xiao Ma927a8912021-01-07 08:05:02 +00002269 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002270 public void testDhcpDecline_WithRapidCommitConflictByArpReply() throws Exception {
2271 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002272 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002273 true /* shouldResponseArpReply */);
2274 }
2275
Xiao Ma927a8912021-01-07 08:05:02 +00002276 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002277 public void testDhcpDecline_WithRapidCommitConflictByArpProbe() throws Exception {
2278 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002279 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002280 false /* shouldResponseArpReply */);
2281 }
2282
Xiao Ma927a8912021-01-07 08:05:02 +00002283 @Test
Xiao Ma7d733952019-07-02 18:55:11 +09002284 public void testDhcpDecline_EnableFlagWithRapidCommitWithoutIpConflict() throws Exception {
2285 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */,
Xiao Ma7b60bfa2019-12-09 10:23:32 +09002286 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
Xiao Ma7d733952019-07-02 18:55:11 +09002287 false /* shouldResponseArpReply */);
2288 }
Xiao Ma8bcd6732019-08-26 17:24:26 +09002289
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002290 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bcd6732019-08-26 17:24:26 +09002291 public void testHostname_enableConfig() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00002292 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */,
2293 TEST_HOST_NAME);
2294
Xiao Ma8bcd6732019-08-26 17:24:26 +09002295 final long currentTime = System.currentTimeMillis();
2296 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2297 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2298 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
Xiao Ma861fe422021-04-16 03:03:03 +00002299 false /* isDhcpIpConflictDetectEnabled */);
2300
Xiao Ma8bcd6732019-08-26 17:24:26 +09002301 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002302 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bcd6732019-08-26 17:24:26 +09002303 assertHostname(true, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets);
2304 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2305 }
2306
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002307 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bcd6732019-08-26 17:24:26 +09002308 public void testHostname_disableConfig() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00002309 mDependencies.setHostnameConfiguration(false /* isHostnameConfigurationEnabled */,
2310 TEST_HOST_NAME);
2311
Xiao Ma8bcd6732019-08-26 17:24:26 +09002312 final long currentTime = System.currentTimeMillis();
2313 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2314 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2315 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
Xiao Ma861fe422021-04-16 03:03:03 +00002316 false /* isDhcpIpConflictDetectEnabled */);
2317
Xiao Ma8bcd6732019-08-26 17:24:26 +09002318 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002319 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bcd6732019-08-26 17:24:26 +09002320 assertHostname(false, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets);
2321 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2322 }
2323
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002324 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bcd6732019-08-26 17:24:26 +09002325 public void testHostname_enableConfigWithNullHostname() throws Exception {
Xiao Ma927a8912021-01-07 08:05:02 +00002326 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */,
2327 null /* hostname */);
2328
Xiao Ma8bcd6732019-08-26 17:24:26 +09002329 final long currentTime = System.currentTimeMillis();
2330 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2331 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2332 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
Xiao Ma861fe422021-04-16 03:03:03 +00002333 false /* isDhcpIpConflictDetectEnabled */);
2334
Xiao Ma8bcd6732019-08-26 17:24:26 +09002335 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002336 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bcd6732019-08-26 17:24:26 +09002337 assertHostname(true, null /* hostname */, null /* hostnameAfterTransliteration */,
2338 sentPackets);
2339 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2340 }
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002341
Xiao Mac4fa89c2021-12-24 08:48:48 +00002342 private LinkProperties runDhcpClientCaptivePortalApiTest(boolean featureEnabled,
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002343 boolean serverSendsOption) throws Exception {
2344 startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
2345 false /* shouldReplyRapidCommitAck */, false /* isPreConnectionEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002346 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002347 final DhcpPacket discover = getNextDhcpPacket();
2348 assertTrue(discover instanceof DhcpDiscoverPacket);
2349 assertEquals(featureEnabled, discover.hasRequestedParam(DhcpPacket.DHCP_CAPTIVE_PORTAL));
2350
2351 // Send Offer and handle Request -> Ack
2352 final String serverSentUrl = serverSendsOption ? TEST_CAPTIVE_PORTAL_URL : null;
Xiao Ma6e2818b2020-06-22 01:18:22 +09002353 mPacketReader.sendResponse(buildDhcpOfferPacket(discover, CLIENT_ADDR,
2354 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, serverSentUrl));
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002355 final int testMtu = 1345;
2356 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
Xiao Ma872b2362020-05-27 12:10:40 +09002357 false /* shouldReplyRapidCommitAck */, testMtu, serverSentUrl);
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002358
2359 final Uri expectedUrl = featureEnabled && serverSendsOption
2360 ? Uri.parse(TEST_CAPTIVE_PORTAL_URL) : null;
Remi NGUYEN VAN5304b782020-09-01 09:40:41 +09002361 // LinkProperties will be updated multiple times. Wait for it to contain DHCP-obtained info,
2362 // such as MTU.
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +09002363 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
Remi NGUYEN VAN5304b782020-09-01 09:40:41 +09002364 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
Remi NGUYEN VAN905b0b62020-04-20 17:06:27 +09002365 argThat(lp -> lp.getMtu() == testMtu));
2366
2367 // Ensure that the URL was set as expected in the callbacks.
2368 // Can't verify the URL up to Q as there is no such attribute in LinkProperties.
Xiao Mac4fa89c2021-12-24 08:48:48 +00002369 if (!ShimUtils.isAtLeastR()) return null;
Remi NGUYEN VAN5304b782020-09-01 09:40:41 +09002370 verify(mCb, atLeastOnce()).onLinkPropertiesChange(captor.capture());
Xiao Mac4fa89c2021-12-24 08:48:48 +00002371 final LinkProperties expectedLp = captor.getAllValues().stream().findFirst().get();
2372 assertNotNull(expectedLp);
2373 assertEquals(expectedUrl, expectedLp.getCaptivePortalApiUrl());
2374 return expectedLp;
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002375 }
2376
Xiao Ma927a8912021-01-07 08:05:02 +00002377 @Test
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002378 public void testDhcpClientCaptivePortalApiEnabled() throws Exception {
2379 // Only run the test on platforms / builds where the API is enabled
2380 assumeTrue(CaptivePortalDataShimImpl.isSupported());
2381 runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, true /* serverSendsOption */);
2382 }
2383
Xiao Ma927a8912021-01-07 08:05:02 +00002384 @Test
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002385 public void testDhcpClientCaptivePortalApiEnabled_NoUrl() throws Exception {
2386 // Only run the test on platforms / builds where the API is enabled
2387 assumeTrue(CaptivePortalDataShimImpl.isSupported());
2388 runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, false /* serverSendsOption */);
2389 }
2390
Xiao Ma927a8912021-01-07 08:05:02 +00002391 @Test
Xiao Mac4fa89c2021-12-24 08:48:48 +00002392 public void testDhcpClientCaptivePortalApiEnabled_ParcelSensitiveFields() throws Exception {
2393 // Only run the test on platforms / builds where the API is enabled
2394 assumeTrue(CaptivePortalDataShimImpl.isSupported());
2395 LinkProperties lp = runDhcpClientCaptivePortalApiTest(true /* featureEnabled */,
2396 true /* serverSendsOption */);
2397
2398 // Integration test process runs in the same process with network stack module, there
2399 // won't be any IPC call happened on IpClientCallbacks, manually run parcelingRoundTrip
2400 // to parcel and unparcel the LinkProperties to simulate what happens during the binder
2401 // call. In this case lp should contain the senstive data but mParcelSensitiveFields is
2402 // false after round trip.
2403 if (useNetworkStackSignature()) {
2404 lp = parcelingRoundTrip(lp);
2405 }
2406 final Uri expectedUrl = Uri.parse(TEST_CAPTIVE_PORTAL_URL);
2407 assertEquals(expectedUrl, lp.getCaptivePortalApiUrl());
2408
2409 // Parcel and unparcel the captured LinkProperties, mParcelSensitiveFields is false,
2410 // CaptivePortalApiUrl should be null after parceling round trip.
2411 final LinkProperties unparceled = parcelingRoundTrip(lp);
2412 assertNull(unparceled.getCaptivePortalApiUrl());
2413 }
2414
2415 @Test
Remi NGUYEN VAN2a738922019-10-28 17:04:55 +09002416 public void testDhcpClientCaptivePortalApiDisabled() throws Exception {
2417 // Only run the test on platforms / builds where the API is disabled
2418 assumeFalse(CaptivePortalDataShimImpl.isSupported());
2419 runDhcpClientCaptivePortalApiTest(false /* featureEnabled */, true /* serverSendsOption */);
2420 }
Xiao Ma562d2422019-12-16 13:20:59 +09002421
2422 private ScanResultInfo makeScanResultInfo(final int id, final String ssid,
Xiao Maf784d612020-04-02 23:16:04 +09002423 final String bssid, final byte[] oui, final byte type, final byte[] data) {
Xiao Ma562d2422019-12-16 13:20:59 +09002424 final ByteBuffer payload = ByteBuffer.allocate(4 + data.length);
2425 payload.put(oui);
2426 payload.put(type);
2427 payload.put(data);
2428 payload.flip();
2429 final ScanResultInfo.InformationElement ie =
2430 new ScanResultInfo.InformationElement(id /* IE id */, payload);
Xiao Maf784d612020-04-02 23:16:04 +09002431 return new ScanResultInfo(ssid, bssid, Collections.singletonList(ie));
Xiao Ma562d2422019-12-16 13:20:59 +09002432 }
2433
Xiao Mae31734e2020-12-10 21:09:26 +09002434 private ScanResultInfo makeScanResultInfo(final int id, final byte[] oui, final byte type) {
2435 byte[] data = new byte[10];
2436 new Random().nextBytes(data);
2437 return makeScanResultInfo(id, TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID, oui, type, data);
2438 }
2439
Xiao Ma8bbceb42019-10-08 16:21:07 +09002440 private ScanResultInfo makeScanResultInfo(final String ssid, final String bssid) {
2441 byte[] data = new byte[10];
2442 new Random().nextBytes(data);
2443 return makeScanResultInfo(0xdd, ssid, bssid, TEST_AP_OUI, (byte) 0x06, data);
2444 }
2445
Xiao Ma562d2422019-12-16 13:20:59 +09002446 private void doUpstreamHotspotDetectionTest(final int id, final String displayName,
Xiao Ma8bbceb42019-10-08 16:21:07 +09002447 final String ssid, final byte[] oui, final byte type, final byte[] data,
2448 final boolean expectMetered) throws Exception {
Xiao Maf784d612020-04-02 23:16:04 +09002449 final ScanResultInfo info = makeScanResultInfo(id, ssid, TEST_DEFAULT_BSSID, oui, type,
2450 data);
Xiao Ma562d2422019-12-16 13:20:59 +09002451 final long currentTime = System.currentTimeMillis();
2452 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */,
2453 TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
2454 false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
2455 false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002456 false /* isIPv6OnlyPreferredEnabled */,
Xiao Ma861fe422021-04-16 03:03:03 +00002457 null /* captivePortalApiUrl */, displayName, info /* scanResultInfo */,
2458 null /* layer2Info */);
Xiao Ma562d2422019-12-16 13:20:59 +09002459 assertEquals(2, sentPackets.size());
Xiao Ma872b2362020-05-27 12:10:40 +09002460 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma562d2422019-12-16 13:20:59 +09002461
2462 ArgumentCaptor<DhcpResultsParcelable> captor =
2463 ArgumentCaptor.forClass(DhcpResultsParcelable.class);
2464 verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(captor.capture());
2465 DhcpResults lease = fromStableParcelable(captor.getValue());
2466 assertNotNull(lease);
2467 assertEquals(lease.getIpAddress().getAddress(), CLIENT_ADDR);
2468 assertEquals(lease.getGateway(), SERVER_ADDR);
2469 assertEquals(1, lease.getDnsServers().size());
2470 assertTrue(lease.getDnsServers().contains(SERVER_ADDR));
2471 assertEquals(lease.getServerAddress(), SERVER_ADDR);
2472 assertEquals(lease.getMtu(), TEST_DEFAULT_MTU);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002473
2474 if (expectMetered) {
Xiao Ma562d2422019-12-16 13:20:59 +09002475 assertEquals(lease.vendorInfo, DhcpPacket.VENDOR_INFO_ANDROID_METERED);
2476 } else {
2477 assertNull(lease.vendorInfo);
2478 }
2479
2480 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2481 }
2482
Xiao Ma927a8912021-01-07 08:05:02 +00002483 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002484 public void testUpstreamHotspotDetection() throws Exception {
2485 byte[] data = new byte[10];
2486 new Random().nextBytes(data);
2487 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002488 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2489 true /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002490 }
2491
Xiao Ma927a8912021-01-07 08:05:02 +00002492 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002493 public void testUpstreamHotspotDetection_incorrectIeId() throws Exception {
2494 byte[] data = new byte[10];
2495 new Random().nextBytes(data);
2496 doUpstreamHotspotDetectionTest(0xdc, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002497 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2498 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002499 }
2500
Xiao Ma927a8912021-01-07 08:05:02 +00002501 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002502 public void testUpstreamHotspotDetection_incorrectOUI() throws Exception {
2503 byte[] data = new byte[10];
2504 new Random().nextBytes(data);
2505 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002506 new byte[] { (byte) 0x00, (byte) 0x1A, (byte) 0x11 }, (byte) 0x06, data,
2507 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002508 }
2509
Xiao Ma927a8912021-01-07 08:05:02 +00002510 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002511 public void testUpstreamHotspotDetection_incorrectSsid() throws Exception {
2512 byte[] data = new byte[10];
2513 new Random().nextBytes(data);
2514 doUpstreamHotspotDetectionTest(0xdd, "\"another ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002515 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2516 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002517 }
2518
Xiao Ma927a8912021-01-07 08:05:02 +00002519 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002520 public void testUpstreamHotspotDetection_incorrectType() throws Exception {
2521 byte[] data = new byte[10];
2522 new Random().nextBytes(data);
2523 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002524 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x0a, data,
2525 false /* expectMetered */);
Xiao Ma562d2422019-12-16 13:20:59 +09002526 }
2527
Xiao Ma927a8912021-01-07 08:05:02 +00002528 @Test
Xiao Ma562d2422019-12-16 13:20:59 +09002529 public void testUpstreamHotspotDetection_zeroLengthData() throws Exception {
2530 byte[] data = new byte[0];
2531 doUpstreamHotspotDetectionTest(0xdd, "\"ssid\"", "ssid",
Xiao Ma8bbceb42019-10-08 16:21:07 +09002532 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data,
2533 true /* expectMetered */);
2534 }
2535
Xiao Ma8a0b7672021-04-19 08:33:29 +00002536 private void forceLayer2Roaming() throws Exception {
2537 final Layer2InformationParcelable roamingInfo = new Layer2InformationParcelable();
2538 roamingInfo.bssid = MacAddress.fromString(TEST_DHCP_ROAM_BSSID);
2539 roamingInfo.l2Key = TEST_DHCP_ROAM_L2KEY;
2540 roamingInfo.cluster = TEST_DHCP_ROAM_CLUSTER;
2541 mIIpClient.updateLayer2Information(roamingInfo);
2542 }
2543
Xiao Ma8bbceb42019-10-08 16:21:07 +09002544 private void doDhcpRoamingTest(final boolean hasMismatchedIpAddress, final String displayName,
Xiao Ma780c09e2021-11-05 09:43:12 +00002545 final MacAddress bssid, final boolean expectRoaming,
2546 final boolean shouldReplyNakOnRoam) throws Exception {
Xiao Ma8bbceb42019-10-08 16:21:07 +09002547 long currentTime = System.currentTimeMillis();
Xiao Ma861fe422021-04-16 03:03:03 +00002548 final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER, bssid);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002549
2550 doAnswer(invocation -> {
2551 // we don't rely on the Init-Reboot state to renew previous cached IP lease.
2552 // Just return null and force state machine enter INIT state.
Lorenzo Colittibd2f2f22020-04-25 18:41:11 +09002553 final String l2Key = invocation.getArgument(0);
2554 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1))
2555 .onNetworkAttributesRetrieved(new Status(SUCCESS), l2Key, null);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002556 return null;
2557 }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any());
2558
Xiao Ma927a8912021-01-07 08:05:02 +00002559 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */,
2560 null /* hostname */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002561 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
2562 true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */,
2563 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00002564 false /* isIPv6OnlyPreferredEnabled */,
Xiao Ma861fe422021-04-16 03:03:03 +00002565 null /* captivePortalApiUrl */, displayName, null /* scanResultInfo */,
2566 layer2Info);
Xiao Ma872b2362020-05-27 12:10:40 +09002567 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
Xiao Ma8bbceb42019-10-08 16:21:07 +09002568 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2569
2570 // simulate the roaming by updating bssid.
Xiao Ma8a0b7672021-04-19 08:33:29 +00002571 forceLayer2Roaming();
Xiao Ma8bbceb42019-10-08 16:21:07 +09002572
2573 currentTime = System.currentTimeMillis();
2574 reset(mIpMemoryStore);
2575 reset(mCb);
2576 if (!expectRoaming) {
2577 assertIpMemoryNeverStoreNetworkAttributes();
2578 return;
2579 }
2580 // check DHCPREQUEST broadcast sent to renew IP address.
2581 DhcpPacket packet;
2582 packet = getNextDhcpPacket();
2583 assertTrue(packet instanceof DhcpRequestPacket);
2584 assertEquals(packet.mClientIp, CLIENT_ADDR); // client IP
2585 assertNull(packet.mRequestedIp); // requested IP option
2586 assertNull(packet.mServerIdentifier); // server ID
2587
Xiao Ma780c09e2021-11-05 09:43:12 +00002588 final ByteBuffer packetBuffer = shouldReplyNakOnRoam
2589 ? buildDhcpNakPacket(packet, "request IP on a wrong subnet")
2590 : buildDhcpAckPacket(packet,
2591 hasMismatchedIpAddress ? CLIENT_ADDR_NEW : CLIENT_ADDR,
2592 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU,
2593 false /* rapidCommit */, null /* captivePortalApiUrl */);
2594 mPacketReader.sendResponse(packetBuffer);
Chalard Jean23a06302020-06-26 00:41:00 +09002595 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
Xiao Ma780c09e2021-11-05 09:43:12 +00002596
Xiao Ma33cc64a2021-11-03 09:31:35 +00002597 if (shouldReplyNakOnRoam) {
2598 ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor =
2599 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class);
2600 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityFailure(lossInfoCaptor.capture());
2601 assertEquals(ReachabilityLossReason.ROAM, lossInfoCaptor.getValue().reason);
2602
2603 // IPv4 address will be still deleted when DhcpClient state machine exits from
2604 // DhcpHaveLeaseState, a following onProvisioningFailure will be thrown then.
2605 // Also check DhcpClient won't send any DHCPDISCOVER packet.
2606 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
2607 assertNull(getNextDhcpPacket(TEST_TIMEOUT_MS));
2608 verify(mCb, never()).onNewDhcpResults(any());
2609 } else if (hasMismatchedIpAddress) {
2610 ArgumentCaptor<DhcpResultsParcelable> resultsCaptor =
Xiao Ma8bbceb42019-10-08 16:21:07 +09002611 ArgumentCaptor.forClass(DhcpResultsParcelable.class);
Xiao Ma33cc64a2021-11-03 09:31:35 +00002612 verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(resultsCaptor.capture());
2613 DhcpResults lease = fromStableParcelable(resultsCaptor.getValue());
Xiao Ma8bbceb42019-10-08 16:21:07 +09002614 assertNull(lease);
2615
Xiao Ma780c09e2021-11-05 09:43:12 +00002616 // DhcpClient rolls back to StoppedState instead of INIT state after calling
2617 // notifyFailure, DHCPDISCOVER should not be sent out.
2618 assertNull(getNextDhcpPacket(TEST_TIMEOUT_MS));
Xiao Ma8bbceb42019-10-08 16:21:07 +09002619 } else {
2620 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime,
2621 TEST_DEFAULT_MTU);
2622 }
2623 }
2624
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002625 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002626 public void testDhcpRoaming() throws Exception {
2627 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002628 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */,
2629 false /* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002630 }
2631
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002632 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002633 public void testDhcpRoaming_invalidBssid() throws Exception {
2634 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002635 MacAddress.fromString(TEST_DHCP_ROAM_BSSID), false /* expectRoaming */,
2636 false/* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002637 }
2638
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002639 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma861fe422021-04-16 03:03:03 +00002640 public void testDhcpRoaming_nullBssid() throws Exception {
Xiao Maad5d93e2020-07-31 17:19:42 +09002641 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002642 null /* BSSID */, false /* expectRoaming */, false /* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002643 }
2644
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002645 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002646 public void testDhcpRoaming_invalidDisplayName() throws Exception {
2647 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"test-ssid\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002648 MacAddress.fromString(TEST_DEFAULT_BSSID), false /* expectRoaming */,
2649 false /* shouldReplyNakOnRoam */);
Xiao Ma8bbceb42019-10-08 16:21:07 +09002650 }
2651
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002652 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma8bbceb42019-10-08 16:21:07 +09002653 public void testDhcpRoaming_mismatchedLeasedIpAddress() throws Exception {
2654 doDhcpRoamingTest(true /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
Xiao Ma780c09e2021-11-05 09:43:12 +00002655 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */,
2656 false /* shouldReplyNakOnRoam */);
2657 }
2658
2659 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
2660 public void testDhcpRoaming_failureLeaseOnNak() throws Exception {
2661 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */,
2662 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */,
2663 true /* shouldReplyNakOnRoam */);
Xiao Ma562d2422019-12-16 13:20:59 +09002664 }
Xiao Ma4edc4f62020-05-21 10:32:47 +09002665
Xiao Ma8a0b7672021-04-19 08:33:29 +00002666 private void performDualStackProvisioning() throws Exception {
Xiao Ma4edc4f62020-05-21 10:32:47 +09002667 final InOrder inOrder = inOrder(mCb);
2668 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>();
2669 final String dnsServer = "2001:4860:4860::64";
2670 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
2671 final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
Xiao Ma60175d22021-06-02 12:28:40 +00002672 final ByteBuffer slla = buildSllaOption();
2673 final ByteBuffer ra = buildRaPacket(pio, rdnss, slla);
Xiao Ma4edc4f62020-05-21 10:32:47 +09002674
2675 doIpv6OnlyProvisioning(inOrder, ra);
2676
2677 // Start IPv4 provisioning and wait until entire provisioning completes.
2678 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
2679 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */);
2680 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(argThat(x -> {
2681 if (!x.isIpv4Provisioned() || !x.isIpv6Provisioned()) return false;
2682 lpFuture.complete(x);
2683 return true;
2684 }));
2685
2686 final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2687 assertNotNull(lp);
2688 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
2689 assertTrue(lp.getDnsServers().contains(SERVER_ADDR));
2690
2691 reset(mCb);
2692 }
2693
Xiao Ma690e12e2021-05-11 11:11:45 +00002694 private void doDualStackProvisioning(boolean shouldDisableAcceptRa) throws Exception {
Xiao Ma8a0b7672021-04-19 08:33:29 +00002695 when(mCm.shouldAvoidBadWifi()).thenReturn(true);
2696
2697 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2698 .withoutIpReachabilityMonitor()
2699 .build();
Xiao Ma690e12e2021-05-11 11:11:45 +00002700
2701 setFeatureEnabled(NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION,
2702 shouldDisableAcceptRa);
Xiao Ma8a0b7672021-04-19 08:33:29 +00002703 // Enable rapid commit to accelerate DHCP handshake to shorten test duration,
2704 // not strictly necessary.
2705 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
2706 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
2707 mIpc.startProvisioning(config);
2708
2709 performDualStackProvisioning();
2710 }
2711
Xiao Ma690e12e2021-05-11 11:11:45 +00002712 @Test @SignatureRequiredTest(reason = "signature perms are required due to mocked callabck")
2713 public void testIgnoreIpv6ProvisioningLoss_disableIPv6Stack() throws Exception {
2714 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Xiao Ma4edc4f62020-05-21 10:32:47 +09002715
2716 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>();
2717
2718 // Send RA with 0-lifetime and wait until all IPv6-related default route and DNS servers
2719 // have been removed, then verify if there is IPv4-only info left in the LinkProperties.
2720 sendRouterAdvertisementWithZeroLifetime();
2721 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
2722 argThat(x -> {
2723 final boolean isOnlyIPv4Provisioned = (x.getLinkAddresses().size() == 1
2724 && x.getDnsServers().size() == 1
2725 && x.getAddresses().get(0) instanceof Inet4Address
2726 && x.getDnsServers().get(0) instanceof Inet4Address);
2727
2728 if (!isOnlyIPv4Provisioned) return false;
2729 lpFuture.complete(x);
2730 return true;
2731 }));
2732 final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2733 assertNotNull(lp);
2734 assertEquals(lp.getAddresses().get(0), CLIENT_ADDR);
2735 assertEquals(lp.getDnsServers().get(0), SERVER_ADDR);
lifrf9105de2021-05-06 15:31:04 +08002736
2737 final ArgumentCaptor<Integer> quirkEvent = ArgumentCaptor.forClass(Integer.class);
2738 verify(mNetworkQuirkMetricsDeps, timeout(TEST_TIMEOUT_MS)).writeStats(quirkEvent.capture());
2739 assertEquals((long) quirkEvent.getValue(),
2740 (long) NetworkQuirkEvent.QE_IPV6_PROVISIONING_ROUTER_LOST.ordinal());
Xiao Ma4edc4f62020-05-21 10:32:47 +09002741 }
2742
Xiao Ma78c89f42022-03-30 22:07:50 +09002743 private boolean hasRouteTo(@NonNull final LinkProperties lp, @NonNull final String prefix) {
2744 for (RouteInfo r : lp.getRoutes()) {
2745 if (r.getDestination().equals(new IpPrefix(prefix))) return true;
2746 }
2747 return false;
2748 }
2749
Xiao Ma690e12e2021-05-11 11:11:45 +00002750 @Test @SignatureRequiredTest(reason = "signature perms are required due to mocked callabck")
2751 public void testIgnoreIpv6ProvisioningLoss_disableAcceptRa() throws Exception {
2752 doDualStackProvisioning(true /* shouldDisableAcceptRa */);
2753
2754 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>();
2755
2756 // Send RA with 0-lifetime and wait until all global IPv6 addresses, IPv6-related default
2757 // route and DNS servers have been removed, then verify if there is IPv4-only, IPv6 link
2758 // local address and route to fe80::/64 info left in the LinkProperties.
2759 sendRouterAdvertisementWithZeroLifetime();
2760 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
2761 argThat(x -> {
2762 // Only IPv4 provisioned and IPv6 link-local address
2763 final boolean isIPv6LinkLocalAndIPv4OnlyProvisioned =
2764 (x.getLinkAddresses().size() == 2
Xiao Ma78c89f42022-03-30 22:07:50 +09002765 // fe80::/64, IPv4 default route, IPv4 subnet route
2766 && x.getRoutes().size() == 3
Xiao Ma690e12e2021-05-11 11:11:45 +00002767 && x.getDnsServers().size() == 1
2768 && x.getAddresses().get(0) instanceof Inet4Address
2769 && x.getDnsServers().get(0) instanceof Inet4Address);
2770
2771 if (!isIPv6LinkLocalAndIPv4OnlyProvisioned) return false;
2772 lpFuture.complete(x);
2773 return true;
2774 }));
2775 final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2776 assertNotNull(lp);
2777 assertEquals(lp.getAddresses().get(0), CLIENT_ADDR);
2778 assertEquals(lp.getDnsServers().get(0), SERVER_ADDR);
Xiao Ma78c89f42022-03-30 22:07:50 +09002779 assertEquals(3, lp.getRoutes().size());
2780 assertTrue(hasRouteTo(lp, IPV6_LINK_LOCAL_PREFIX)); // fe80::/64
2781 assertTrue(hasRouteTo(lp, IPV4_TEST_SUBNET_PREFIX)); // IPv4 directly-connected route
2782 assertTrue(hasRouteTo(lp, IPV4_ANY_ADDRESS_PREFIX)); // IPv4 default route
Xiao Ma690e12e2021-05-11 11:11:45 +00002783 assertTrue(lp.getAddresses().get(1).isLinkLocalAddress());
2784
2785 reset(mCb);
2786
Xiao Ma97a0eec2022-03-25 09:40:18 +00002787 // Send an RA to verify that global IPv6 addresses won't be configured on the interface.
Xiao Ma690e12e2021-05-11 11:11:45 +00002788 sendBasicRouterAdvertisement(false /* waitForRs */);
Xiao Ma97a0eec2022-03-25 09:40:18 +00002789 verify(mCb, timeout(TEST_TIMEOUT_MS).times(0)).onLinkPropertiesChange(any());
Xiao Ma690e12e2021-05-11 11:11:45 +00002790 }
2791
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002792 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma4edc4f62020-05-21 10:32:47 +09002793 public void testDualStackProvisioning() throws Exception {
Xiao Ma690e12e2021-05-11 11:11:45 +00002794 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Xiao Ma4edc4f62020-05-21 10:32:47 +09002795
2796 verify(mCb, never()).onProvisioningFailure(any());
2797 }
Xiao Ma6e2818b2020-06-22 01:18:22 +09002798
2799 private DhcpPacket verifyDhcpPacketRequestsIPv6OnlyPreferredOption(
2800 Class<? extends DhcpPacket> packetType) throws Exception {
2801 final DhcpPacket packet = getNextDhcpPacket();
2802 assertTrue(packetType.isInstance(packet));
2803 assertTrue(packet.hasRequestedParam(DHCP_IPV6_ONLY_PREFERRED));
2804 return packet;
2805 }
2806
2807 private void doIPv6OnlyPreferredOptionTest(final Integer ipv6OnlyWaitTime,
2808 final Inet4Address clientAddress) throws Exception {
2809 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2810 .withoutIpReachabilityMonitor()
2811 .build();
Xiao Ma927a8912021-01-07 08:05:02 +00002812 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, false /* isRapidCommitEnabled */,
2813 false /* isDhcpIpConflictDetectEnabled */, true /* isIPv6OnlyPreferredEnabled */);
2814 startIpClientProvisioning(config);
Xiao Ma6e2818b2020-06-22 01:18:22 +09002815
2816 final DhcpPacket packet =
2817 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2818
2819 // Respond DHCPOFFER with IPv6-Only preferred option and offered address.
2820 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, clientAddress,
2821 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, null /* captivePortalUrl */,
2822 ipv6OnlyWaitTime));
2823 }
2824
2825 private void doDiscoverIPv6OnlyPreferredOptionTest(final int optionSecs,
2826 final long expectedWaitSecs) throws Exception {
2827 doIPv6OnlyPreferredOptionTest(optionSecs, CLIENT_ADDR);
2828 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT",
2829 expectedWaitSecs, mDependencies.mDhcpClient.getHandler());
2830 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm());
2831 // Implicitly check that the client never sent a DHCPREQUEST to request the offered address.
2832 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2833 }
2834
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002835 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002836 public void testDiscoverIPv6OnlyPreferredOption() throws Exception {
2837 doDiscoverIPv6OnlyPreferredOptionTest(TEST_IPV6_ONLY_WAIT_S, TEST_IPV6_ONLY_WAIT_S);
2838 }
2839
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002840 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002841 public void testDiscoverIPv6OnlyPreferredOption_LowerIPv6OnlyWait() throws Exception {
2842 doDiscoverIPv6OnlyPreferredOptionTest(TEST_LOWER_IPV6_ONLY_WAIT_S,
2843 TEST_LOWER_IPV6_ONLY_WAIT_S);
2844 }
2845
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002846 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002847 public void testDiscoverIPv6OnlyPreferredOption_ZeroIPv6OnlyWait() throws Exception {
2848 doDiscoverIPv6OnlyPreferredOptionTest(TEST_ZERO_IPV6_ONLY_WAIT_S,
2849 TEST_LOWER_IPV6_ONLY_WAIT_S);
2850 }
2851
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002852 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002853 public void testDiscoverIPv6OnlyPreferredOption_MaxIPv6OnlyWait() throws Exception {
2854 doDiscoverIPv6OnlyPreferredOptionTest((int) TEST_MAX_IPV6_ONLY_WAIT_S, 0xffffffffL);
2855 }
2856
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002857 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002858 public void testDiscoverIPv6OnlyPreferredOption_ZeroIPv6OnlyWaitWithOfferedAnyAddress()
2859 throws Exception {
2860 doIPv6OnlyPreferredOptionTest(TEST_ZERO_IPV6_ONLY_WAIT_S, IPV4_ADDR_ANY);
2861
2862 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 300,
2863 mDependencies.mDhcpClient.getHandler());
2864 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm());
2865
2866 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2867 }
2868
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002869 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002870 public void testDiscoverIPv6OnlyPreferredOption_enabledPreconnection() throws Exception {
2871 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2872 .withoutIpReachabilityMonitor()
2873 .withPreconnection()
2874 .build();
2875
Xiao Ma927a8912021-01-07 08:05:02 +00002876 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
2877 false /* isDhcpIpConflictDetectEnabled */, true /* isIPv6OnlyPreferredEnabled */);
2878 startIpClientProvisioning(config);
Xiao Ma6e2818b2020-06-22 01:18:22 +09002879
2880 final DhcpPacket packet = assertDiscoverPacketOnPreconnectionStart();
2881 verify(mCb).setNeighborDiscoveryOffload(true);
2882
2883 // Force IpClient transition to RunningState from PreconnectionState.
2884 mIpc.notifyPreconnectionComplete(true /* success */);
2885 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS);
2886 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
2887
2888 // DHCP server SHOULD NOT honor the Rapid-Commit option if the response would
2889 // contain the IPv6-only Preferred option to the client, instead respond with
2890 // a DHCPOFFER.
2891 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR, TEST_LEASE_DURATION_S,
2892 (short) TEST_DEFAULT_MTU, null /* captivePortalUrl */, TEST_IPV6_ONLY_WAIT_S));
2893
2894 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 1800,
2895 mDependencies.mDhcpClient.getHandler());
2896 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm());
2897
2898 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class);
2899 }
2900
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002901 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002902 public void testDiscoverIPv6OnlyPreferredOption_NoIPv6OnlyPreferredOption() throws Exception {
2903 doIPv6OnlyPreferredOptionTest(null /* ipv6OnlyWaitTime */, CLIENT_ADDR);
2904
2905 // The IPv6-only Preferred option SHOULD be included in the Parameter Request List option
2906 // in DHCPREQUEST messages after receiving a DHCPOFFER without this option.
2907 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpRequestPacket.class);
2908 }
2909
Xiao Ma4ca906c2021-01-30 12:09:41 +00002910 private void setUpRetrievedNetworkAttributesForInitRebootState() {
2911 final NetworkAttributes na = new NetworkAttributes.Builder()
2912 .setAssignedV4Address(CLIENT_ADDR)
2913 .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid
2914 .setMtu(new Integer(TEST_DEFAULT_MTU))
2915 .setCluster(TEST_CLUSTER)
2916 .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
2917 .build();
2918 storeNetworkAttributes(TEST_L2KEY, na);
2919 }
2920
Xiao Ma6e2818b2020-06-22 01:18:22 +09002921 private void startFromInitRebootStateWithIPv6OnlyPreferredOption(final Integer ipv6OnlyWaitTime,
2922 final long expectedWaitSecs) throws Exception {
Xiao Ma4ca906c2021-01-30 12:09:41 +00002923 setUpRetrievedNetworkAttributesForInitRebootState();
Xiao Ma6e2818b2020-06-22 01:18:22 +09002924
2925 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
2926 .withoutIpReachabilityMonitor()
2927 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
2928 MacAddress.fromString(TEST_DEFAULT_BSSID)))
2929 .build();
2930
Xiao Ma927a8912021-01-07 08:05:02 +00002931 setDhcpFeatures(true /* isDhcpLeaseCacheEnabled */, false /* isRapidCommitEnabled */,
2932 false /* isDhcpIpConflictDetectEnabled */, true /* isIPv6OnlyPreferredEnabled */);
2933 startIpClientProvisioning(config);
Xiao Ma6e2818b2020-06-22 01:18:22 +09002934
2935 final DhcpPacket packet =
2936 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpRequestPacket.class);
2937
2938 // Respond DHCPACK with IPv6-Only preferred option.
2939 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR,
2940 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, false /* rapidcommit */,
2941 null /* captivePortalUrl */, ipv6OnlyWaitTime));
2942
2943 if (ipv6OnlyWaitTime != null) {
2944 expectAlarmSet(null /* inOrder */, "TIMEOUT", expectedWaitSecs,
2945 mDependencies.mDhcpClient.getHandler());
2946 }
2947 }
2948
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002949 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002950 public void testRequestIPv6OnlyPreferredOption() throws Exception {
2951 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_IPV6_ONLY_WAIT_S,
2952 TEST_IPV6_ONLY_WAIT_S);
2953
2954 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2955 // IPv6-Only preferred option(default value) in the DHCPACK packet.
2956 assertIpMemoryNeverStoreNetworkAttributes();
2957 }
2958
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002959 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002960 public void testRequestIPv6OnlyPreferredOption_LowerIPv6OnlyWait() throws Exception {
2961 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_LOWER_IPV6_ONLY_WAIT_S,
2962 TEST_LOWER_IPV6_ONLY_WAIT_S);
2963
2964 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2965 // IPv6-Only preferred option(less than MIN_V6ONLY_WAIT_MS) in the DHCPACK packet.
2966 assertIpMemoryNeverStoreNetworkAttributes();
2967 }
2968
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002969 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002970 public void testRequestIPv6OnlyPreferredOption_ZeroIPv6OnlyWait() throws Exception {
2971 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_ZERO_IPV6_ONLY_WAIT_S,
2972 TEST_LOWER_IPV6_ONLY_WAIT_S);
2973
2974 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2975 // IPv6-Only preferred option(0) in the DHCPACK packet.
2976 assertIpMemoryNeverStoreNetworkAttributes();
2977 }
2978
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002979 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002980 public void testRequestIPv6OnlyPreferredOption_MaxIPv6OnlyWait() throws Exception {
2981 startFromInitRebootStateWithIPv6OnlyPreferredOption((int) TEST_MAX_IPV6_ONLY_WAIT_S,
2982 0xffffffffL);
2983
2984 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid
2985 // IPv6-Only preferred option(MAX_UNSIGNED_INTEGER: 0xFFFFFFFF) in the DHCPACK packet.
2986 assertIpMemoryNeverStoreNetworkAttributes();
2987 }
2988
Remi NGUYEN VANa55eae52020-09-07 22:00:26 +09002989 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
Xiao Ma6e2818b2020-06-22 01:18:22 +09002990 public void testRequestIPv6OnlyPreferredOption_NoIPv6OnlyPreferredOption() throws Exception {
2991 final long currentTime = System.currentTimeMillis();
2992 startFromInitRebootStateWithIPv6OnlyPreferredOption(null /* ipv6OnlyWaitTime */,
2993 0 /* expectedWaitSecs */);
2994
2995 // Client processes DHCPACK packet normally and transits to the ConfiguringInterfaceState
2996 // due to the null V6ONLY_WAIT.
2997 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
2998 }
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09002999
3000 private static int getNumOpenFds() {
3001 return new File("/proc/" + Os.getpid() + "/fd").listFiles().length;
3002 }
3003
3004 private void shutdownAndRecreateIpClient() throws Exception {
3005 mIpc.shutdown();
3006 awaitIpClientShutdown();
3007 mIpc = makeIpClient();
3008 }
3009
Remi NGUYEN VAN0dc6d222020-12-21 07:05:41 +00003010 @Test @SignatureRequiredTest(reason = "Only counts FDs from the current process. TODO: fix")
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09003011 public void testNoFdLeaks() throws Exception {
3012 // Shut down and restart IpClient once to ensure that any fds that are opened the first
3013 // time it runs do not cause the test to fail.
Xiao Ma690e12e2021-05-11 11:11:45 +00003014 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09003015 shutdownAndRecreateIpClient();
3016
3017 // Unfortunately we cannot use a large number of iterations as it would make the test run
3018 // too slowly. On crosshatch-eng each iteration takes ~250ms.
3019 final int iterations = 10;
3020 final int before = getNumOpenFds();
3021 for (int i = 0; i < iterations; i++) {
Xiao Ma690e12e2021-05-11 11:11:45 +00003022 doDualStackProvisioning(false /* shouldDisableAcceptRa */);
Lorenzo Colitti675e0f52020-08-18 22:13:24 +09003023 shutdownAndRecreateIpClient();
3024 // The last time this loop runs, mIpc will be shut down in tearDown.
3025 }
3026 final int after = getNumOpenFds();
3027
3028 // Check that the number of open fds is the same as before.
3029 // If this exact match becomes flaky, we could add some tolerance here (e.g., allow 2-3
3030 // extra fds), since it's likely that any leak would at least leak one FD per loop.
3031 assertEquals("Fd leak after " + iterations + " iterations: ", before, after);
3032 }
Xiao Mae31734e2020-12-10 21:09:26 +09003033
3034 // TODO: delete when DhcpOption is @JavaOnlyImmutable.
3035 private static DhcpOption makeDhcpOption(final byte type, final byte[] value) {
3036 final DhcpOption opt = new DhcpOption();
3037 opt.type = type;
3038 opt.value = value;
3039 return opt;
3040 }
3041
3042 private static final List<DhcpOption> TEST_OEM_DHCP_OPTIONS = Arrays.asList(
3043 // DHCP_USER_CLASS
3044 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3045 // DHCP_VENDOR_CLASS_ID
3046 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes())
3047 );
3048
3049 private DhcpPacket doCustomizedDhcpOptionsTest(final List<DhcpOption> options,
Xiao Ma4ca906c2021-01-30 12:09:41 +00003050 final ScanResultInfo info, boolean isDhcpLeaseCacheEnabled) throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003051 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
3052 .withoutIpReachabilityMonitor()
3053 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
3054 MacAddress.fromString(TEST_DEFAULT_BSSID)))
3055 .withScanResultInfo(info)
3056 .withDhcpOptions(options)
3057 .withoutIPv6();
3058
Xiao Ma4ca906c2021-01-30 12:09:41 +00003059 setDhcpFeatures(isDhcpLeaseCacheEnabled, false /* isRapidCommitEnabled */,
Xiao Ma927a8912021-01-07 08:05:02 +00003060 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003061
3062 startIpClientProvisioning(prov.build());
3063 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
3064 verify(mCb, never()).onProvisioningFailure(any());
3065
3066 return getNextDhcpPacket();
3067 }
3068
3069 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003070 public void testDiscoverCustomizedDhcpOptions() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003071 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3072 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003073 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3074 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003075
3076 assertTrue(packet instanceof DhcpDiscoverPacket);
3077 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3078 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3079 }
3080
3081 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003082 public void testDiscoverCustomizedDhcpOptions_nullDhcpOptions() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003083 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3084 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003085 final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info,
3086 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003087
3088 assertTrue(packet instanceof DhcpDiscoverPacket);
3089 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3090 assertNull(packet.mUserClass);
3091 }
3092
3093 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003094 public void testDiscoverCustomizedDhcpOptions_nullScanResultInfo() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003095 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS,
Xiao Ma4ca906c2021-01-30 12:09:41 +00003096 null /* scanResultInfo */, false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003097
3098 assertTrue(packet instanceof DhcpDiscoverPacket);
3099 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3100 assertNull(packet.mUserClass);
3101 }
3102
3103 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003104 public void testDiscoverCustomizedDhcpOptions_disallowedOui() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003105 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */,
3106 new byte[]{ 0x00, 0x11, 0x22} /* oui */, (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003107 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3108 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003109
3110 assertTrue(packet instanceof DhcpDiscoverPacket);
3111 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3112 assertNull(packet.mUserClass);
3113 }
3114
3115 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003116 public void testDiscoverCustomizedDhcpOptions_invalidIeId() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003117 final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specificIE */, TEST_OEM_OUI,
3118 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003119 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3120 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003121
3122 assertTrue(packet instanceof DhcpDiscoverPacket);
3123 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3124 assertNull(packet.mUserClass);
3125 }
3126
3127 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003128 public void testDiscoverCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003129 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3130 (byte) 0x10 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003131 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3132 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003133
3134 assertTrue(packet instanceof DhcpDiscoverPacket);
3135 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3136 assertNull(packet.mUserClass);
3137 }
3138
3139 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003140 public void testDisoverCustomizedDhcpOptions_disallowedOption() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003141 final List<DhcpOption> options = Arrays.asList(
3142 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3143 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
Xiao Ma45676f02021-04-20 09:15:42 +00003144 // Option 26: MTU
3145 makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU)));
Xiao Mae31734e2020-12-10 21:09:26 +09003146 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3147 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003148 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3149 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003150
3151 assertTrue(packet instanceof DhcpDiscoverPacket);
3152 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3153 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
Xiao Ma45676f02021-04-20 09:15:42 +00003154 assertNull(packet.mMtu);
Xiao Mae31734e2020-12-10 21:09:26 +09003155 }
3156
3157 @Test
Xiao Ma4ca906c2021-01-30 12:09:41 +00003158 public void testDiscoverCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception {
Xiao Mae31734e2020-12-10 21:09:26 +09003159 final List<DhcpOption> options = Arrays.asList(
3160 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3161 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3162 // NTP_SERVER
3163 makeDhcpOption((byte) 42, null));
3164 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3165 (byte) 0x17 /* vendor-specific IE type */);
Xiao Ma4ca906c2021-01-30 12:09:41 +00003166 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3167 false /* isDhcpLeaseCacheEnabled */);
Xiao Mae31734e2020-12-10 21:09:26 +09003168
3169 assertTrue(packet instanceof DhcpDiscoverPacket);
3170 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3171 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3172 assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */));
3173 }
Xiao Ma002dd5a2020-12-22 01:14:49 +00003174
Xiao Ma4ca906c2021-01-30 12:09:41 +00003175 @Test
3176 public void testDiscoverCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception {
3177 final List<DhcpOption> options = Arrays.asList(
3178 // DHCP_USER_CLASS
3179 makeDhcpOption((byte) 77, null));
3180 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3181 (byte) 0x17 /* vendor-specific IE type */);
3182 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3183 false /* isDhcpLeaseCacheEnabled */);
3184
3185 assertTrue(packet instanceof DhcpDiscoverPacket);
3186 assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */));
3187 assertNull(packet.mUserClass);
3188 }
3189
3190 @Test
3191 public void testRequestCustomizedDhcpOptions() throws Exception {
3192 setUpRetrievedNetworkAttributesForInitRebootState();
3193
3194 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3195 (byte) 0x17 /* vendor-specific IE type */);
3196 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3197 true /* isDhcpLeaseCacheEnabled */);
3198
3199 assertTrue(packet instanceof DhcpRequestPacket);
3200 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3201 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3202 }
3203
3204 @Test
3205 public void testRequestCustomizedDhcpOptions_nullDhcpOptions() throws Exception {
3206 setUpRetrievedNetworkAttributesForInitRebootState();
3207
3208 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3209 (byte) 0x17 /* vendor-specific IE type */);
3210 final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info,
3211 true /* isDhcpLeaseCacheEnabled */);
3212
3213 assertTrue(packet instanceof DhcpRequestPacket);
3214 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3215 assertNull(packet.mUserClass);
3216 }
3217
3218 @Test
3219 public void testRequestCustomizedDhcpOptions_nullScanResultInfo() throws Exception {
3220 setUpRetrievedNetworkAttributesForInitRebootState();
3221
3222 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS,
3223 null /* scanResultInfo */, true /* isDhcpLeaseCacheEnabled */);
3224
3225 assertTrue(packet instanceof DhcpRequestPacket);
3226 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3227 assertNull(packet.mUserClass);
3228 }
3229
3230 @Test
3231 public void testRequestCustomizedDhcpOptions_disallowedOui() throws Exception {
3232 setUpRetrievedNetworkAttributesForInitRebootState();
3233
3234 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */,
3235 new byte[]{ 0x00, 0x11, 0x22} /* oui */, (byte) 0x17 /* vendor-specific IE type */);
3236 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3237 true /* isDhcpLeaseCacheEnabled */);
3238
3239 assertTrue(packet instanceof DhcpRequestPacket);
3240 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3241 assertNull(packet.mUserClass);
3242 }
3243
3244 @Test
3245 public void testRequestCustomizedDhcpOptions_invalidIeId() throws Exception {
3246 setUpRetrievedNetworkAttributesForInitRebootState();
3247
3248 final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specificIE */, TEST_OEM_OUI,
3249 (byte) 0x17 /* vendor-specific IE type */);
3250 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3251 true /* isDhcpLeaseCacheEnabled */);
3252
3253 assertTrue(packet instanceof DhcpRequestPacket);
3254 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3255 assertNull(packet.mUserClass);
3256 }
3257
3258 @Test
3259 public void testRequestCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception {
3260 setUpRetrievedNetworkAttributesForInitRebootState();
3261
3262 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3263 (byte) 0x10 /* vendor-specific IE type */);
3264 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
3265 true /* isDhcpLeaseCacheEnabled */);
3266
3267 assertTrue(packet instanceof DhcpRequestPacket);
3268 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
3269 assertNull(packet.mUserClass);
3270 }
3271
3272 @Test
3273 public void testRequestCustomizedDhcpOptions_disallowedOption() throws Exception {
3274 setUpRetrievedNetworkAttributesForInitRebootState();
3275
3276 final List<DhcpOption> options = Arrays.asList(
3277 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3278 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3279 // Option 26: MTU
3280 makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU)));
3281 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3282 (byte) 0x17 /* vendor-specific IE type */);
3283 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3284 true /* isDhcpLeaseCacheEnabled */);
3285
3286 assertTrue(packet instanceof DhcpRequestPacket);
3287 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3288 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3289 assertNull(packet.mMtu);
3290 }
3291
3292 @Test
3293 public void testRequestCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception {
3294 setUpRetrievedNetworkAttributesForInitRebootState();
3295
3296 final List<DhcpOption> options = Arrays.asList(
3297 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
3298 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
3299 // NTP_SERVER
3300 makeDhcpOption((byte) 42, null));
3301 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3302 (byte) 0x17 /* vendor-specific IE type */);
3303 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3304 true /* isDhcpLeaseCacheEnabled */);
3305
3306 assertTrue(packet instanceof DhcpRequestPacket);
3307 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
3308 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
3309 assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */));
3310 }
3311
3312 @Test
3313 public void testRequestCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception {
3314 setUpRetrievedNetworkAttributesForInitRebootState();
3315
3316 final List<DhcpOption> options = Arrays.asList(
3317 // DHCP_USER_CLASS
3318 makeDhcpOption((byte) 77, null));
3319 final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
3320 (byte) 0x17 /* vendor-specific IE type */);
3321 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
3322 true /* isDhcpLeaseCacheEnabled */);
3323
3324 assertTrue(packet instanceof DhcpRequestPacket);
3325 assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */));
3326 assertNull(packet.mUserClass);
3327 }
3328
Xiao Ma002dd5a2020-12-22 01:14:49 +00003329 private void assertGratuitousNa(final NeighborAdvertisement na) throws Exception {
3330 final MacAddress etherMulticast =
3331 NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST);
3332 final LinkAddress target = new LinkAddress(na.naHdr.target, 64);
3333
3334 assertEquals(etherMulticast, na.ethHdr.dstMac);
3335 assertEquals(ETH_P_IPV6, na.ethHdr.etherType);
3336 assertEquals(IPPROTO_ICMPV6, na.ipv6Hdr.nextHeader);
3337 assertEquals(0xff, na.ipv6Hdr.hopLimit);
3338 assertTrue(na.ipv6Hdr.srcIp.isLinkLocalAddress());
3339 assertEquals(IPV6_ADDR_ALL_ROUTERS_MULTICAST, na.ipv6Hdr.dstIp);
3340 assertEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, na.icmpv6Hdr.type);
3341 assertEquals(0, na.icmpv6Hdr.code);
3342 assertEquals(0, na.naHdr.flags);
3343 assertTrue(target.isGlobalPreferred());
3344 }
3345
3346 @Test
Xiao Ma8a0b7672021-04-19 08:33:29 +00003347 public void testGratuitousNaForNewGlobalUnicastAddresses() throws Exception {
Xiao Ma002dd5a2020-12-22 01:14:49 +00003348 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3349 .withoutIpReachabilityMonitor()
3350 .withoutIPv4()
3351 .build();
3352
3353 setFeatureEnabled(NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION,
3354 true /* isGratuitousNaEnabled */);
3355 assertTrue(isFeatureEnabled(NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION, false));
3356 startIpClientProvisioning(config);
3357
Xiao Ma8a0b7672021-04-19 08:33:29 +00003358 doIpv6OnlyProvisioning();
Xiao Ma002dd5a2020-12-22 01:14:49 +00003359
3360 final List<NeighborAdvertisement> naList = new ArrayList<>();
3361 NeighborAdvertisement packet;
3362 while ((packet = getNextNeighborAdvertisement()) != null) {
3363 assertGratuitousNa(packet);
3364 naList.add(packet);
3365 }
3366 assertEquals(2, naList.size()); // privacy address and stable privacy address
3367 }
Xiao Ma8a0b7672021-04-19 08:33:29 +00003368
3369 private void startGratuitousArpAndNaAfterRoamingTest(boolean isGratuitousArpNaRoamingEnabled,
3370 boolean hasIpv4, boolean hasIpv6) throws Exception {
Xiao Ma861fe422021-04-16 03:03:03 +00003371 final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
3372 MacAddress.fromString(TEST_DEFAULT_BSSID));
Xiao Ma8a0b7672021-04-19 08:33:29 +00003373 final ScanResultInfo scanResultInfo =
3374 makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID);
3375 final ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
3376 .withoutIpReachabilityMonitor()
Xiao Ma861fe422021-04-16 03:03:03 +00003377 .withLayer2Information(layer2Info)
Xiao Ma8a0b7672021-04-19 08:33:29 +00003378 .withScanResultInfo(scanResultInfo)
3379 .withDisplayName("ssid");
3380 if (!hasIpv4) prov.withoutIPv4();
3381 if (!hasIpv6) prov.withoutIPv6();
3382
3383 // Enable rapid commit to accelerate DHCP handshake to shorten test duration,
3384 // not strictly necessary.
3385 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
3386 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
3387 if (isGratuitousArpNaRoamingEnabled) {
3388 setFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, true);
3389 assertTrue(isFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, false));
3390 }
3391 startIpClientProvisioning(prov.build());
3392 }
3393
3394 private void waitForGratuitousArpAndNaPacket(final List<ArpPacket> arpList,
3395 final List<NeighborAdvertisement> naList) throws Exception {
3396 NeighborAdvertisement na;
3397 ArpPacket garp;
3398 do {
3399 na = getNextNeighborAdvertisement();
3400 if (na != null) {
3401 assertGratuitousNa(na);
3402 naList.add(na);
3403 }
3404 garp = getNextArpPacket(TEST_TIMEOUT_MS);
3405 if (garp != null) {
3406 assertGratuitousARP(garp);
3407 arpList.add(garp);
3408 }
3409 } while (na != null || garp != null);
3410 }
3411
3412 @Test
3413 public void testGratuitousArpAndNaAfterRoaming() throws Exception {
3414 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
3415 true /* hasIpv4 */, true /* hasIpv6 */);
3416 performDualStackProvisioning();
3417 forceLayer2Roaming();
3418
3419 final List<ArpPacket> arpList = new ArrayList<>();
3420 final List<NeighborAdvertisement> naList = new ArrayList<>();
3421 waitForGratuitousArpAndNaPacket(arpList, naList);
3422 assertEquals(2, naList.size()); // privacy address and stable privacy address
3423 assertEquals(1, arpList.size()); // IPv4 address
3424 }
3425
3426 @Test
3427 public void testGratuitousArpAndNaAfterRoaming_disableExpFlag() throws Exception {
3428 startGratuitousArpAndNaAfterRoamingTest(false /* isGratuitousArpNaRoamingEnabled */,
Xiao Ma60175d22021-06-02 12:28:40 +00003429 true /* hasIpv4 */, true /* hasIpv6 */);
Xiao Ma8a0b7672021-04-19 08:33:29 +00003430 performDualStackProvisioning();
3431 forceLayer2Roaming();
3432
3433 final List<ArpPacket> arpList = new ArrayList<>();
3434 final List<NeighborAdvertisement> naList = new ArrayList<>();
3435 waitForGratuitousArpAndNaPacket(arpList, naList);
3436 assertEquals(0, naList.size());
3437 assertEquals(0, arpList.size());
3438 }
3439
3440 @Test
3441 public void testGratuitousArpAndNaAfterRoaming_IPv6OnlyNetwork() throws Exception {
3442 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
3443 false /* hasIpv4 */, true /* hasIpv6 */);
3444 doIpv6OnlyProvisioning();
3445 forceLayer2Roaming();
3446
3447 final List<ArpPacket> arpList = new ArrayList<>();
3448 final List<NeighborAdvertisement> naList = new ArrayList<>();
3449 waitForGratuitousArpAndNaPacket(arpList, naList);
3450 assertEquals(2, naList.size());
3451 assertEquals(0, arpList.size());
3452 }
3453
3454 @Test
3455 public void testGratuitousArpAndNaAfterRoaming_IPv4OnlyNetwork() throws Exception {
3456 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
3457 true /* hasIpv4 */, false /* hasIpv6 */);
3458
3459 // Start IPv4 provisioning and wait until entire provisioning completes.
3460 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
3461 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */);
3462 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
3463 forceLayer2Roaming();
3464
3465 final List<ArpPacket> arpList = new ArrayList<>();
3466 final List<NeighborAdvertisement> naList = new ArrayList<>();
3467 waitForGratuitousArpAndNaPacket(arpList, naList);
3468 assertEquals(0, naList.size());
3469 assertEquals(1, arpList.size());
3470 }
Xiao Ma60175d22021-06-02 12:28:40 +00003471
3472 private void assertNeighborSolicitation(final NeighborSolicitation ns,
3473 final Inet6Address target) {
3474 assertEquals(ETH_P_IPV6, ns.ethHdr.etherType);
3475 assertEquals(IPPROTO_ICMPV6, ns.ipv6Hdr.nextHeader);
3476 assertEquals(0xff, ns.ipv6Hdr.hopLimit);
3477 assertTrue(ns.ipv6Hdr.srcIp.isLinkLocalAddress());
3478 assertEquals(ICMPV6_NEIGHBOR_SOLICITATION, ns.icmpv6Hdr.type);
3479 assertEquals(0, ns.icmpv6Hdr.code);
3480 assertEquals(0, ns.nsHdr.reserved);
3481 assertEquals(target, ns.nsHdr.target);
3482 assertEquals(ns.slla.linkLayerAddress, ns.ethHdr.srcMac);
3483 }
3484
3485 private void assertUnicastNeighborSolicitation(final NeighborSolicitation ns,
3486 final MacAddress dstMac, final Inet6Address dstIp, final Inet6Address target) {
3487 assertEquals(dstMac, ns.ethHdr.dstMac);
3488 assertEquals(dstIp, ns.ipv6Hdr.dstIp);
3489 assertNeighborSolicitation(ns, target);
3490 }
3491
Xiao Ma69a936a2021-04-21 08:14:44 +00003492 private void assertMulticastNeighborSolicitation(final NeighborSolicitation ns,
3493 final Inet6Address target) {
3494 final MacAddress etherMulticast =
3495 NetworkStackUtils.ipv6MulticastToEthernetMulticast(ns.ipv6Hdr.dstIp);
3496 assertEquals(etherMulticast, ns.ethHdr.dstMac);
3497 assertTrue(ns.ipv6Hdr.dstIp.isMulticastAddress());
3498 assertNeighborSolicitation(ns, target);
3499 }
3500
3501 private NeighborSolicitation waitForUnicastNeighborSolicitation(final MacAddress dstMac,
3502 final Inet6Address dstIp, final Inet6Address targetIp) throws Exception {
3503 NeighborSolicitation ns;
3504 while ((ns = getNextNeighborSolicitation()) != null) {
3505 // Filter out the NSes used for duplicate address detetction, the target address
3506 // is the global IPv6 address inside these NSes.
3507 if (ns.nsHdr.target.isLinkLocalAddress()) break;
3508 }
3509 assertNotNull("No unicast Neighbor solicitation received on interface within timeout", ns);
3510 assertUnicastNeighborSolicitation(ns, dstMac, dstIp, targetIp);
3511 return ns;
3512 }
3513
3514 private List<NeighborSolicitation> waitForMultipleNeighborSolicitations() throws Exception {
3515 NeighborSolicitation ns;
3516 final List<NeighborSolicitation> nsList = new ArrayList<NeighborSolicitation>();
3517 while ((ns = getNextNeighborSolicitation()) != null) {
3518 // Filter out the NSes used for duplicate address detetction, the target address
3519 // is the global IPv6 address inside these NSes.
3520 if (ns.nsHdr.target.isLinkLocalAddress()) {
3521 nsList.add(ns);
3522 }
3523 }
3524 assertFalse(nsList.isEmpty());
3525 return nsList;
3526 }
3527
3528 // Override this function with disabled experiment flag by default, in order not to
3529 // affect those tests which are just related to basic IpReachabilityMonitor infra.
Xiao Ma60175d22021-06-02 12:28:40 +00003530 private void prepareIpReachabilityMonitorTest() throws Exception {
Xiao Ma69a936a2021-04-21 08:14:44 +00003531 prepareIpReachabilityMonitorTest(false /* isMulticastResolicitEnabled */);
3532 }
3533
Xiao Ma374387c2021-11-02 02:25:55 +00003534 private void assertNotifyNeighborLost(Inet6Address targetIp, NudEventType eventType)
3535 throws Exception {
3536 // For root test suite, rely on the IIpClient aidl interface version constant defined in
3537 // {@link IpClientRootTest.BinderCbWrapper}; for privileged integration test suite that
3538 // requires signature permission, use the mocked aidl version defined in {@link setUpMocks},
3539 // which results in only new callbacks are verified. And add separate test cases to test the
3540 // legacy callbacks explicitly as well.
3541 assertNeighborReachabilityLoss(targetIp, eventType,
3542 useNetworkStackSignature()
3543 ? IpClient.VERSION_ADDED_REACHABILITY_FAILURE
3544 : mIIpClient.getInterfaceVersion());
3545 }
3546
3547 private void assertNeighborReachabilityLoss(Inet6Address targetIp, NudEventType eventType,
3548 int targetAidlVersion) throws Exception {
3549 if (targetAidlVersion >= IpClient.VERSION_ADDED_REACHABILITY_FAILURE) {
3550 final ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor =
3551 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class);
3552 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityFailure(lossInfoCaptor.capture());
3553 assertEquals(nudEventTypeToInt(eventType), lossInfoCaptor.getValue().reason);
3554 verify(mCb, never()).onReachabilityLost(any());
3555 } else {
3556 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any());
3557 verify(mCb, never()).onReachabilityFailure(any());
3558 }
3559 }
3560
3561 private void assertNeverNotifyNeighborLost() throws Exception {
3562 verify(mCb, never()).onReachabilityFailure(any());
3563 verify(mCb, never()).onReachabilityLost(any());
3564 }
3565
Xiao Ma69a936a2021-04-21 08:14:44 +00003566 private void prepareIpReachabilityMonitorTest(boolean isMulticastResolicitEnabled)
3567 throws Exception {
Xiao Ma60175d22021-06-02 12:28:40 +00003568 final ScanResultInfo info = makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID);
3569 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3570 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
3571 MacAddress.fromString(TEST_DEFAULT_BSSID)))
3572 .withScanResultInfo(info)
3573 .withDisplayName(TEST_DEFAULT_SSID)
3574 .withoutIPv4()
3575 .build();
Xiao Ma69a936a2021-04-21 08:14:44 +00003576 setFeatureEnabled(NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION,
3577 isMulticastResolicitEnabled);
Xiao Ma60175d22021-06-02 12:28:40 +00003578 startIpClientProvisioning(config);
3579 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
3580 doIpv6OnlyProvisioning();
3581
3582 // Simulate the roaming.
3583 forceLayer2Roaming();
3584 }
3585
Xiao Ma374387c2021-11-02 02:25:55 +00003586 private void runIpReachabilityMonitorProbeFailedTest() throws Exception {
Xiao Ma60175d22021-06-02 12:28:40 +00003587 prepareIpReachabilityMonitorTest();
3588
Xiao Ma69a936a2021-04-21 08:14:44 +00003589 final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations();
3590 assertEquals(MIN_NUD_SOLICIT_NUM, nsList.size());
Xiao Ma60175d22021-06-02 12:28:40 +00003591 for (NeighborSolicitation ns : nsList) {
3592 assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
3593 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3594 }
Xiao Ma374387c2021-11-02 02:25:55 +00003595 }
3596
3597 @Test
3598 public void testIpReachabilityMonitor_probeFailed() throws Exception {
3599 runIpReachabilityMonitorProbeFailedTest();
3600 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */,
3601 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL);
3602 }
3603
3604 @Test @SignatureRequiredTest(reason = "requires mock callback object")
3605 public void testIpReachabilityMonitor_probeFailed_legacyCallback() throws Exception {
3606 when(mCb.getInterfaceVersion()).thenReturn(12 /* assign an older interface aidl version */);
3607
3608 runIpReachabilityMonitorProbeFailedTest();
3609 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any());
3610 verify(mCb, never()).onReachabilityFailure(any());
Xiao Ma60175d22021-06-02 12:28:40 +00003611 }
3612
3613 @Test
3614 public void testIpReachabilityMonitor_probeReachable() throws Exception {
3615 prepareIpReachabilityMonitorTest();
3616
Xiao Ma69a936a2021-04-21 08:14:44 +00003617 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
Xiao Ma60175d22021-06-02 12:28:40 +00003618 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3619
3620 // Reply Neighbor Advertisement and check notifyLost callback won't be triggered.
3621 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
3622 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */,
3623 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
3624 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
3625 mPacketReader.sendResponse(na);
3626 assertNeverNotifyNeighborLost();
3627 }
Xiao Ma69a936a2021-04-21 08:14:44 +00003628
Xiao Ma374387c2021-11-02 02:25:55 +00003629 private void runIpReachabilityMonitorMcastResolicitProbeFailedTest() throws Exception {
Xiao Ma69a936a2021-04-21 08:14:44 +00003630 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
3631
3632 final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations();
3633 int expectedSize = MIN_NUD_SOLICIT_NUM + NUD_MCAST_RESOLICIT_NUM;
3634 assertEquals(expectedSize, nsList.size()); // 5 unicast NSes + 3 multicast NSes
3635 for (NeighborSolicitation ns : nsList.subList(0, MIN_NUD_SOLICIT_NUM)) {
3636 assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
3637 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3638 }
3639 for (NeighborSolicitation ns : nsList.subList(MIN_NUD_SOLICIT_NUM, nsList.size())) {
3640 assertMulticastNeighborSolicitation(ns, ROUTER_LINK_LOCAL /* targetIp */);
3641 }
Xiao Ma69a936a2021-04-21 08:14:44 +00003642 }
3643
3644 @Test
Xiao Ma374387c2021-11-02 02:25:55 +00003645 public void testIpReachabilityMonitor_mcastResolicitProbeFailed() throws Exception {
3646 runIpReachabilityMonitorMcastResolicitProbeFailedTest();
3647 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */,
3648 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL);
3649 }
3650
3651 @Test @SignatureRequiredTest(reason = "requires mock callback object")
3652 public void testIpReachabilityMonitor_mcastResolicitProbeFailed_legacyCallback()
3653 throws Exception {
3654 when(mCb.getInterfaceVersion()).thenReturn(12 /* assign an older interface aidl version */);
3655
3656 runIpReachabilityMonitorMcastResolicitProbeFailedTest();
3657 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any());
3658 verify(mCb, never()).onReachabilityFailure(any());
3659 }
3660
3661 @Test
3662 public void testIpReachabilityMonitor_mcastResolicitProbeReachableWithSameLinkLayerAddress()
Xiao Ma69a936a2021-04-21 08:14:44 +00003663 throws Exception {
3664 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
3665
3666 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
3667 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3668
3669 // Reply Neighbor Advertisement and check notifyLost callback won't be triggered.
3670 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
3671 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */,
3672 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
3673 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
3674 mPacketReader.sendResponse(na);
3675 assertNeverNotifyNeighborLost();
3676 }
3677
3678 @Test
Xiao Ma374387c2021-11-02 02:25:55 +00003679 public void testIpReachabilityMonitor_mcastResolicitProbeReachableWithDiffLinkLayerAddress()
Xiao Ma69a936a2021-04-21 08:14:44 +00003680 throws Exception {
3681 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
3682
3683 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
3684 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
3685
3686 // Reply Neighbor Advertisement with a different link-layer address and check notifyLost
3687 // callback will be triggered. Override flag must be set, which indicates that the
3688 // advertisement should override an existing cache entry and update the cached link-layer
3689 // address, otherwise, kernel won't transit to REACHABLE state with a different link-layer
3690 // address.
3691 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
3692 | NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE;
3693 final MacAddress newMac = MacAddress.fromString("00:1a:11:22:33:55");
3694 final ByteBuffer na = NeighborAdvertisement.build(newMac /* srcMac */,
3695 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
3696 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
3697 mPacketReader.sendResponse(na);
Xiao Ma374387c2021-11-02 02:25:55 +00003698 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */,
3699 NudEventType.NUD_POST_ROAMING_MAC_ADDRESS_CHANGED);
Xiao Ma69a936a2021-04-21 08:14:44 +00003700 }
Xiao Ma326820d2020-11-24 16:21:04 +09003701
3702 @Test
3703 public void testIPv6LinkLocalOnly() throws Exception {
3704 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3705 .withoutIPv4()
3706 .withIpv6LinkLocalOnly()
3707 .withRandomMacAddress()
3708 .build();
3709 startIpClientProvisioning(config);
3710
3711 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
3712 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
3713 final LinkProperties lp = captor.getValue();
3714 assertNotNull(lp);
3715 assertEquals(0, lp.getDnsServers().size());
3716 final List<LinkAddress> addresses = lp.getLinkAddresses();
3717 assertEquals(1, addresses.size());
3718 assertTrue(addresses.get(0).getAddress().isLinkLocalAddress());
3719 assertEquals(1, lp.getRoutes().size());
3720 final RouteInfo route = lp.getRoutes().get(0);
3721 assertNotNull(route);
3722 assertTrue(route.getDestination().equals(new IpPrefix("fe80::/64")));
3723 assertTrue(route.getGateway().isAnyLocalAddress());
Lorenzo Colitti8b93f292021-10-12 16:58:56 +09003724
3725 // Check that if an RA is received, no IP addresses, routes, or DNS servers are configured.
3726 // Instead of waiting some period of time for the RA to be received and checking the
3727 // LinkProperties after that, tear down the interface and wait for it to go down. Then check
3728 // that no LinkProperties updates ever contained non-link-local information.
3729 sendBasicRouterAdvertisement(false /* waitForRs */);
3730 teardownTapInterface();
3731 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any());
3732 verify(mCb, never()).onLinkPropertiesChange(argThat(newLp ->
3733 newLp.getDnsServers().size() != 0
3734 || newLp.getRoutes().size() > 1
3735 || newLp.hasIpv6DefaultRoute()
3736 || newLp.hasGlobalIpv6Address()
3737 ));
3738 }
3739
3740 @Test
3741 public void testIPv6LinkLocalOnlyAndThenGlobal() throws Exception {
3742 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3743 .withoutIPv4()
3744 .withIpv6LinkLocalOnly()
3745 .withRandomMacAddress()
3746 .build();
3747 startIpClientProvisioning(config);
3748 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any());
3749 mIIpClient.stop();
3750 verifyAfterIpClientShutdown();
3751 reset(mCb);
3752
3753 // Speed up provisioning by enabling rapid commit. TODO: why is this necessary?
3754 setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
3755 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
3756 config = new ProvisioningConfiguration.Builder()
3757 .build();
3758 startIpClientProvisioning(config);
3759 performDualStackProvisioning();
3760 // No exceptions? Dual-stack provisioning worked.
Xiao Ma326820d2020-11-24 16:21:04 +09003761 }
3762
3763 @Test
3764 public void testIPv6LinkLocalOnly_enableBothIPv4andIPv6LinkLocalOnly() throws Exception {
3765 assertThrows(IllegalArgumentException.class,
3766 () -> new ProvisioningConfiguration.Builder()
3767 .withoutIpReachabilityMonitor()
3768 .withIpv6LinkLocalOnly()
3769 .withRandomMacAddress()
3770 .build()
3771 );
3772 }
Xiao Maac371ef2021-09-15 03:37:41 +00003773
3774 @Test
3775 public void testIpClientLinkObserver_onClatInterfaceStateUpdate() throws Exception {
3776 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3777 .withoutIPv4()
3778 .build();
3779 startIpClientProvisioning(config);
3780 doIpv6OnlyProvisioning();
3781
3782 reset(mCb);
3783
3784 // Add the clat interface and check the callback.
3785 final TestNetworkInterface clatIface = setUpClatInterface(mIfaceName);
3786 assertNotNull(clatIface);
3787 assertTrue(clatIface.getInterfaceName().equals(CLAT_PREFIX + mIfaceName));
3788 verify(mCb, timeout(TEST_TIMEOUT_MS)).setNeighborDiscoveryOffload(false);
3789
3790 // Remove the clat interface and check the callback.
3791 removeTestInterface(clatIface.getFileDescriptor().getFileDescriptor());
3792 verify(mCb, timeout(TEST_TIMEOUT_MS)).setNeighborDiscoveryOffload(true);
3793 }
Xiao Mad83a6a82022-06-09 14:39:25 +09003794
Xiao Mad1c55452022-06-10 09:10:13 +09003795 @Ignore("TODO: temporarily ignore tests until prebuilts are updated")
Xiao Mad83a6a82022-06-09 14:39:25 +09003796 @Test @SignatureRequiredTest(reason = "requires mock callback object")
3797 public void testNetlinkSocketReceiveENOBUFS() throws Exception {
3798 if (!mIsNetlinkEventParseEnabled) return;
3799
3800 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
3801 .withoutIPv4()
3802 .build();
3803 startIpClientProvisioning(config);
3804 doIpv6OnlyProvisioning();
3805 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
3806
3807 // Block IpClient handler.
3808 final CountDownLatch latch = new CountDownLatch(1);
3809 mIpc.getHandler().post(() -> {
3810 try {
3811 latch.await(10_000L /* 10s */, TimeUnit.MILLISECONDS);
3812 } catch (InterruptedException e) {
3813 // do nothing
3814 }
3815 });
3816
3817 // Send large amount of RAs to overflow the netlink socket receive buffer.
3818 for (int i = 0; i < 100; i++) {
3819 sendBasicRouterAdvertisement(false /* waitRs */);
3820 }
3821
3822 // Unblock the IpClient handler.
3823 latch.countDown();
3824 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
3825
3826 reset(mCb);
3827
3828 // 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 +09003829 // Due to ignoring the ENOBUFS and wait until handler gets idle, IpClient should be still
3830 // able to see the RA with 0 router lifetime and the IPv6 default route will be removed.
Xiao Mad83a6a82022-06-09 14:39:25 +09003831 sendRouterAdvertisementWithZeroLifetime();
Xiao Ma148f5742022-06-06 11:20:33 +09003832 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
3833 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
3834 final LinkProperties lp = captor.getValue();
3835 assertFalse(lp.hasIpv6DefaultRoute());
Xiao Mad83a6a82022-06-09 14:39:25 +09003836 }
Lorenzo Colitti038f3cd2019-11-02 01:02:39 +09003837}