1 /* 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 17 package android.net.ip; 18 19 import static android.Manifest.permission.MANAGE_TEST_NETWORKS; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; 23 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; 24 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 25 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; 26 import static android.net.NetworkCapabilities.TRANSPORT_TEST; 27 import static android.net.RouteInfo.RTN_UNICAST; 28 import static android.net.dhcp.DhcpClient.EXPIRED_LEASE; 29 import static android.net.dhcp.DhcpPacket.CONFIG_MINIMUM_LEASE; 30 import static android.net.dhcp.DhcpPacket.DHCP_BOOTREQUEST; 31 import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; 32 import static android.net.dhcp.DhcpPacket.DHCP_IPV6_ONLY_PREFERRED; 33 import static android.net.dhcp.DhcpPacket.DHCP_MAGIC_COOKIE; 34 import static android.net.dhcp.DhcpPacket.DHCP_SERVER; 35 import static android.net.dhcp.DhcpPacket.ENCAP_L2; 36 import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; 37 import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; 38 import static android.net.dhcp.DhcpPacket.MIN_V6ONLY_WAIT_MS; 39 import static android.net.ip.IIpClientCallbacks.DTIM_MULTIPLIER_RESET; 40 import static android.net.ip.IpClient.CONFIG_IPV6_AUTOCONF_TIMEOUT; 41 import static android.net.ip.IpClient.CONFIG_ACCEPT_RA_MIN_LFT; 42 import static android.net.ip.IpClient.CONFIG_APF_COUNTER_POLLING_INTERVAL_SECS; 43 import static android.net.ip.IpClient.CONFIG_NUD_FAILURE_COUNT_DAILY_THRESHOLD; 44 import static android.net.ip.IpClient.CONFIG_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD; 45 import static android.net.ip.IpClient.DEFAULT_APF_COUNTER_POLLING_INTERVAL_SECS; 46 import static android.net.ip.IpClient.DEFAULT_NUD_FAILURE_COUNT_DAILY_THRESHOLD; 47 import static android.net.ip.IpClient.DEFAULT_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD; 48 import static android.net.ip.IpClient.ONE_DAY_IN_MS; 49 import static android.net.ip.IpClient.ONE_WEEK_IN_MS; 50 import static android.net.ip.IpClient.SIX_HOURS_IN_MS; 51 import static android.net.ip.IpClientLinkObserver.CLAT_PREFIX; 52 import static android.net.ip.IpClientLinkObserver.CONFIG_SOCKET_RECV_BUFSIZE; 53 import static android.net.ip.IpReachabilityMonitor.NUD_MCAST_RESOLICIT_NUM; 54 import static android.net.ip.IpReachabilityMonitor.nudEventTypeToInt; 55 import static android.net.ipmemorystore.Status.SUCCESS; 56 import static android.system.OsConstants.ETH_P_IPV6; 57 import static android.system.OsConstants.IFA_F_TEMPORARY; 58 import static android.system.OsConstants.IPPROTO_ICMPV6; 59 import static android.system.OsConstants.IPPROTO_IPV6; 60 import static android.system.OsConstants.IPPROTO_UDP; 61 62 import static com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress; 63 import static com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address; 64 import static com.android.net.module.util.NetworkStackConstants.ALL_DHCP_RELAY_AGENTS_AND_SERVERS; 65 import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY; 66 import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST; 67 import static com.android.net.module.util.NetworkStackConstants.DHCP6_CLIENT_PORT; 68 import static com.android.net.module.util.NetworkStackConstants.DHCP6_SERVER_PORT; 69 import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; 70 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST; 71 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN; 72 import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_OFFSET; 73 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA; 74 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; 75 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; 76 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; 77 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; 78 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; 79 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; 80 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; 81 import static com.android.net.module.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET; 82 import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; 83 import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; 84 import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; 85 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; 86 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; 87 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION; 88 import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION; 89 import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION; 90 import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION; 91 import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION; 92 import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION; 93 import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION; 94 import static com.android.testutils.MiscAsserts.assertThrows; 95 import static com.android.testutils.ParcelUtils.parcelingRoundTrip; 96 import static com.android.testutils.TestPermissionUtil.runAsShell; 97 98 import static junit.framework.Assert.fail; 99 100 import static org.junit.Assert.assertArrayEquals; 101 import static org.junit.Assert.assertEquals; 102 import static org.junit.Assert.assertFalse; 103 import static org.junit.Assert.assertNotEquals; 104 import static org.junit.Assert.assertNotNull; 105 import static org.junit.Assert.assertNull; 106 import static org.junit.Assert.assertTrue; 107 import static org.junit.Assume.assumeFalse; 108 import static org.junit.Assume.assumeTrue; 109 import static org.mockito.ArgumentMatchers.anyInt; 110 import static org.mockito.ArgumentMatchers.anyLong; 111 import static org.mockito.ArgumentMatchers.contains; 112 import static org.mockito.ArgumentMatchers.longThat; 113 import static org.mockito.Mockito.after; 114 import static org.mockito.Mockito.any; 115 import static org.mockito.Mockito.argThat; 116 import static org.mockito.Mockito.atLeastOnce; 117 import static org.mockito.Mockito.clearInvocations; 118 import static org.mockito.Mockito.doAnswer; 119 import static org.mockito.Mockito.doThrow; 120 import static org.mockito.Mockito.eq; 121 import static org.mockito.Mockito.inOrder; 122 import static org.mockito.Mockito.mock; 123 import static org.mockito.Mockito.never; 124 import static org.mockito.Mockito.reset; 125 import static org.mockito.Mockito.spy; 126 import static org.mockito.Mockito.timeout; 127 import static org.mockito.Mockito.times; 128 import static org.mockito.Mockito.verify; 129 import static org.mockito.Mockito.verifyNoMoreInteractions; 130 import static org.mockito.Mockito.when; 131 132 import android.app.AlarmManager; 133 import android.app.AlarmManager.OnAlarmListener; 134 import android.app.Instrumentation; 135 import android.app.admin.DevicePolicyManager; 136 import android.content.ComponentName; 137 import android.content.ContentResolver; 138 import android.content.Context; 139 import android.content.pm.PackageManager; 140 import android.content.res.Resources; 141 import android.net.ConnectivityManager; 142 import android.net.DhcpResultsParcelable; 143 import android.net.IIpMemoryStore; 144 import android.net.INetd; 145 import android.net.InetAddresses; 146 import android.net.InterfaceConfigurationParcel; 147 import android.net.IpPrefix; 148 import android.net.Layer2InformationParcelable; 149 import android.net.Layer2PacketParcelable; 150 import android.net.LinkAddress; 151 import android.net.LinkProperties; 152 import android.net.MacAddress; 153 import android.net.Network; 154 import android.net.NetworkAgentConfig; 155 import android.net.NetworkCapabilities; 156 import android.net.NetworkRequest; 157 import android.net.NetworkSpecifier; 158 import android.net.NetworkStackIpMemoryStore; 159 import android.net.RouteInfo; 160 import android.net.TestNetworkInterface; 161 import android.net.TestNetworkManager; 162 import android.net.Uri; 163 import android.net.dhcp.DhcpClient; 164 import android.net.dhcp.DhcpDeclinePacket; 165 import android.net.dhcp.DhcpDiscoverPacket; 166 import android.net.dhcp.DhcpPacket; 167 import android.net.dhcp.DhcpPacket.ParseException; 168 import android.net.dhcp.DhcpRequestPacket; 169 import android.net.dhcp6.Dhcp6Client; 170 import android.net.dhcp6.Dhcp6Packet; 171 import android.net.dhcp6.Dhcp6Packet.PrefixDelegation; 172 import android.net.dhcp6.Dhcp6RebindPacket; 173 import android.net.dhcp6.Dhcp6RenewPacket; 174 import android.net.dhcp6.Dhcp6RequestPacket; 175 import android.net.dhcp6.Dhcp6SolicitPacket; 176 import android.net.ipmemorystore.NetworkAttributes; 177 import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener; 178 import android.net.ipmemorystore.OnNetworkEventCountRetrievedListener; 179 import android.net.ipmemorystore.Status; 180 import android.net.networkstack.TestNetworkStackServiceClient; 181 import android.net.networkstack.aidl.dhcp.DhcpOption; 182 import android.net.networkstack.aidl.ip.ReachabilityLossInfoParcelable; 183 import android.net.networkstack.aidl.ip.ReachabilityLossReason; 184 import android.net.shared.Layer2Information; 185 import android.net.shared.ProvisioningConfiguration; 186 import android.net.shared.ProvisioningConfiguration.ScanResultInfo; 187 import android.net.util.HostnameTransliterator; 188 import android.os.Build; 189 import android.os.Handler; 190 import android.os.HandlerThread; 191 import android.os.IBinder; 192 import android.os.ParcelFileDescriptor; 193 import android.os.PowerManager; 194 import android.os.RemoteException; 195 import android.os.SystemClock; 196 import android.provider.Settings; 197 import android.stats.connectivity.NudEventType; 198 import android.system.ErrnoException; 199 import android.system.Os; 200 import android.util.Log; 201 import android.util.Pair; 202 203 import androidx.annotation.NonNull; 204 import androidx.test.InstrumentationRegistry; 205 import androidx.test.filters.SmallTest; 206 207 import com.android.internal.util.HexDump; 208 import com.android.internal.util.StateMachine; 209 import com.android.modules.utils.build.SdkLevel; 210 import com.android.net.module.util.ArrayTrackRecord; 211 import com.android.net.module.util.InterfaceParams; 212 import com.android.net.module.util.Ipv6Utils; 213 import com.android.net.module.util.PacketBuilder; 214 import com.android.net.module.util.SharedLog; 215 import com.android.net.module.util.Struct; 216 import com.android.net.module.util.arp.ArpPacket; 217 import com.android.net.module.util.ip.IpNeighborMonitor; 218 import com.android.net.module.util.ip.IpNeighborMonitor.NeighborEventConsumer; 219 import com.android.net.module.util.netlink.NetlinkUtils; 220 import com.android.net.module.util.netlink.StructNdOptPref64; 221 import com.android.net.module.util.structs.EthernetHeader; 222 import com.android.net.module.util.structs.IaPrefixOption; 223 import com.android.net.module.util.structs.Ipv6Header; 224 import com.android.net.module.util.structs.LlaOption; 225 import com.android.net.module.util.structs.PrefixInformationOption; 226 import com.android.net.module.util.structs.RdnssOption; 227 import com.android.networkstack.R; 228 import com.android.networkstack.apishim.CaptivePortalDataShimImpl; 229 import com.android.networkstack.ipmemorystore.IpMemoryStoreService; 230 import com.android.networkstack.metrics.IpProvisioningMetrics; 231 import com.android.networkstack.metrics.IpReachabilityMonitorMetrics; 232 import com.android.networkstack.metrics.NetworkQuirkMetrics; 233 import com.android.networkstack.packets.NeighborAdvertisement; 234 import com.android.networkstack.packets.NeighborSolicitation; 235 import com.android.networkstack.util.NetworkStackUtils; 236 import com.android.server.NetworkStackService.NetworkStackServiceManager; 237 import com.android.testutils.CompatUtil; 238 import com.android.testutils.DevSdkIgnoreRule; 239 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 240 import com.android.testutils.HandlerUtils; 241 import com.android.testutils.PollPacketReader; 242 import com.android.testutils.TestableNetworkAgent; 243 import com.android.testutils.TestableNetworkCallback; 244 245 import kotlin.Lazy; 246 import kotlin.LazyKt; 247 248 import org.junit.After; 249 import org.junit.Before; 250 import org.junit.Rule; 251 import org.junit.Test; 252 import org.junit.rules.TestName; 253 import org.mockito.ArgumentCaptor; 254 import org.mockito.InOrder; 255 import org.mockito.Mock; 256 import org.mockito.MockitoAnnotations; 257 import org.mockito.Spy; 258 259 import java.io.BufferedReader; 260 import java.io.File; 261 import java.io.FileDescriptor; 262 import java.io.FileReader; 263 import java.io.IOException; 264 import java.lang.annotation.ElementType; 265 import java.lang.annotation.Repeatable; 266 import java.lang.annotation.Retention; 267 import java.lang.annotation.RetentionPolicy; 268 import java.lang.annotation.Target; 269 import java.lang.reflect.Method; 270 import java.net.DatagramPacket; 271 import java.net.DatagramSocket; 272 import java.net.Inet4Address; 273 import java.net.Inet6Address; 274 import java.net.InetAddress; 275 import java.net.NetworkInterface; 276 import java.nio.ByteBuffer; 277 import java.util.ArrayList; 278 import java.util.Arrays; 279 import java.util.Collection; 280 import java.util.Collections; 281 import java.util.List; 282 import java.util.Objects; 283 import java.util.Random; 284 import java.util.concurrent.CompletableFuture; 285 import java.util.concurrent.CountDownLatch; 286 import java.util.concurrent.TimeUnit; 287 import java.util.concurrent.atomic.AtomicReference; 288 import java.util.function.Predicate; 289 290 /** 291 * Base class for IpClient tests. 292 * 293 * Tests in this class can either be run with signature permissions, or with root access. 294 */ 295 @SmallTest 296 public abstract class IpClientIntegrationTestCommon { 297 private static final String TAG = IpClientIntegrationTestCommon.class.getSimpleName(); 298 private static final int DATA_BUFFER_LEN = 4096; 299 private static final int PACKET_TIMEOUT_MS = 5_000; 300 private static final String TEST_CLUSTER = "some cluster"; 301 private static final int TEST_LEASE_DURATION_S = 3_600; // 1 hour 302 private static final int TEST_IPV6_ONLY_WAIT_S = 1_800; // 30 min 303 private static final int TEST_LOWER_IPV6_ONLY_WAIT_S = (int) (MIN_V6ONLY_WAIT_MS / 1000 - 1); 304 private static final int TEST_ZERO_IPV6_ONLY_WAIT_S = 0; 305 private static final long TEST_MAX_IPV6_ONLY_WAIT_S = 0xffffffffL; 306 private static final int TEST_DEVICE_OWNER_APP_UID = 14242; 307 private static final String TEST_DEVICE_OWNER_APP_PACKAGE = "com.example.deviceowner"; 308 protected static final String TEST_L2KEY = "some l2key"; 309 310 // TODO: move to NetlinkConstants, NetworkStackConstants, or OsConstants. 311 private static final int IFA_F_STABLE_PRIVACY = 0x800; 312 // To fix below AndroidLint warning: 313 // [InlinedApi] Field requires version 3 of the U Extensions SDK (current min is 0). 314 private static final int RTN_UNREACHABLE = 315 SdkLevel.isAtLeastT() ? RouteInfo.RTN_UNREACHABLE : 7; 316 317 protected static final long TEST_TIMEOUT_MS = 2_000L; 318 private static final long TEST_WAIT_ENOBUFS_TIMEOUT_MS = 30_000L; 319 private static final long TEST_WAIT_RENEW_REBIND_RETRANSMIT_MS = 15_000L; 320 // To prevent the flakiness about deprecationTime and expirationTime check, +/- 4s tolerance 321 // should be enough between the timestamp when the IP provisioning completes successfully and 322 // when IpClientLinkObserver sees the RTM_NEWADDR netlink events. 323 private static final long TEST_LIFETIME_TOLERANCE_MS = 4_000L; 324 325 @Rule 326 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); 327 @Rule 328 public final TestName mTestNameRule = new TestName(); 329 330 /** 331 * Indicates that a test requires signature permissions to run. 332 * 333 * Such tests can only be run on devices that use known signing keys, so this annotation must be 334 * avoided as much as possible. Consider whether the test can be written to use shell and root 335 * shell permissions, and run against the NetworkStack AIDL interface (IIpClient) instead. 336 */ 337 @Retention(RetentionPolicy.RUNTIME) 338 @Target({ElementType.METHOD}) 339 private @interface SignatureRequiredTest { reason()340 String reason(); 341 } 342 343 @Retention(RetentionPolicy.RUNTIME) 344 @Target({ElementType.METHOD}) 345 @Repeatable(FlagArray.class) 346 @interface Flag { name()347 String name(); enabled()348 boolean enabled(); 349 } 350 351 @Target({ElementType.METHOD}) 352 @Retention(RetentionPolicy.RUNTIME) 353 @interface FlagArray { value()354 Flag[] value(); 355 } 356 357 /**** BEGIN signature required test members ****/ 358 // Do not use unless the test *really* cannot be written to exercise IIpClient without mocks. 359 // Tests using the below members must be annotated with @SignatureRequiredTest (otherwise the 360 // members will be null), and can only be run on devices that use known signing keys. 361 // The members could technically be moved to the IpClientIntegrationTest subclass together with 362 // the tests requiring signature permissions, but this would make it harder to follow tests in 363 // multiple classes, and harder to migrate tests between signature required and not required. 364 365 @Mock private Context mContext; 366 @Mock private ConnectivityManager mCm; 367 @Mock private Resources mResources; 368 @Mock private AlarmManager mAlarm; 369 @Mock private ContentResolver mContentResolver; 370 @Mock private NetworkStackServiceManager mNetworkStackServiceManager; 371 @Mock private IpMemoryStoreService mIpMemoryStoreService; 372 @Mock private PowerManager.WakeLock mTimeoutWakeLock; 373 @Mock protected NetworkStackIpMemoryStore mIpMemoryStore; 374 @Mock private NetworkQuirkMetrics.Dependencies mNetworkQuirkMetricsDeps; 375 @Mock private IpReachabilityMonitorMetrics mIpReachabilityMonitorMetrics; 376 @Mock private DevicePolicyManager mDevicePolicyManager; 377 @Mock private PackageManager mPackageManager; 378 @Spy private INetd mNetd; 379 380 protected IpClient mIpc; 381 protected Dependencies mDependencies; 382 protected List<Pair<String, Pair<Long, Integer>>> mNetworkEvents = new ArrayList<>(); 383 384 /***** END signature required test members *****/ 385 386 protected IIpClientCallbacks mCb; 387 private IIpClient mIIpClient; 388 private String mIfaceName; 389 private HandlerThread mPacketReaderThread; 390 private Handler mHandler; 391 private PollPacketReader mPacketReader; 392 private FileDescriptor mTapFd; 393 private byte[] mClientMac; 394 private InetAddress mClientIpAddress; 395 private TestableNetworkAgent mNetworkAgent; 396 private HandlerThread mNetworkAgentThread; 397 398 private boolean mIsSignatureRequiredTest; 399 400 // ReadHeads for various packet streams. Cannot be initialized in @Before because ReadHead is 401 // single-thread-only, and AndroidJUnitRunner runs @Before and @Test on different threads. 402 // While it looks like these are created only once per test, they are actually created once per 403 // test method because JUnit recreates a fresh test class instance before every test method. 404 private Lazy<ArrayTrackRecord<byte[]>.ReadHead> mDhcpPacketReadHead = 405 LazyKt.lazy(() -> mPacketReader.getReceivedPackets().newReadHead()); 406 private Lazy<ArrayTrackRecord<byte[]>.ReadHead> mArpPacketReadHead = 407 LazyKt.lazy(() -> mPacketReader.getReceivedPackets().newReadHead()); 408 private Lazy<ArrayTrackRecord<byte[]>.ReadHead> mDhcp6PacketReadHead = 409 LazyKt.lazy(() -> mPacketReader.getReceivedPackets().newReadHead()); 410 411 // Ethernet header 412 private static final int ETH_HEADER_LEN = 14; 413 414 // IP header 415 private static final int IPV4_HEADER_LEN = 20; 416 private static final int IPV6_HEADER_LEN = 40; 417 private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12; 418 private static final int IPV4_DST_ADDR_OFFSET = IPV4_SRC_ADDR_OFFSET + 4; 419 420 // UDP header 421 private static final int UDP_HEADER_LEN = 8; 422 private static final int UDP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN; 423 private static final int UDP_SRC_PORT_OFFSET = UDP_HEADER_OFFSET + 0; 424 425 // DHCP header 426 private static final int DHCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN 427 + UDP_HEADER_LEN; 428 private static final int DHCP_MESSAGE_OP_CODE_OFFSET = DHCP_HEADER_OFFSET + 0; 429 private static final int DHCP_TRANSACTION_ID_OFFSET = DHCP_HEADER_OFFSET + 4; 430 private static final int DHCP_OPTION_MAGIC_COOKIE_OFFSET = DHCP_HEADER_OFFSET + 236; 431 432 // DHCPv6 header 433 private static final int DHCP6_HEADER_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN 434 + UDP_HEADER_LEN; 435 436 private static final Inet4Address SERVER_ADDR = ipv4Addr("192.168.1.100"); 437 private static final Inet4Address CLIENT_ADDR = ipv4Addr("192.168.1.2"); 438 private static final Inet4Address CLIENT_ADDR_NEW = ipv4Addr("192.168.1.3"); 439 private static final Inet4Address INADDR_ANY = ipv4Addr("0.0.0.0"); 440 private static final int PREFIX_LENGTH = 24; 441 private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH); 442 private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress( 443 SERVER_ADDR, PREFIX_LENGTH); 444 private static final String IPV6_LINK_LOCAL_PREFIX = "fe80::/64"; 445 private static final String IPV4_TEST_SUBNET_PREFIX = "192.168.1.0/24"; 446 private static final String IPV4_ANY_ADDRESS_PREFIX = "0.0.0.0/0"; 447 private static final String HOSTNAME = "testhostname"; 448 private static final String IPV6_OFF_LINK_DNS_SERVER = "2001:4860:4860::64"; 449 private static final String IPV6_ON_LINK_DNS_SERVER = "2001:db8:1::64"; 450 private static final int TEST_DEFAULT_MTU = 1500; 451 private static final int TEST_MIN_MTU = 1280; 452 private static final MacAddress ROUTER_MAC = MacAddress.fromString("00:1A:11:22:33:44"); 453 private static final byte[] ROUTER_MAC_BYTES = ROUTER_MAC.toByteArray(); 454 private static final Inet6Address ROUTER_LINK_LOCAL = ipv6Addr("fe80::1"); 455 private static final byte[] ROUTER_DUID = new byte[] { 456 // type: Link-layer address, hardware type: EUI64(27) 457 (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x1b, 458 // set 7th bit, and copy the first 3 bytes of mac address 459 (byte) 0x02, (byte) 0x1A, (byte) 0x11, 460 (byte) 0xFF, (byte) 0xFE, 461 // copy the last 3 bytes of mac address 462 (byte) 0x22, (byte) 0x33, (byte) 0x44, 463 }; 464 private static final String TEST_HOST_NAME = "AOSP on Crosshatch"; 465 private static final String TEST_HOST_NAME_TRANSLITERATION = "AOSP-on-Crosshatch"; 466 private static final String TEST_CAPTIVE_PORTAL_URL = "https://example.com/capportapi"; 467 private static final byte[] TEST_HOTSPOT_OUI = new byte[] { 468 (byte) 0x00, (byte) 0x17, (byte) 0xF2 469 }; 470 private static final byte LEGACY_TEST_VENDOR_SPECIFIC_IE_TYPE = 0x11; 471 private static final byte TEST_VENDOR_SPECIFIC_IE_TYPE = 0x21; 472 private static final int TEST_VENDOR_SPECIFIC_IE_ID = 0xdd; 473 474 private static final String TEST_DEFAULT_SSID = "test_ssid"; 475 private static final String TEST_DEFAULT_BSSID = "00:11:22:33:44:55"; 476 private static final String TEST_DHCP_ROAM_SSID = "0001docomo"; 477 private static final String TEST_DHCP_ROAM_BSSID = "00:4e:35:17:98:55"; 478 private static final String TEST_DHCP_ROAM_L2KEY = "roaming_l2key"; 479 private static final String TEST_DHCP_ROAM_CLUSTER = "roaming_cluster"; 480 private static final byte[] TEST_AP_OUI = new byte[] { 0x00, 0x1A, 0x11 }; 481 private static final byte[] TEST_OEM_OUI = new byte[] {(byte) 0x00, (byte) 0x17, (byte) 0xc3}; 482 private static final String TEST_OEM_VENDOR_ID = "vendor-class-identifier"; 483 private static final byte[] TEST_OEM_USER_CLASS_INFO = new byte[] { 484 // Instance of User Class: [0] 485 (byte) 0x03, /* UC_Len_0 */ (byte) 0x11, (byte) 0x22, (byte) 0x33, 486 // Instance of User Class: [1] 487 (byte) 0x03, /* UC_Len_1 */ (byte) 0x44, (byte) 0x55, (byte) 0x66, 488 }; 489 490 protected class Dependencies extends IpClient.Dependencies { 491 private DhcpClient mDhcpClient; 492 private Dhcp6Client mDhcp6Client; 493 private boolean mIsHostnameConfigurationEnabled; 494 private String mHostname; 495 private boolean mIsInterfaceRecovered; 496 setHostnameConfiguration(final boolean enable, final String hostname)497 public void setHostnameConfiguration(final boolean enable, final String hostname) { 498 mIsHostnameConfigurationEnabled = enable; 499 mHostname = hostname; 500 } 501 502 // Enable this flag to simulate the interface has been added back after removing 503 // on the provisioning start. However, the actual tap interface has been removed, 504 // interface parameters query will get null when attempting to restore Interface 505 // MTU. Create a new InterfaceParams instance and return instead just for interface 506 // toggling test case. simulateInterfaceRecover()507 public void simulateInterfaceRecover() { 508 mIsInterfaceRecovered = true; 509 } 510 511 @Override getInterfaceParams(String ifname)512 public InterfaceParams getInterfaceParams(String ifname) { 513 return mIsInterfaceRecovered 514 ? new InterfaceParams(ifname, 1 /* index */, 515 MacAddress.fromString("00:11:22:33:44:55")) 516 : super.getInterfaceParams(ifname); 517 } 518 519 @Override getNetd(Context context)520 public INetd getNetd(Context context) { 521 return mNetd; 522 } 523 524 @Override getIpMemoryStore(Context context, NetworkStackServiceManager nssManager)525 public NetworkStackIpMemoryStore getIpMemoryStore(Context context, 526 NetworkStackServiceManager nssManager) { 527 return mIpMemoryStore; 528 } 529 530 @Override makeDhcpClient(Context context, StateMachine controller, InterfaceParams ifParams, DhcpClient.Dependencies deps)531 public DhcpClient makeDhcpClient(Context context, StateMachine controller, 532 InterfaceParams ifParams, DhcpClient.Dependencies deps) { 533 mDhcpClient = DhcpClient.makeDhcpClient(context, controller, ifParams, deps); 534 return mDhcpClient; 535 } 536 537 @Override makeDhcp6Client(Context context, StateMachine controller, InterfaceParams ifParams, Dhcp6Client.Dependencies deps)538 public Dhcp6Client makeDhcp6Client(Context context, StateMachine controller, 539 InterfaceParams ifParams, Dhcp6Client.Dependencies deps) { 540 mDhcp6Client = Dhcp6Client.makeDhcp6Client(context, controller, ifParams, deps); 541 return mDhcp6Client; 542 } 543 544 @Override getIpReachabilityMonitor(Context context, InterfaceParams ifParams, Handler h, SharedLog log, IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker, IpReachabilityMonitor.Dependencies deps, final INetd netd)545 public IpReachabilityMonitor getIpReachabilityMonitor(Context context, 546 InterfaceParams ifParams, Handler h, SharedLog log, 547 IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker, 548 IpReachabilityMonitor.Dependencies deps, final INetd netd) { 549 return new IpReachabilityMonitor(context, ifParams, h, log, callback, 550 usingMultinetworkPolicyTracker, deps, netd); 551 } 552 553 @Override isFeatureEnabled(final Context context, final String name)554 public boolean isFeatureEnabled(final Context context, final String name) { 555 return IpClientIntegrationTestCommon.this.isFeatureEnabled(name); 556 } 557 558 @Override isFeatureNotChickenedOut(final Context context, final String name)559 public boolean isFeatureNotChickenedOut(final Context context, final String name) { 560 return IpClientIntegrationTestCommon.this.isFeatureNotChickenedOut(name); 561 } 562 563 @Override getDeviceConfigPropertyInt(String name, int ignoredDefaultValue)564 public int getDeviceConfigPropertyInt(String name, int ignoredDefaultValue) { 565 // Default is never used because all device config properties must be mocked by test. 566 try { 567 return Integer.parseInt(getDeviceConfigProperty(name)); 568 } catch (NumberFormatException e) { 569 throw new IllegalStateException("Non-mocked device config property " + name); 570 } 571 } 572 573 @Override getDhcp6ClientDependencies()574 public Dhcp6Client.Dependencies getDhcp6ClientDependencies() { 575 return new Dhcp6Client.Dependencies() { 576 @Override 577 public int getDeviceConfigPropertyInt(String name, int defaultValue) { 578 return Dependencies.this.getDeviceConfigPropertyInt(name, 579 defaultValue); 580 } 581 }; 582 } 583 584 @Override getDhcpClientDependencies( NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics)585 public DhcpClient.Dependencies getDhcpClientDependencies( 586 NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics) { 587 return new DhcpClient.Dependencies(ipMemoryStore, metrics) { 588 @Override 589 public boolean isFeatureEnabled(final Context context, final String name) { 590 return Dependencies.this.isFeatureEnabled(context, name); 591 } 592 593 @Override 594 public boolean isFeatureNotChickenedOut(final Context context, final String name) { 595 return Dependencies.this.isFeatureNotChickenedOut(context, name); 596 } 597 598 @Override 599 public int getIntDeviceConfig(final String name, int minimumValue, 600 int maximumValue, int defaultValue) { 601 return Dependencies.this.getDeviceConfigPropertyInt(name, defaultValue); 602 } 603 604 @Override 605 public int getIntDeviceConfig(final String name, int defaultValue) { 606 return Dependencies.this.getDeviceConfigPropertyInt(name, defaultValue); 607 } 608 609 @Override 610 public PowerManager.WakeLock getWakeLock(final PowerManager powerManager) { 611 return mTimeoutWakeLock; 612 } 613 614 @Override 615 public boolean getSendHostnameOverlaySetting(final Context context) { 616 return mIsHostnameConfigurationEnabled; 617 } 618 619 @Override 620 public String getDeviceName(final Context context) { 621 return mHostname; 622 } 623 }; 624 } 625 626 @Override 627 public IpReachabilityMonitor.Dependencies getIpReachabilityMonitorDeps(Context context, 628 String name) { 629 return new IpReachabilityMonitor.Dependencies() { 630 public void acquireWakeLock(long durationMs) { 631 // It doesn't matter for the integration test app on whether the wake lock 632 // is acquired or not. 633 return; 634 } 635 636 public IpNeighborMonitor makeIpNeighborMonitor(Handler h, SharedLog log, 637 NeighborEventConsumer cb) { 638 return new IpNeighborMonitor(h, log, cb); 639 } 640 641 public boolean isFeatureEnabled(final Context context, final String name) { 642 return Dependencies.this.isFeatureEnabled(context, name); 643 } 644 645 public boolean isFeatureNotChickenedOut(final Context context, final String name) { 646 return Dependencies.this.isFeatureNotChickenedOut(context, name); 647 } 648 649 public IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics() { 650 return mIpReachabilityMonitorMetrics; 651 } 652 }; 653 } 654 655 @Override 656 public NetworkQuirkMetrics getNetworkQuirkMetrics() { 657 return new NetworkQuirkMetrics(mNetworkQuirkMetricsDeps); 658 } 659 } 660 661 @NonNull 662 protected abstract IIpClient makeIIpClient( 663 @NonNull String ifaceName, @NonNull IIpClientCallbacks cb); 664 665 // In production. features are enabled if the flag is lower than the package version. 666 // For testing, we can just use 1 for enabled and -1 for disabled or chickened out. 667 static final String FEATURE_ENABLED = "1"; 668 static final String FEATURE_DISABLED = "-1"; 669 670 final void setFeatureEnabled(String feature, boolean enabled) { 671 setDeviceConfigProperty(feature, enabled ? FEATURE_ENABLED : FEATURE_DISABLED); 672 } 673 674 final void setFeatureChickenedOut(String feature, boolean chickenedOut) { 675 setDeviceConfigProperty(feature, chickenedOut ? FEATURE_DISABLED : FEATURE_ENABLED); 676 } 677 678 final void setDeviceConfigProperty(String name, int value) { 679 setDeviceConfigProperty(name, Integer.toString(value)); 680 } 681 682 protected abstract void setDeviceConfigProperty(String name, String value); 683 684 protected abstract String getDeviceConfigProperty(String name); 685 686 protected abstract boolean isFeatureEnabled(String name); 687 688 protected abstract boolean isFeatureNotChickenedOut(String name); 689 690 protected abstract boolean useNetworkStackSignature(); 691 692 protected abstract NetworkAttributes getStoredNetworkAttributes(String l2Key, long timeout); 693 694 protected abstract void storeNetworkAttributes(String l2Key, NetworkAttributes na); 695 696 protected abstract void assertIpMemoryNeverStoreNetworkAttributes(String l2Key, long timeout); 697 698 protected abstract int readNudSolicitNumInSteadyStateFromResource(); 699 700 protected abstract int readNudSolicitNumPostRoamingFromResource(); 701 702 protected abstract void storeNetworkEvent(String cluster, long now, long expiry, int eventType); 703 704 protected abstract int[] getStoredNetworkEventCount(String cluster, long[] sinceTimes, 705 int[] eventType, long timeout); 706 707 protected final boolean testSkipped() { 708 if (!useNetworkStackSignature() && !TestNetworkStackServiceClient.isSupported()) { 709 fail("Device running root tests doesn't support TestNetworkStackServiceClient."); 710 } 711 return !useNetworkStackSignature() && mIsSignatureRequiredTest; 712 } 713 714 private static InetAddress ipAddr(String addr) { 715 return InetAddresses.parseNumericAddress(addr); 716 } 717 718 private static Inet4Address ipv4Addr(String addr) { 719 return (Inet4Address) ipAddr(addr); 720 } 721 722 private static Inet6Address ipv6Addr(String addr) { 723 return (Inet6Address) ipAddr(addr); 724 } 725 726 private void setDhcpFeatures(final boolean isRapidCommitEnabled, 727 final boolean isDhcpIpConflictDetectEnabled) { 728 setFeatureEnabled(NetworkStackUtils.DHCP_RAPID_COMMIT_VERSION, isRapidCommitEnabled); 729 setFeatureEnabled(NetworkStackUtils.DHCP_IP_CONFLICT_DETECT_VERSION, 730 isDhcpIpConflictDetectEnabled); 731 } 732 733 private void setDeviceConfigForMaxDtimMultiplier() { 734 setDeviceConfigProperty(IpClient.CONFIG_INITIAL_PROVISIONING_DTIM_DELAY_MS, 735 500 /* default value */); 736 setDeviceConfigProperty(IpClient.CONFIG_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER, 737 IpClient.DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER); 738 setDeviceConfigProperty(IpClient.CONFIG_IPV6_ONLY_NETWORK_MAX_DTIM_MULTIPLIER, 739 IpClient.DEFAULT_IPV6_ONLY_NETWORK_MAX_DTIM_MULTIPLIER); 740 setDeviceConfigProperty(IpClient.CONFIG_IPV4_ONLY_NETWORK_MAX_DTIM_MULTIPLIER, 741 IpClient.DEFAULT_IPV4_ONLY_NETWORK_MAX_DTIM_MULTIPLIER); 742 setDeviceConfigProperty(IpClient.CONFIG_DUAL_STACK_MAX_DTIM_MULTIPLIER, 743 IpClient.DEFAULT_DUAL_STACK_MAX_DTIM_MULTIPLIER); 744 setDeviceConfigProperty(IpClient.CONFIG_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER, 745 IpClient.DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER); 746 } 747 748 @Before 749 public void setUp() throws Exception { 750 final String testMethodName = mTestNameRule.getMethodName(); 751 final Method testMethod = IpClientIntegrationTestCommon.class.getMethod(testMethodName); 752 mIsSignatureRequiredTest = testMethod.getAnnotation(SignatureRequiredTest.class) != null; 753 assumeFalse(testSkipped()); 754 755 // Enable DHCPv6 Prefix Delegation. 756 setFeatureEnabled(NetworkStackUtils.IPCLIENT_DHCPV6_PREFIX_DELEGATION_VERSION, 757 true /* isDhcp6PrefixDelegationEnabled */); 758 759 // Set flags based on test method annotations. 760 final Flag[] flags = testMethod.getAnnotationsByType(Flag.class); 761 for (Flag flag : flags) { 762 setFeatureEnabled(flag.name(), flag.enabled()); 763 } 764 765 setUpTapInterface(); 766 // It turns out that Router Solicitation will also be sent out even after the tap interface 767 // is brought up, however, we want to wait for RS which is sent due to IPv6 stack is enabled 768 // in the test code. The early RS might bring kind of race, for example, the IPv6 stack has 769 // not been enabled when test code sees the RS, then kernel will not process RA even if we 770 // replies immediately after receiving RS. Always waiting for the first RS show up after 771 // interface is brought up helps prevent the race. 772 waitForRouterSolicitation(); 773 774 mCb = mock(IIpClientCallbacks.class); 775 if (useNetworkStackSignature()) { 776 setUpMocks(); 777 setUpIpClient(); 778 // Enable packet retransmit alarm in DhcpClient. 779 enableRealAlarm("DhcpClient." + mIfaceName + ".KICK"); 780 enableRealAlarm("DhcpClient." + mIfaceName + ".RENEW"); 781 // Enable alarm for IPv6 autoconf via SLAAC in IpClient. 782 enableRealAlarm("IpClient." + mIfaceName + ".EVENT_IPV6_AUTOCONF_TIMEOUT"); 783 // Enable packet retransmit alarm in Dhcp6Client. 784 enableRealAlarm("Dhcp6Client." + mIfaceName + ".KICK"); 785 } 786 787 mIIpClient = makeIIpClient(mIfaceName, mCb); 788 789 // Enable multicast filtering after creating IpClient instance, make the integration test 790 // more realistic. 791 mIIpClient.setMulticastFilter(true); 792 setDeviceConfigForMaxDtimMultiplier(); 793 // Set IPv6 autoconf timeout. For signature tests, it has disabled the provisioning delay, 794 // use a small timeout value to speed up the test execution; For root tests, we have to 795 // wait a bit longer to make sure that we do see the success IPv6 provisioning, otherwise, 796 // the global IPv6 address may show up later due to DAD, so we consider that autoconf fails 797 // in this case and start DHCPv6 Prefix Delegation then. 798 final int timeout = useNetworkStackSignature() ? 500 : (int) TEST_TIMEOUT_MS; 799 setDeviceConfigProperty(IpClient.CONFIG_IPV6_AUTOCONF_TIMEOUT, timeout /* default value */); 800 // Set DHCP minimum lease. 801 setDeviceConfigProperty(DhcpPacket.CONFIG_MINIMUM_LEASE, DhcpPacket.DEFAULT_MINIMUM_LEASE); 802 } 803 804 protected void setUpMocks() throws Exception { 805 MockitoAnnotations.initMocks(this); 806 807 mDependencies = new Dependencies(); 808 when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarm); 809 when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mCm); 810 when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) 811 .thenReturn(mDevicePolicyManager); 812 when(mContext.getPackageManager()).thenReturn(mPackageManager); 813 when(mContext.getResources()).thenReturn(mResources); 814 when(mResources.getInteger(eq(R.integer.config_nud_postroaming_solicit_num))).thenReturn(5); 815 when(mResources.getInteger(eq(R.integer.config_nud_postroaming_solicit_interval))) 816 .thenReturn(750); 817 when(mResources.getInteger(eq(R.integer.config_nud_steadystate_solicit_num))) 818 .thenReturn(10); 819 when(mResources.getInteger(eq(R.integer.config_nud_steadystate_solicit_interval))) 820 .thenReturn(750); 821 when(mContext.getContentResolver()).thenReturn(mContentResolver); 822 when(mNetworkStackServiceManager.getIpMemoryStoreService()) 823 .thenReturn(mIpMemoryStoreService); 824 when(mCb.getInterfaceVersion()).thenReturn(IpClient.VERSION_ADDED_REACHABILITY_FAILURE); 825 // This mock is required, otherwise, ignoreIPv6ProvisioningLoss variable is always true, 826 // and IpReachabilityMonitor#avoidingBadLinks() will always return false as well, that 827 // results in the target tested IPv6 off-link DNS server won't be removed from LP and 828 // notifyLost won't be invoked, or the wrong code path when receiving RA with 0 router 829 // liftime. 830 when(mCm.shouldAvoidBadWifi()).thenReturn(true); 831 832 when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn( 833 new ComponentName(TEST_DEVICE_OWNER_APP_PACKAGE, "com.example.SomeClass")); 834 when(mPackageManager.getPackagesForUid(TEST_DEVICE_OWNER_APP_UID)).thenReturn( 835 new String[] { TEST_DEVICE_OWNER_APP_PACKAGE }); 836 837 // Retrieve the network event count. 838 doAnswer(invocation -> { 839 final String cluster = invocation.getArgument(0); 840 final long[] sinceTimes = invocation.getArgument(1); 841 final int[] eventType = invocation.getArgument(2); 842 ((OnNetworkEventCountRetrievedListener) invocation.getArgument(3)) 843 .onNetworkEventCountRetrieved( 844 new Status(SUCCESS), 845 getStoredNetworkEventCount(cluster, sinceTimes, eventType, 846 0 /* timeout not used */)); 847 return null; 848 }).when(mIpMemoryStore).retrieveNetworkEventCount(eq(TEST_CLUSTER), any(), any(), any()); 849 850 setDeviceConfigProperty(DhcpClient.DHCP_RESTART_CONFIG_DELAY, 10); 851 setDeviceConfigProperty(DhcpClient.ARP_FIRST_PROBE_DELAY_MS, 10); 852 setDeviceConfigProperty(DhcpClient.ARP_PROBE_MIN_MS, 10); 853 setDeviceConfigProperty(DhcpClient.ARP_PROBE_MAX_MS, 20); 854 setDeviceConfigProperty(DhcpClient.ARP_FIRST_ANNOUNCE_DELAY_MS, 10); 855 setDeviceConfigProperty(DhcpClient.ARP_ANNOUNCE_INTERVAL_MS, 10); 856 857 // Set the initial netlink socket receive buffer size to a minimum of 100KB to ensure test 858 // cases are still working, meanwhile in order to easily overflow the receive buffer by 859 // sending as few RAs as possible for test case where it's used to verify ENOBUFS. 860 setDeviceConfigProperty(CONFIG_SOCKET_RECV_BUFSIZE, 100 * 1024); 861 862 // Set the timeout to wait IPv6 autoconf to complete. 863 setDeviceConfigProperty(CONFIG_IPV6_AUTOCONF_TIMEOUT, 500); 864 865 // Set the minimal RA lifetime value, any RA section with liftime below this value will be 866 // ignored. 867 setDeviceConfigProperty(CONFIG_ACCEPT_RA_MIN_LFT, 67); 868 869 // Set the polling interval to update APF data snapshot. 870 setDeviceConfigProperty(CONFIG_APF_COUNTER_POLLING_INTERVAL_SECS, 871 DEFAULT_APF_COUNTER_POLLING_INTERVAL_SECS); 872 873 // Set the NUD failure event count daily and weekly thresholds. 874 setDeviceConfigProperty(CONFIG_NUD_FAILURE_COUNT_DAILY_THRESHOLD, 875 DEFAULT_NUD_FAILURE_COUNT_DAILY_THRESHOLD); 876 setDeviceConfigProperty(CONFIG_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD, 877 DEFAULT_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD); 878 } 879 880 private void awaitIpClientShutdown() throws Exception { 881 verify(mCb, timeout(TEST_TIMEOUT_MS)).onQuit(); 882 } 883 884 @After 885 public void tearDown() throws Exception { 886 if (testSkipped()) return; 887 if (mNetworkAgent != null) { 888 mNetworkAgent.unregister(); 889 } 890 if (mNetworkAgentThread != null) { 891 mNetworkAgentThread.quitSafely(); 892 mNetworkAgentThread.join(); 893 } 894 teardownTapInterface(); 895 mIIpClient.shutdown(); 896 awaitIpClientShutdown(); 897 } 898 899 private void setUpTapInterface() throws Exception { 900 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 901 final TestNetworkInterface iface = runAsShell(MANAGE_TEST_NETWORKS, () -> { 902 final TestNetworkManager tnm = 903 inst.getContext().getSystemService(TestNetworkManager.class); 904 try { 905 return tnm.createTapInterface(true /* carrierUp */, true /* bringUp */, 906 true /* disableIpv6ProvisioningDelay */); 907 } catch (NoSuchMethodError e) { 908 // createTapInterface(boolean, boolean, boolean) has been introduced since T, 909 // use the legancy API if the method is not found on previous platforms. 910 return tnm.createTapInterface(); 911 } 912 }); 913 mIfaceName = iface.getInterfaceName(); 914 mClientMac = getIfaceMacAddr(mIfaceName).toByteArray(); 915 mPacketReaderThread = new HandlerThread( 916 IpClientIntegrationTestCommon.class.getSimpleName()); 917 mPacketReaderThread.start(); 918 mHandler = mPacketReaderThread.getThreadHandler(); 919 920 // Detach the FileDescriptor from the ParcelFileDescriptor. 921 // Otherwise, the garbage collector might call the ParcelFileDescriptor's finalizer, which 922 // closes the FileDescriptor and destroys our tap interface. An alternative would be to 923 // make the ParcelFileDescriptor or the TestNetworkInterface a class member so they never 924 // go out of scope. 925 mTapFd = new FileDescriptor(); 926 mTapFd.setInt$(iface.getFileDescriptor().detachFd()); 927 mPacketReader = new PollPacketReader(mHandler, mTapFd, DATA_BUFFER_LEN); 928 mHandler.post(() -> mPacketReader.start()); 929 } 930 931 private TestNetworkInterface setUpClatInterface(@NonNull String baseIface) throws Exception { 932 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 933 final TestNetworkInterface iface = runAsShell(MANAGE_TEST_NETWORKS, () -> { 934 final TestNetworkManager tnm = 935 inst.getContext().getSystemService(TestNetworkManager.class); 936 return tnm.createTapInterface(false /* bringUp */, CLAT_PREFIX + baseIface); 937 }); 938 return iface; 939 } 940 941 private void teardownTapInterface() throws Exception { 942 if (mPacketReader != null) { 943 mHandler.post(() -> mPacketReader.stop()); // Also closes the socket 944 mTapFd = null; 945 } 946 if (mPacketReaderThread != null) { 947 mPacketReaderThread.quitSafely(); 948 mPacketReaderThread.join(); 949 } 950 } 951 952 private MacAddress getIfaceMacAddr(String ifaceName) throws IOException { 953 // InterfaceParams.getByName requires CAP_NET_ADMIN: read the mac address with the shell 954 final String strMacAddr = getOneLineCommandOutput( 955 "su root cat /sys/class/net/" + ifaceName + "/address"); 956 return MacAddress.fromString(strMacAddr); 957 } 958 959 private String getOneLineCommandOutput(String cmd) throws IOException { 960 try (ParcelFileDescriptor fd = InstrumentationRegistry.getInstrumentation() 961 .getUiAutomation().executeShellCommand(cmd); 962 BufferedReader reader = new BufferedReader(new FileReader(fd.getFileDescriptor()))) { 963 return reader.readLine(); 964 } 965 } 966 967 private void enableRealAlarm(String cmdName) { 968 doAnswer((inv) -> { 969 final Context context = InstrumentationRegistry.getTargetContext(); 970 final AlarmManager alarmManager = context.getSystemService(AlarmManager.class); 971 alarmManager.setExact(inv.getArgument(0), inv.getArgument(1), inv.getArgument(2), 972 inv.getArgument(3), inv.getArgument(4)); 973 return null; 974 }).when(mAlarm).setExact(anyInt(), anyLong(), eq(cmdName), any(OnAlarmListener.class), 975 any(Handler.class)); 976 } 977 978 private IpClient makeIpClient() throws Exception { 979 IpClient ipc = 980 new IpClient(mContext, mIfaceName, mCb, mNetworkStackServiceManager, mDependencies); 981 // Wait for IpClient to enter its initial state. Otherwise, additional setup steps or tests 982 // that mock IpClient's dependencies might interact with those mocks while IpClient is 983 // starting. This would cause UnfinishedStubbingExceptions as mocks cannot be interacted 984 // with while they are being stubbed. 985 HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS); 986 return ipc; 987 } 988 989 private void setUpIpClient() throws Exception { 990 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 991 final IBinder netdIBinder = 992 (IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE); 993 mNetd = spy(INetd.Stub.asInterface(netdIBinder)); 994 when(mContext.getSystemService(eq(Context.NETD_SERVICE))).thenReturn(netdIBinder); 995 assertNotNull(mNetd); 996 997 mIpc = makeIpClient(); 998 999 // Tell the IpMemoryStore immediately to answer any question about network attributes with a 1000 // null response. Otherwise, the DHCP client will wait for two seconds before starting, 1001 // while its query to the IpMemoryStore times out. 1002 // This does not affect any test that makes the mock memory store return results, because 1003 // unlike when(), it is documented that doAnswer() can be called more than once, to change 1004 // the behaviour of a mock in the middle of a test. 1005 doAnswer(invocation -> { 1006 final String l2Key = invocation.getArgument(0); 1007 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1)) 1008 .onNetworkAttributesRetrieved(new Status(SUCCESS), l2Key, null); 1009 return null; 1010 }).when(mIpMemoryStore).retrieveNetworkAttributes(any(), any()); 1011 1012 disableIpv6ProvisioningDelays(); 1013 } 1014 1015 private <T> T verifyWithTimeout(InOrder inOrder, T t) { 1016 if (inOrder != null) { 1017 return inOrder.verify(t, timeout(TEST_TIMEOUT_MS)); 1018 } else { 1019 return verify(t, timeout(TEST_TIMEOUT_MS)); 1020 } 1021 } 1022 1023 private void expectAlarmCancelled(InOrder inOrder, OnAlarmListener listener) { 1024 inOrder.verify(mAlarm, timeout(TEST_TIMEOUT_MS)).cancel(eq(listener)); 1025 } 1026 1027 private OnAlarmListener expectAlarmSet(InOrder inOrder, String tagMatch, long afterSeconds, 1028 Handler handler) { 1029 // Allow +/- 3 seconds to prevent flaky tests. 1030 final long when = SystemClock.elapsedRealtime() + afterSeconds * 1000; 1031 final long min = when - 3 * 1000; 1032 final long max = when + 3 * 1000; 1033 ArgumentCaptor<OnAlarmListener> captor = ArgumentCaptor.forClass(OnAlarmListener.class); 1034 verifyWithTimeout(inOrder, mAlarm).setExact( 1035 anyInt(), longThat(x -> x >= min && x <= max), 1036 contains(tagMatch), captor.capture(), eq(handler)); 1037 return captor.getValue(); 1038 } 1039 1040 private OnAlarmListener expectAlarmSet(InOrder inOrder, String tagMatch, int afterSeconds) { 1041 return expectAlarmSet(inOrder, tagMatch, (long) afterSeconds, mIpc.getHandler()); 1042 } 1043 1044 private boolean packetContainsExpectedField(final byte[] packet, final int offset, 1045 final byte[] expected) { 1046 if (packet.length < offset + expected.length) return false; 1047 for (int i = 0; i < expected.length; ++i) { 1048 if (packet[offset + i] != expected[i]) return false; 1049 } 1050 return true; 1051 } 1052 1053 private boolean isDhcpPacket(final byte[] packet) { 1054 final ByteBuffer buffer = ByteBuffer.wrap(packet); 1055 1056 // check the packet length 1057 if (packet.length < DHCP_HEADER_OFFSET) return false; 1058 1059 // check the source port and dest port in UDP header 1060 buffer.position(UDP_SRC_PORT_OFFSET); 1061 final short udpSrcPort = buffer.getShort(); 1062 final short udpDstPort = buffer.getShort(); 1063 if (udpSrcPort != DHCP_CLIENT || udpDstPort != DHCP_SERVER) return false; 1064 1065 // check DHCP message type 1066 buffer.position(DHCP_MESSAGE_OP_CODE_OFFSET); 1067 final byte dhcpOpCode = buffer.get(); 1068 if (dhcpOpCode != DHCP_BOOTREQUEST) return false; 1069 1070 // check DHCP magic cookie 1071 buffer.position(DHCP_OPTION_MAGIC_COOKIE_OFFSET); 1072 final int dhcpMagicCookie = buffer.getInt(); 1073 if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) return false; 1074 1075 return true; 1076 } 1077 1078 private boolean isDhcp6Packet(final byte[] packet) { 1079 final ByteBuffer buffer = ByteBuffer.wrap(packet); 1080 1081 // check the packet length 1082 if (packet.length < DHCP6_HEADER_OFFSET) return false; 1083 1084 // check Ethernet header 1085 final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buffer); 1086 if (ethHdr.etherType != ETH_P_IPV6) { 1087 return false; 1088 } 1089 1090 // check IPv6 header 1091 final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buffer); 1092 final int version = (ipv6Hdr.vtf >> 28) & 0x0F; 1093 if (version != 6) { 1094 return false; 1095 } 1096 if (ipv6Hdr.nextHeader != IPPROTO_UDP) { 1097 return false; 1098 } 1099 if (!ipv6Hdr.dstIp.equals(ALL_DHCP_RELAY_AGENTS_AND_SERVERS)) { 1100 return false; 1101 } 1102 mClientIpAddress = ipv6Hdr.srcIp; 1103 1104 // check the source port and dest port in UDP header 1105 final short udpSrcPort = buffer.getShort(); 1106 final short udpDstPort = buffer.getShort(); 1107 return (udpSrcPort == DHCP6_CLIENT_PORT && udpDstPort == DHCP6_SERVER_PORT); 1108 } 1109 1110 private ArpPacket parseArpPacketOrNull(final byte[] packet) { 1111 try { 1112 return ArpPacket.parseArpPacket(packet, packet.length); 1113 } catch (ArpPacket.ParseException e) { 1114 return null; 1115 } 1116 } 1117 1118 private NeighborAdvertisement parseNeighborAdvertisementOrNull(final byte[] packet) { 1119 try { 1120 return NeighborAdvertisement.parse(packet, packet.length); 1121 } catch (NeighborAdvertisement.ParseException e) { 1122 return null; 1123 } 1124 } 1125 1126 private NeighborSolicitation parseNeighborSolicitationOrNull(final byte[] packet) { 1127 try { 1128 return NeighborSolicitation.parse(packet, packet.length); 1129 } catch (NeighborSolicitation.ParseException e) { 1130 return null; 1131 } 1132 } 1133 1134 private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet, 1135 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu, 1136 final String captivePortalUrl, final Integer ipv6OnlyWaitTime, 1137 final String domainName, final List<String> domainSearchList) { 1138 return DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), 1139 false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */, 1140 clientAddress /* yourIp */, packet.getClientMac(), leaseTimeSec, 1141 NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */, 1142 Collections.singletonList(SERVER_ADDR) /* gateways */, 1143 Collections.singletonList(SERVER_ADDR) /* dnsServers */, 1144 SERVER_ADDR /* dhcpServerIdentifier */, domainName, HOSTNAME, 1145 false /* metered */, mtu, captivePortalUrl, ipv6OnlyWaitTime, domainSearchList); 1146 } 1147 1148 private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet, 1149 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu, 1150 final String captivePortalUrl) { 1151 return buildDhcpOfferPacket(packet, clientAddress, leaseTimeSec, mtu, captivePortalUrl, 1152 null /* ipv6OnlyWaitTime */, null /* domainName */, null /* domainSearchList */); 1153 } 1154 1155 private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet, 1156 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu, 1157 final boolean rapidCommit, final String captivePortalApiUrl, 1158 final Integer ipv6OnlyWaitTime, final String domainName, 1159 final List<String> domainSearchList) { 1160 return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), 1161 false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */, 1162 clientAddress /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(), 1163 leaseTimeSec, NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */, 1164 Collections.singletonList(SERVER_ADDR) /* gateways */, 1165 Collections.singletonList(SERVER_ADDR) /* dnsServers */, 1166 SERVER_ADDR /* dhcpServerIdentifier */, domainName, HOSTNAME, 1167 false /* metered */, mtu, rapidCommit, captivePortalApiUrl, ipv6OnlyWaitTime, 1168 domainSearchList); 1169 } 1170 1171 private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet, 1172 final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu, 1173 final boolean rapidCommit, final String captivePortalApiUrl) { 1174 return buildDhcpAckPacket(packet, clientAddress, leaseTimeSec, mtu, rapidCommit, 1175 captivePortalApiUrl, null /* ipv6OnlyWaitTime */, null /* domainName */, 1176 null /* domainSearchList */); 1177 } 1178 1179 private static ByteBuffer buildDhcpNakPacket(final DhcpPacket packet, final String message) { 1180 return DhcpPacket.buildNakPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), 1181 SERVER_ADDR /* serverIp */, INADDR_ANY /* relayIp */, packet.getClientMac(), 1182 false /* broadcast */, message); 1183 } 1184 1185 private static ByteBuffer buildDhcp6Packet(final ByteBuffer payload, final MacAddress clientMac, 1186 final Inet6Address clientIp) throws Exception { 1187 final ByteBuffer buffer = PacketBuilder.allocate(true /* hasEther */, IPPROTO_IPV6, 1188 IPPROTO_UDP, payload.limit()); 1189 final PacketBuilder pb = new PacketBuilder(buffer); 1190 1191 pb.writeL2Header(ROUTER_MAC /* srcMac */, clientMac /* dstMac */, (short) ETH_P_IPV6); 1192 pb.writeIpv6Header(0x60000000 /* version=6, traffic class=0, flow label=0 */, 1193 (byte) IPPROTO_UDP, (short) 64 /* hop limit */, ROUTER_LINK_LOCAL /* srcIp */, 1194 clientIp /* dstIp */); 1195 pb.writeUdpHeader((short) DHCP6_SERVER_PORT /*src port */, 1196 (short) DHCP6_CLIENT_PORT /* dst port */); 1197 buffer.put(payload); 1198 return pb.finalizePacket(); 1199 } 1200 1201 private static ByteBuffer buildDhcp6Advertise(final Dhcp6Packet solicit, final byte[] iapd, 1202 final byte[] clientMac, final Inet6Address clientIp) throws Exception { 1203 final ByteBuffer advertise = Dhcp6Packet.buildAdvertisePacket(solicit.getTransactionId(), 1204 iapd, solicit.getClientDuid(), ROUTER_DUID); 1205 return buildDhcp6Packet(advertise, MacAddress.fromBytes(clientMac), clientIp); 1206 } 1207 1208 private static ByteBuffer buildDhcp6Reply(final Dhcp6Packet request, final byte[] iapd, 1209 final byte[] clientMac, final Inet6Address clientIp, boolean rapidCommit) 1210 throws Exception { 1211 final ByteBuffer reply = Dhcp6Packet.buildReplyPacket(request.getTransactionId(), 1212 iapd, request.getClientDuid(), ROUTER_DUID, rapidCommit); 1213 return buildDhcp6Packet(reply, MacAddress.fromBytes(clientMac), clientIp); 1214 } 1215 1216 private void sendArpReply(final byte[] dstMac, final byte[] srcMac, final Inet4Address targetIp, 1217 final Inet4Address senderIp) throws IOException { 1218 final ByteBuffer packet = ArpPacket.buildArpPacket(dstMac, srcMac, targetIp.getAddress(), 1219 dstMac /* target HW address */, senderIp.getAddress(), (short) ARP_REPLY); 1220 mPacketReader.sendResponse(packet); 1221 } 1222 1223 private void sendArpProbe() throws IOException { 1224 final ByteBuffer packet = ArpPacket.buildArpPacket(DhcpPacket.ETHER_BROADCAST /* dst */, 1225 ROUTER_MAC_BYTES /* srcMac */, CLIENT_ADDR.getAddress() /* target IP */, 1226 new byte[ETHER_ADDR_LEN] /* target HW address */, 1227 INADDR_ANY.getAddress() /* sender IP */, (short) ARP_REQUEST); 1228 mPacketReader.sendResponse(packet); 1229 } 1230 1231 private void startIpClientProvisioning(final ProvisioningConfiguration cfg) throws Exception { 1232 mIIpClient.startProvisioning(cfg.toStableParcelable()); 1233 } 1234 1235 private void startIpClientProvisioning(final boolean shouldReplyRapidCommitAck, 1236 final boolean isPreconnectionEnabled, 1237 final boolean isDhcpIpConflictDetectEnabled, 1238 final String displayName, 1239 final ScanResultInfo scanResultInfo, 1240 final Layer2Information layer2Info) 1241 throws Exception { 1242 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder() 1243 .withoutIpReachabilityMonitor() 1244 .withLayer2Information(layer2Info == null 1245 ? new Layer2Information(TEST_L2KEY, TEST_CLUSTER, 1246 MacAddress.fromString(TEST_DEFAULT_BSSID)) 1247 : layer2Info) 1248 .withoutIPv6(); 1249 if (isPreconnectionEnabled) prov.withPreconnection(); 1250 if (displayName != null) prov.withDisplayName(displayName); 1251 if (scanResultInfo != null) prov.withScanResultInfo(scanResultInfo); 1252 1253 setDhcpFeatures(shouldReplyRapidCommitAck, isDhcpIpConflictDetectEnabled); 1254 1255 startIpClientProvisioning(prov.build()); 1256 if (!isPreconnectionEnabled) { 1257 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(true); 1258 } 1259 verify(mCb, never()).onProvisioningFailure(any()); 1260 } 1261 1262 private void startIpClientProvisioning(final boolean isDhcpRapidCommitEnabled, 1263 final boolean isPreconnectionEnabled, 1264 final boolean isDhcpIpConflictDetectEnabled) throws Exception { 1265 startIpClientProvisioning(isDhcpRapidCommitEnabled, 1266 isPreconnectionEnabled, isDhcpIpConflictDetectEnabled, 1267 null /* displayName */, null /* ScanResultInfo */, null /* layer2Info */); 1268 } 1269 1270 private void assertIpMemoryStoreNetworkAttributes(final Integer leaseTimeSec, 1271 final long startTime, final int mtu) { 1272 final NetworkAttributes na = getStoredNetworkAttributes(TEST_L2KEY, TEST_TIMEOUT_MS); 1273 assertNotNull(na); 1274 assertEquals(CLIENT_ADDR, na.assignedV4Address); 1275 if (leaseTimeSec == null || leaseTimeSec.intValue() == DhcpPacket.INFINITE_LEASE) { 1276 assertEquals(Long.MAX_VALUE, na.assignedV4AddressExpiry.longValue()); 1277 } else { 1278 // check the lease expiry's scope 1279 final long upperBound = startTime + 7_200_000; // start timestamp + 2h 1280 final long lowerBound = startTime + 3_600_000; // start timestamp + 1h 1281 final long expiry = na.assignedV4AddressExpiry; 1282 assertTrue(upperBound > expiry); 1283 assertTrue(lowerBound < expiry); 1284 } 1285 assertEquals(Collections.singletonList(SERVER_ADDR), na.dnsAddresses); 1286 assertEquals(new Integer(mtu), na.mtu); 1287 } 1288 1289 private void assertIpMemoryNeverStoreNetworkAttributes() { 1290 assertIpMemoryNeverStoreNetworkAttributes(TEST_L2KEY, TEST_TIMEOUT_MS); 1291 } 1292 1293 private void assertHostname(final boolean expectSendHostname, 1294 final String hostname, final String hostnameAfterTransliteration, 1295 final List<DhcpPacket> packetList) throws Exception { 1296 for (DhcpPacket packet : packetList) { 1297 if (!expectSendHostname || hostname == null) { 1298 assertNull(packet.getHostname()); 1299 } else { 1300 assertEquals(hostnameAfterTransliteration, packet.getHostname()); 1301 } 1302 } 1303 } 1304 1305 // Helper method to complete DHCP 2-way or 4-way handshake 1306 private List<DhcpPacket> performDhcpHandshake(final boolean isSuccessLease, 1307 final Integer leaseTimeSec, final boolean shouldReplyRapidCommitAck, final int mtu, 1308 final boolean isDhcpIpConflictDetectEnabled, 1309 final String captivePortalApiUrl, final String displayName, 1310 final ScanResultInfo scanResultInfo, final Layer2Information layer2Info) 1311 throws Exception { 1312 startIpClientProvisioning(shouldReplyRapidCommitAck, 1313 false /* isPreconnectionEnabled */, isDhcpIpConflictDetectEnabled, 1314 displayName, scanResultInfo, layer2Info); 1315 return handleDhcpPackets(isSuccessLease, leaseTimeSec, shouldReplyRapidCommitAck, mtu, 1316 captivePortalApiUrl); 1317 } 1318 1319 private List<DhcpPacket> handleDhcpPackets(final boolean isSuccessLease, 1320 final Integer leaseTimeSec, final boolean shouldReplyRapidCommitAck, final int mtu, 1321 final String captivePortalApiUrl) throws Exception { 1322 return handleDhcpPackets(isSuccessLease, leaseTimeSec, shouldReplyRapidCommitAck, 1323 mtu, captivePortalApiUrl, null /* ipv6OnlyWaitTime */, 1324 null /* domainName */, null /* domainSearchList */); 1325 } 1326 1327 private List<DhcpPacket> handleDhcpPackets(final boolean isSuccessLease, 1328 final Integer leaseTimeSec, final boolean shouldReplyRapidCommitAck, final int mtu, 1329 final String captivePortalApiUrl, final Integer ipv6OnlyWaitTime, 1330 final String domainName, final List<String> domainSearchList) throws Exception { 1331 final List<DhcpPacket> packetList = new ArrayList<>(); 1332 DhcpPacket packet; 1333 while ((packet = getNextDhcpPacket()) != null) { 1334 packetList.add(packet); 1335 if (packet instanceof DhcpDiscoverPacket) { 1336 if (shouldReplyRapidCommitAck) { 1337 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec, 1338 (short) mtu, true /* rapidCommit */, captivePortalApiUrl, 1339 ipv6OnlyWaitTime, domainName, domainSearchList)); 1340 } else { 1341 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR, 1342 leaseTimeSec, (short) mtu, captivePortalApiUrl, ipv6OnlyWaitTime, 1343 domainName, domainSearchList)); 1344 } 1345 } else if (packet instanceof DhcpRequestPacket) { 1346 final ByteBuffer byteBuffer = isSuccessLease 1347 ? buildDhcpAckPacket(packet, CLIENT_ADDR, leaseTimeSec, (short) mtu, 1348 false /* rapidCommit */, captivePortalApiUrl, ipv6OnlyWaitTime, 1349 domainName, domainSearchList) 1350 : buildDhcpNakPacket(packet, "duplicated request IP address"); 1351 mPacketReader.sendResponse(byteBuffer); 1352 } else { 1353 fail("invalid DHCP packet"); 1354 } 1355 1356 // wait for reply to DHCPOFFER packet if disabling rapid commit option 1357 if (shouldReplyRapidCommitAck || !(packet instanceof DhcpDiscoverPacket)) { 1358 return packetList; 1359 } 1360 } 1361 fail("No DHCPREQUEST received on interface"); 1362 return packetList; 1363 } 1364 1365 private List<DhcpPacket> performDhcpHandshake(final boolean isSuccessLease, 1366 final Integer leaseTimeSec, final boolean isDhcpRapidCommitEnabled, final int mtu, 1367 final boolean isDhcpIpConflictDetectEnabled) throws Exception { 1368 return performDhcpHandshake(isSuccessLease, leaseTimeSec, isDhcpRapidCommitEnabled, 1369 mtu, isDhcpIpConflictDetectEnabled, 1370 null /* captivePortalApiUrl */, null /* displayName */, null /* scanResultInfo */, 1371 null /* layer2Info */); 1372 } 1373 1374 private List<DhcpPacket> performDhcpHandshake() throws Exception { 1375 return performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 1376 false /* shouldReplyRapidCommitAck */, 1377 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 1378 } 1379 1380 private DhcpPacket getNextDhcpPacket(final long timeout) throws Exception { 1381 byte[] packet; 1382 while ((packet = mDhcpPacketReadHead.getValue() 1383 .poll(timeout, this::isDhcpPacket)) != null) { 1384 final DhcpPacket dhcpPacket = DhcpPacket.decodeFullPacket(packet, packet.length, 1385 ENCAP_L2); 1386 if (dhcpPacket != null) return dhcpPacket; 1387 } 1388 return null; 1389 } 1390 1391 private DhcpPacket getNextDhcpPacket() throws Exception { 1392 final DhcpPacket packet = getNextDhcpPacket(PACKET_TIMEOUT_MS); 1393 assertNotNull("No expected DHCP packet received on interface within timeout", packet); 1394 return packet; 1395 } 1396 1397 private Dhcp6Packet getNextDhcp6Packet(final long timeout) throws Exception { 1398 byte[] packet; 1399 while ((packet = mDhcp6PacketReadHead.getValue() 1400 .poll(timeout, this::isDhcp6Packet)) != null) { 1401 // Strip the Ethernet/IPv6/UDP headers, only keep DHCPv6 message payload for decode. 1402 final byte[] payload = 1403 Arrays.copyOfRange(packet, DHCP6_HEADER_OFFSET, packet.length); 1404 final Dhcp6Packet dhcp6Packet = Dhcp6Packet.decode(payload, payload.length); 1405 if (dhcp6Packet != null) return dhcp6Packet; 1406 } 1407 return null; 1408 } 1409 1410 private Dhcp6Packet getNextDhcp6Packet() throws Exception { 1411 final Dhcp6Packet packet = getNextDhcp6Packet(PACKET_TIMEOUT_MS); 1412 assertNotNull("No expected DHCPv6 packet received on interface within timeout", packet); 1413 return packet; 1414 } 1415 1416 private DhcpPacket getReplyFromDhcpLease(final NetworkAttributes na, boolean timeout) 1417 throws Exception { 1418 doAnswer(invocation -> { 1419 if (timeout) return null; 1420 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1)) 1421 .onNetworkAttributesRetrieved(new Status(SUCCESS), TEST_L2KEY, na); 1422 return null; 1423 }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any()); 1424 startIpClientProvisioning(false /* shouldReplyRapidCommitAck */, 1425 false /* isPreconnectionEnabled */, 1426 false /* isDhcpIpConflictDetectEnabled */); 1427 return getNextDhcpPacket(); 1428 } 1429 1430 private void removeTestInterface(final FileDescriptor fd) { 1431 try { 1432 Os.close(fd); 1433 } catch (ErrnoException e) { 1434 fail("Fail to close file descriptor: " + e); 1435 } 1436 } 1437 1438 private void verifyAfterIpClientShutdown() throws RemoteException { 1439 final LinkProperties emptyLp = new LinkProperties(); 1440 emptyLp.setInterfaceName(mIfaceName); 1441 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(emptyLp); 1442 } 1443 1444 // Verify IPv4-only provisioning success. No need to verify IPv4 provisioning when below cases 1445 // happen: 1446 // 1. if there's a failure lease, onProvisioningSuccess() won't be called; 1447 // 2. if duplicated IPv4 address detection is enabled, verify TIMEOUT will affect ARP packets 1448 // capture running in other test cases. 1449 // 3. if IPv6 is enabled, e.g. withoutIPv6() isn't called when starting provisioning. 1450 private LinkProperties verifyIPv4OnlyProvisioningSuccess( 1451 final Collection<InetAddress> addresses) throws Exception { 1452 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 1453 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 1454 final LinkProperties lp = captor.getValue(); 1455 assertNotNull(lp); 1456 assertNotEquals(0, lp.getDnsServers().size()); 1457 assertEquals(addresses.size(), lp.getAddresses().size()); 1458 assertTrue(lp.getAddresses().containsAll(addresses)); 1459 assertTrue(hasRouteTo(lp, IPV4_TEST_SUBNET_PREFIX)); // IPv4 directly-connected route 1460 assertTrue(hasRouteTo(lp, IPV4_ANY_ADDRESS_PREFIX)); // IPv4 default route 1461 return lp; 1462 } 1463 1464 private void doRestoreInitialMtuTest(final boolean shouldChangeMtu, 1465 final boolean shouldRemoveTestInterface) throws Exception { 1466 final long currentTime = System.currentTimeMillis(); 1467 int mtu = TEST_DEFAULT_MTU; 1468 1469 if (shouldChangeMtu) mtu = TEST_MIN_MTU; 1470 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 1471 false /* shouldReplyRapidCommitAck */, 1472 mtu, false /* isDhcpIpConflictDetectEnabled */); 1473 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1474 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, mtu); 1475 1476 if (shouldChangeMtu) { 1477 // Pretend that ConnectivityService set the MTU. 1478 mNetd.interfaceSetMtu(mIfaceName, mtu); 1479 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), mtu); 1480 } 1481 1482 // Sometimes, IpClient receives an update with an empty LinkProperties during startup, 1483 // when the link-local address is deleted after interface bringup. Reset expectations 1484 // here to ensure that verifyAfterIpClientShutdown does not fail because it sees two 1485 // empty LinkProperties changes instead of one. 1486 reset(mCb); 1487 1488 if (shouldRemoveTestInterface) removeTestInterface(mTapFd); 1489 try { 1490 mIpc.shutdown(); 1491 awaitIpClientShutdown(); 1492 if (shouldRemoveTestInterface) { 1493 verify(mNetd, never()).interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU); 1494 } else { 1495 // Verify that MTU indeed has been restored or not. 1496 verify(mNetd, times(shouldChangeMtu ? 1 : 0)) 1497 .interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU); 1498 } 1499 verifyAfterIpClientShutdown(); 1500 } catch (Exception e) { 1501 fail("Exception should not have been thrown after shutdown: " + e); 1502 } 1503 } 1504 1505 private DhcpPacket assertDiscoverPacketOnPreconnectionStart() throws Exception { 1506 final ArgumentCaptor<List<Layer2PacketParcelable>> l2PacketList = 1507 ArgumentCaptor.forClass(List.class); 1508 1509 verify(mCb, timeout(TEST_TIMEOUT_MS)).onPreconnectionStart(l2PacketList.capture()); 1510 final byte[] payload = l2PacketList.getValue().get(0).payload; 1511 DhcpPacket packet = DhcpPacket.decodeFullPacket(payload, payload.length, ENCAP_L2); 1512 assertTrue(packet instanceof DhcpDiscoverPacket); 1513 assertArrayEquals(INADDR_BROADCAST.getAddress(), 1514 Arrays.copyOfRange(payload, IPV4_DST_ADDR_OFFSET, IPV4_DST_ADDR_OFFSET + 4)); 1515 return packet; 1516 } 1517 1518 private void doIpClientProvisioningWithPreconnectionTest( 1519 final boolean shouldReplyRapidCommitAck, final boolean shouldAbortPreconnection, 1520 final boolean shouldFirePreconnectionTimeout, 1521 final boolean timeoutBeforePreconnectionComplete) throws Exception { 1522 final long currentTime = System.currentTimeMillis(); 1523 startIpClientProvisioning(shouldReplyRapidCommitAck, 1524 true /* isDhcpPreConnectionEnabled */, 1525 false /* isDhcpIpConflictDetectEnabled */); 1526 DhcpPacket packet = assertDiscoverPacketOnPreconnectionStart(); 1527 final int preconnDiscoverTransId = packet.getTransactionId(); 1528 1529 if (shouldAbortPreconnection) { 1530 if (shouldFirePreconnectionTimeout && timeoutBeforePreconnectionComplete) { 1531 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT); 1532 } 1533 1534 mIpc.notifyPreconnectionComplete(false /* abort */); 1535 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 1536 1537 if (shouldFirePreconnectionTimeout && !timeoutBeforePreconnectionComplete) { 1538 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT); 1539 } 1540 1541 // Either way should get DhcpClient go back to INIT state, and broadcast 1542 // DISCOVER with new transaction ID. 1543 packet = getNextDhcpPacket(); 1544 assertTrue(packet instanceof DhcpDiscoverPacket); 1545 assertTrue(packet.getTransactionId() != preconnDiscoverTransId); 1546 } else if (shouldFirePreconnectionTimeout && timeoutBeforePreconnectionComplete) { 1547 // If timeout fires before success preconnection, DhcpClient will go back to INIT state, 1548 // and broadcast DISCOVER with new transaction ID. 1549 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT); 1550 packet = getNextDhcpPacket(); 1551 assertTrue(packet instanceof DhcpDiscoverPacket); 1552 assertTrue(packet.getTransactionId() != preconnDiscoverTransId); 1553 // any old response would be ignored due to mismatched transaction ID. 1554 } 1555 1556 final short mtu = (short) TEST_DEFAULT_MTU; 1557 if (!shouldReplyRapidCommitAck) { 1558 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR, 1559 TEST_LEASE_DURATION_S, mtu, null /* captivePortalUrl */)); 1560 packet = getNextDhcpPacket(); 1561 assertTrue(packet instanceof DhcpRequestPacket); 1562 } 1563 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, TEST_LEASE_DURATION_S, 1564 mtu, shouldReplyRapidCommitAck, null /* captivePortalUrl */)); 1565 1566 if (!shouldAbortPreconnection) { 1567 mIpc.notifyPreconnectionComplete(true /* success */); 1568 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS); 1569 1570 // If timeout fires after successful preconnection, right now DhcpClient will have 1571 // already entered BOUND state, the delayed CMD_TIMEOUT command would be ignored. So 1572 // this case should be very rare, because the timeout alarm is cancelled when state 1573 // machine exits from Preconnecting state. 1574 if (shouldFirePreconnectionTimeout && !timeoutBeforePreconnectionComplete) { 1575 mDependencies.mDhcpClient.sendMessage(DhcpClient.CMD_TIMEOUT); 1576 } 1577 } 1578 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(true); 1579 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1580 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 1581 } 1582 1583 private ArpPacket getNextArpPacket(final long timeout) throws Exception { 1584 byte[] packet; 1585 while ((packet = mArpPacketReadHead.getValue().poll(timeout, p -> true)) != null) { 1586 final ArpPacket arpPacket = parseArpPacketOrNull(packet); 1587 if (arpPacket != null) return arpPacket; 1588 } 1589 return null; 1590 } 1591 1592 private ArpPacket getNextArpPacket() throws Exception { 1593 final ArpPacket packet = getNextArpPacket(PACKET_TIMEOUT_MS); 1594 assertNotNull("No expected ARP packet received on interface within timeout", packet); 1595 return packet; 1596 } 1597 1598 private void assertArpPacket(final ArpPacket packet) { 1599 assertEquals(packet.opCode, ARP_REQUEST); 1600 assertEquals(packet.targetIp, CLIENT_ADDR); 1601 assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac)); 1602 } 1603 1604 private void assertArpProbe(final ArpPacket packet) { 1605 assertArpPacket(packet); 1606 assertEquals(packet.senderIp, INADDR_ANY); 1607 } 1608 1609 private void assertArpAnnounce(final ArpPacket packet) { 1610 assertArpPacket(packet); 1611 assertEquals(packet.senderIp, CLIENT_ADDR); 1612 } 1613 1614 private void assertArpRequest(final ArpPacket packet, final Inet4Address targetIp) { 1615 assertEquals(packet.opCode, ARP_REQUEST); 1616 assertEquals(packet.senderIp, CLIENT_ADDR); 1617 assertEquals(packet.targetIp, targetIp); 1618 assertTrue(Arrays.equals(packet.targetHwAddress.toByteArray(), 1619 MacAddress.fromString("00:00:00:00:00:00").toByteArray())); 1620 assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac)); 1621 } 1622 1623 private void assertGratuitousARP(final ArpPacket packet) { 1624 assertEquals(packet.opCode, ARP_REPLY); 1625 assertEquals(packet.senderIp, CLIENT_ADDR); 1626 assertEquals(packet.targetIp, CLIENT_ADDR); 1627 assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac)); 1628 assertTrue(Arrays.equals(packet.targetHwAddress.toByteArray(), ETHER_BROADCAST)); 1629 } 1630 1631 private void doIpAddressConflictDetectionTest(final boolean causeIpAddressConflict, 1632 final boolean shouldReplyRapidCommitAck, final boolean isDhcpIpConflictDetectEnabled, 1633 final boolean shouldResponseArpReply) throws Exception { 1634 final long currentTime = System.currentTimeMillis(); 1635 1636 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 1637 shouldReplyRapidCommitAck, 1638 TEST_DEFAULT_MTU, isDhcpIpConflictDetectEnabled); 1639 1640 // If we receive an ARP packet here, it's guaranteed to be from IP conflict detection, 1641 // because at this time the test interface does not have an IP address and therefore 1642 // won't send ARP for anything. 1643 if (causeIpAddressConflict) { 1644 final ArpPacket arpProbe = getNextArpPacket(); 1645 assertArpProbe(arpProbe); 1646 1647 if (shouldResponseArpReply) { 1648 sendArpReply(mClientMac /* dstMac */, ROUTER_MAC_BYTES /* srcMac */, 1649 INADDR_ANY /* target IP */, CLIENT_ADDR /* sender IP */); 1650 } else { 1651 sendArpProbe(); 1652 } 1653 final DhcpPacket packet = getNextDhcpPacket(); 1654 assertTrue(packet instanceof DhcpDeclinePacket); 1655 assertEquals(packet.mServerIdentifier, SERVER_ADDR); 1656 assertEquals(packet.mRequestedIp, CLIENT_ADDR); 1657 1658 verify(mCb, never()).onProvisioningFailure(any()); 1659 assertIpMemoryNeverStoreNetworkAttributes(); 1660 } else if (isDhcpIpConflictDetectEnabled) { 1661 int arpPacketCount = 0; 1662 final List<ArpPacket> packetList = new ArrayList<ArpPacket>(); 1663 // Total sent ARP packets should be 5 (3 ARP Probes + 2 ARP Announcements) 1664 ArpPacket packet; 1665 while ((packet = getNextArpPacket(TEST_TIMEOUT_MS)) != null) { 1666 packetList.add(packet); 1667 } 1668 assertEquals(5, packetList.size()); 1669 assertArpProbe(packetList.get(0)); 1670 assertArpAnnounce(packetList.get(3)); 1671 } else { 1672 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1673 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, 1674 TEST_DEFAULT_MTU); 1675 } 1676 } 1677 1678 @Test @SignatureRequiredTest(reason = "InterfaceParams.getByName requires CAP_NET_ADMIN") 1679 public void testInterfaceParams() throws Exception { 1680 InterfaceParams params = InterfaceParams.getByName(mIfaceName); 1681 assertNotNull(params); 1682 assertEquals(mIfaceName, params.name); 1683 assertTrue(params.index > 0); 1684 assertNotNull(params.macAddr); 1685 assertTrue(params.hasMacAddress); 1686 1687 // Check interface "lo". 1688 params = InterfaceParams.getByName("lo"); 1689 assertNotNull(params); 1690 assertEquals("lo", params.name); 1691 assertTrue(params.index > 0); 1692 assertNotNull(params.macAddr); 1693 assertFalse(params.hasMacAddress); 1694 } 1695 1696 @Test 1697 public void testDhcpInit() throws Exception { 1698 startIpClientProvisioning(false /* shouldReplyRapidCommitAck */, 1699 false /* isPreconnectionEnabled */, 1700 false /* isDhcpIpConflictDetectEnabled */); 1701 final DhcpPacket packet = getNextDhcpPacket(); 1702 assertTrue(packet instanceof DhcpDiscoverPacket); 1703 } 1704 1705 @Test 1706 public void testHandleSuccessDhcpLease() throws Exception { 1707 final long currentTime = System.currentTimeMillis(); 1708 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 1709 false /* shouldReplyRapidCommitAck */, 1710 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 1711 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1712 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 1713 } 1714 1715 @Test 1716 public void testHandleFailureDhcpLease() throws Exception { 1717 performDhcpHandshake(false /* isSuccessLease */, TEST_LEASE_DURATION_S, 1718 false /* shouldReplyRapidCommitAck */, 1719 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 1720 1721 verify(mCb, never()).onProvisioningSuccess(any()); 1722 assertIpMemoryNeverStoreNetworkAttributes(); 1723 } 1724 1725 @Test 1726 public void testHandleInfiniteLease() throws Exception { 1727 final long currentTime = System.currentTimeMillis(); 1728 performDhcpHandshake(true /* isSuccessLease */, INFINITE_LEASE, 1729 false /* shouldReplyRapidCommitAck */, 1730 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 1731 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1732 assertIpMemoryStoreNetworkAttributes(INFINITE_LEASE, currentTime, TEST_DEFAULT_MTU); 1733 } 1734 1735 @Test 1736 public void testHandleNoLease() throws Exception { 1737 final long currentTime = System.currentTimeMillis(); 1738 performDhcpHandshake(true /* isSuccessLease */, null /* no lease time */, 1739 false /* shouldReplyRapidCommitAck */, 1740 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 1741 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1742 assertIpMemoryStoreNetworkAttributes(null, currentTime, TEST_DEFAULT_MTU); 1743 } 1744 1745 @Test 1746 public void testHandleRapidCommitOption() throws Exception { 1747 final long currentTime = System.currentTimeMillis(); 1748 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 1749 true /* shouldReplyRapidCommitAck */, 1750 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 1751 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1752 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 1753 } 1754 1755 @Test 1756 public void testRollbackFromRapidCommitOption() throws Exception { 1757 startIpClientProvisioning(true /* isDhcpRapidCommitEnabled */, 1758 false /* isPreConnectionEnabled */, 1759 false /* isDhcpIpConflictDetectEnabled */); 1760 1761 final List<DhcpPacket> discoverList = new ArrayList<DhcpPacket>(); 1762 DhcpPacket packet; 1763 do { 1764 packet = getNextDhcpPacket(); 1765 assertTrue(packet instanceof DhcpDiscoverPacket); 1766 discoverList.add(packet); 1767 } while (discoverList.size() < 4); 1768 1769 // Check the only first 3 DHCPDISCOVERs take rapid commit option. 1770 assertTrue(discoverList.get(0).mRapidCommit); 1771 assertTrue(discoverList.get(1).mRapidCommit); 1772 assertTrue(discoverList.get(2).mRapidCommit); 1773 assertFalse(discoverList.get(3).mRapidCommit); 1774 } 1775 1776 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1777 public void testDhcpClientStartWithCachedInfiniteLease() throws Exception { 1778 final DhcpPacket packet = getReplyFromDhcpLease( 1779 new NetworkAttributes.Builder() 1780 .setAssignedV4Address(CLIENT_ADDR) 1781 .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid 1782 .setMtu(new Integer(TEST_DEFAULT_MTU)) 1783 .setCluster(TEST_CLUSTER) 1784 .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) 1785 .build(), false /* timeout */); 1786 assertTrue(packet instanceof DhcpRequestPacket); 1787 } 1788 1789 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1790 public void testDhcpClientStartWithCachedExpiredLease() throws Exception { 1791 final DhcpPacket packet = getReplyFromDhcpLease( 1792 new NetworkAttributes.Builder() 1793 .setAssignedV4Address(CLIENT_ADDR) 1794 .setAssignedV4AddressExpiry(EXPIRED_LEASE) 1795 .setMtu(new Integer(TEST_DEFAULT_MTU)) 1796 .setCluster(TEST_CLUSTER) 1797 .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) 1798 .build(), false /* timeout */); 1799 assertTrue(packet instanceof DhcpDiscoverPacket); 1800 } 1801 1802 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1803 public void testDhcpClientStartWithNullRetrieveNetworkAttributes() throws Exception { 1804 final DhcpPacket packet = getReplyFromDhcpLease(null /* na */, false /* timeout */); 1805 assertTrue(packet instanceof DhcpDiscoverPacket); 1806 } 1807 1808 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1809 public void testDhcpClientStartWithTimeoutRetrieveNetworkAttributes() throws Exception { 1810 final DhcpPacket packet = getReplyFromDhcpLease( 1811 new NetworkAttributes.Builder() 1812 .setAssignedV4Address(CLIENT_ADDR) 1813 .setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000) 1814 .setMtu(new Integer(TEST_DEFAULT_MTU)) 1815 .setCluster(TEST_CLUSTER) 1816 .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) 1817 .build(), true /* timeout */); 1818 assertTrue(packet instanceof DhcpDiscoverPacket); 1819 } 1820 1821 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1822 public void testDhcpClientStartWithCachedLeaseWithoutIPAddress() throws Exception { 1823 final DhcpPacket packet = getReplyFromDhcpLease( 1824 new NetworkAttributes.Builder() 1825 .setMtu(new Integer(TEST_DEFAULT_MTU)) 1826 .setCluster(TEST_CLUSTER) 1827 .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) 1828 .build(), false /* timeout */); 1829 assertTrue(packet instanceof DhcpDiscoverPacket); 1830 } 1831 1832 @Test 1833 public void testDhcpClientRapidCommitEnabled() throws Exception { 1834 startIpClientProvisioning(true /* shouldReplyRapidCommitAck */, 1835 false /* isPreconnectionEnabled */, 1836 false /* isDhcpIpConflictDetectEnabled */); 1837 final DhcpPacket packet = getNextDhcpPacket(); 1838 assertTrue(packet instanceof DhcpDiscoverPacket); 1839 } 1840 1841 @Test 1842 public void testDhcpServerInLinkProperties() throws Exception { 1843 performDhcpHandshake(); 1844 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 1845 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 1846 assertEquals(SERVER_ADDR, captor.getValue().getDhcpServerAddress()); 1847 } 1848 1849 private void createTestNetworkAgentAndRegister(final LinkProperties lp) throws Exception { 1850 final Context context = InstrumentationRegistry.getInstrumentation().getContext(); 1851 final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class); 1852 final NetworkSpecifier testNetworkSpecifier = 1853 CompatUtil.makeTestNetworkSpecifier(mIfaceName); 1854 final TestableNetworkCallback cb = new TestableNetworkCallback(); 1855 1856 // Requesting a network make sure the NetworkAgent is alive during the whole life cycle of 1857 // requested network. 1858 cm.requestNetwork(new NetworkRequest.Builder() 1859 .removeCapability(NET_CAPABILITY_TRUSTED) 1860 .removeCapability(NET_CAPABILITY_INTERNET) 1861 .addTransportType(TRANSPORT_TEST) 1862 .setNetworkSpecifier(testNetworkSpecifier) 1863 .build(), cb); 1864 mNetworkAgent = new TestableNetworkAgent(context, mNetworkAgentThread.getLooper(), 1865 new NetworkCapabilities.Builder() 1866 .removeCapability(NET_CAPABILITY_TRUSTED) 1867 .removeCapability(NET_CAPABILITY_INTERNET) 1868 .addCapability(NET_CAPABILITY_NOT_SUSPENDED) 1869 .addCapability(NET_CAPABILITY_NOT_ROAMING) 1870 .addCapability(NET_CAPABILITY_NOT_VPN) 1871 .addCapability(NET_CAPABILITY_NOT_RESTRICTED) 1872 .addTransportType(TRANSPORT_TEST) 1873 .setNetworkSpecifier(testNetworkSpecifier) 1874 .build(), 1875 lp, 1876 new NetworkAgentConfig.Builder().build()); 1877 mNetworkAgent.register(); 1878 mNetworkAgent.markConnected(); 1879 cb.expectAvailableThenValidatedCallbacks(mNetworkAgent.getNetwork(), TEST_TIMEOUT_MS); 1880 } 1881 1882 private void assertReceivedDhcpRequestPacketCount() throws Exception { 1883 final List<DhcpPacket> packetList = new ArrayList<>(); 1884 DhcpPacket packet; 1885 while ((packet = getNextDhcpPacket(PACKET_TIMEOUT_MS)) != null) { 1886 assertDhcpRequestForReacquire(packet); 1887 packetList.add(packet); 1888 } 1889 assertEquals(1, packetList.size()); 1890 } 1891 1892 private LinkProperties prepareDhcpReacquireTest() throws Exception { 1893 mNetworkAgentThread = 1894 new HandlerThread(IpClientIntegrationTestCommon.class.getSimpleName()); 1895 mNetworkAgentThread.start(); 1896 1897 final long currentTime = System.currentTimeMillis(); 1898 setFeatureEnabled(NetworkStackUtils.DHCP_SLOW_RETRANSMISSION_VERSION, true); 1899 performDhcpHandshake(true /* isSuccessLease */, 1900 TEST_LEASE_DURATION_S, false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, 1901 false /* isDhcpIpConflictDetectEnabled */); 1902 final LinkProperties lp = 1903 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 1904 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 1905 return lp; 1906 } 1907 1908 private OnAlarmListener runDhcpRenewTest(final Handler handler, final LinkProperties lp, 1909 final InOrder inOrder) throws Exception { 1910 // Create a NetworkAgent and register it to ConnectivityService with IPv4 LinkProperties, 1911 // then ConnectivityService will call netd API to configure the IPv4 route on the kernel, 1912 // otherwise, unicast DHCPREQUEST cannot be sent out due to no route to host(EHOSTUNREACH). 1913 runAsShell(MANAGE_TEST_NETWORKS, () -> createTestNetworkAgentAndRegister(lp)); 1914 1915 // DHCP client is in BOUND state right now, simulate the renewal via triggering renew alarm 1916 // which should happen at T1. E.g. lease duration is 3600s, T1 = lease_duration * 0.5(1800s) 1917 // T2 = lease_duration * 0.875(3150s). 1918 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 1800, handler); 1919 final OnAlarmListener rebindAlarm = expectAlarmSet(inOrder, "REBIND", 3150, handler); 1920 1921 // Trigger renew alarm and force DHCP client enter RenewingState. Device needs to start 1922 // the ARP resolution for the fake DHCP server IPv4 address before sending the unicast 1923 // DHCPREQUEST out, wait for the unicast ARP request and respond to it with ARP reply, 1924 // otherwise, DHCPREQUEST still cannot be sent out due to that there is no correct ARP 1925 // table for the dest IPv4 address. 1926 handler.post(() -> renewAlarm.onAlarm()); 1927 final ArpPacket request = getNextArpPacket(); 1928 assertArpRequest(request, SERVER_ADDR); 1929 sendArpReply(request.senderHwAddress.toByteArray() /* dst */, ROUTER_MAC_BYTES /* srcMac */, 1930 request.senderIp /* target IP */, SERVER_ADDR /* sender IP */); 1931 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 1932 1933 // Verify there should be only one unicast DHCPREQUESTs to be received per RFC2131. 1934 assertReceivedDhcpRequestPacketCount(); 1935 1936 return rebindAlarm; 1937 } 1938 1939 @Test @SignatureRequiredTest(reason = "Need to mock the DHCP renew/rebind alarms") 1940 public void testDhcpRenew() throws Exception { 1941 final LinkProperties lp = prepareDhcpReacquireTest(); 1942 final InOrder inOrder = inOrder(mAlarm); 1943 runDhcpRenewTest(mDependencies.mDhcpClient.getHandler(), lp, inOrder); 1944 } 1945 1946 @Test @SignatureRequiredTest(reason = "Need to mock the DHCP renew/rebind alarms") 1947 public void testDhcpRebind() throws Exception { 1948 final LinkProperties lp = prepareDhcpReacquireTest(); 1949 final Handler handler = mDependencies.mDhcpClient.getHandler(); 1950 final InOrder inOrder = inOrder(mAlarm); 1951 final OnAlarmListener rebindAlarm = runDhcpRenewTest(handler, lp, inOrder); 1952 1953 // Trigger rebind alarm and forece DHCP client enter RebindingState. DHCP client sends 1954 // broadcast DHCPREQUEST to nearby servers, then check how many DHCPREQUEST packets are 1955 // retransmitted within PACKET_TIMEOUT_MS(5s), there should be only one DHCPREQUEST 1956 // captured per RFC2131. 1957 handler.post(() -> rebindAlarm.onAlarm()); 1958 assertReceivedDhcpRequestPacketCount(); 1959 } 1960 1961 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1962 public void testRestoreInitialInterfaceMtu() throws Exception { 1963 doRestoreInitialMtuTest(true /* shouldChangeMtu */, false /* shouldRemoveTestInterface */); 1964 } 1965 1966 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1967 public void testRestoreInitialInterfaceMtu_WithoutMtuChange() throws Exception { 1968 doRestoreInitialMtuTest(false /* shouldChangeMtu */, false /* shouldRemoveTestInterface */); 1969 } 1970 1971 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1972 public void testRestoreInitialInterfaceMtu_WithException() throws Exception { 1973 doThrow(new RemoteException("NetdNativeService::interfaceSetMtu")).when(mNetd) 1974 .interfaceSetMtu(mIfaceName, TEST_DEFAULT_MTU); 1975 1976 doRestoreInitialMtuTest(true /* shouldChangeMtu */, false /* shouldRemoveTestInterface */); 1977 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_MIN_MTU); 1978 } 1979 1980 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 1981 public void testRestoreInitialInterfaceMtu_NotFoundInterfaceWhenStopping() throws Exception { 1982 doRestoreInitialMtuTest(true /* shouldChangeMtu */, true /* shouldRemoveTestInterface */); 1983 } 1984 1985 @Test 1986 public void testRestoreInitialInterfaceMtu_NotFoundInterfaceWhenStartingProvisioning() 1987 throws Exception { 1988 removeTestInterface(mTapFd); 1989 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 1990 .withoutIpReachabilityMonitor() 1991 .withoutIPv6() 1992 .build(); 1993 1994 startIpClientProvisioning(config); 1995 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any()); 1996 verify(mCb, never()).setNeighborDiscoveryOffload(true); 1997 } 1998 1999 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2000 public void testRestoreInitialInterfaceMtu_stopIpClientAndRestart() throws Exception { 2001 long currentTime = System.currentTimeMillis(); 2002 2003 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 2004 false /* shouldReplyRapidCommitAck */, 2005 TEST_MIN_MTU, false /* isDhcpIpConflictDetectEnabled */); 2006 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2007 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_MIN_MTU); 2008 2009 // Pretend that ConnectivityService set the MTU. 2010 mNetd.interfaceSetMtu(mIfaceName, TEST_MIN_MTU); 2011 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_MIN_MTU); 2012 2013 reset(mCb); 2014 reset(mIpMemoryStore); 2015 2016 // Stop IpClient and then restart provisioning immediately. 2017 mIpc.stop(); 2018 currentTime = System.currentTimeMillis(); 2019 // Intend to set mtu option to 0, then verify that won't influence interface mtu restore. 2020 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 2021 false /* shouldReplyRapidCommitAck */, 2022 0 /* mtu */, false /* isDhcpIpConflictDetectEnabled */); 2023 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2024 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, 0 /* mtu */); 2025 assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), TEST_DEFAULT_MTU); 2026 } 2027 2028 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2029 public void testRestoreInitialInterfaceMtu_removeInterfaceAndAddback() throws Exception { 2030 doAnswer(invocation -> { 2031 final LinkProperties lp = invocation.getArgument(0); 2032 assertEquals(lp.getInterfaceName(), mIfaceName); 2033 assertEquals(0, lp.getLinkAddresses().size()); 2034 assertEquals(0, lp.getDnsServers().size()); 2035 2036 mDependencies.simulateInterfaceRecover(); 2037 return null; 2038 }).when(mCb).onProvisioningFailure(any()); 2039 2040 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 2041 .withoutIpReachabilityMonitor() 2042 .withoutIPv6() 2043 .build(); 2044 2045 // Intend to remove the tap interface and force IpClient throw provisioning failure 2046 // due to that interface is not found. 2047 removeTestInterface(mTapFd); 2048 assertNull(InterfaceParams.getByName(mIfaceName)); 2049 2050 startIpClientProvisioning(config); 2051 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any()); 2052 2053 // Make sure everything queued by this test was processed (e.g. transition to StoppingState 2054 // from ClearingIpAddressState) and tearDown will check if IpClient exits normally or crash. 2055 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 2056 } 2057 2058 private boolean isIcmpv6PacketOfType(final byte[] packetBytes, int type) { 2059 ByteBuffer packet = ByteBuffer.wrap(packetBytes); 2060 return packet.getShort(ETHER_TYPE_OFFSET) == (short) ETH_P_IPV6 2061 && packet.get(ETHER_HEADER_LEN + IPV6_PROTOCOL_OFFSET) == (byte) IPPROTO_ICMPV6 2062 && packet.get(ETHER_HEADER_LEN + IPV6_HEADER_LEN) == (byte) type; 2063 } 2064 2065 private boolean isRouterSolicitation(final byte[] packetBytes) { 2066 return isIcmpv6PacketOfType(packetBytes, ICMPV6_ROUTER_SOLICITATION); 2067 } 2068 2069 private boolean isNeighborAdvertisement(final byte[] packetBytes) { 2070 return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_ADVERTISEMENT); 2071 } 2072 2073 private boolean isNeighborSolicitation(final byte[] packetBytes) { 2074 return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_SOLICITATION); 2075 } 2076 2077 private NeighborAdvertisement getNextNeighborAdvertisement() throws ParseException { 2078 final byte[] packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS, 2079 this::isNeighborAdvertisement); 2080 if (packet == null) return null; 2081 2082 final NeighborAdvertisement na = parseNeighborAdvertisementOrNull(packet); 2083 assertNotNull("Invalid neighbour advertisement received", na); 2084 return na; 2085 } 2086 2087 private NeighborSolicitation getNextNeighborSolicitation() throws ParseException { 2088 final byte[] packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS, 2089 this::isNeighborSolicitation); 2090 if (packet == null) return null; 2091 2092 final NeighborSolicitation ns = parseNeighborSolicitationOrNull(packet); 2093 assertNotNull("Invalid neighbour solicitation received", ns); 2094 return ns; 2095 } 2096 2097 private void waitForRouterSolicitation() throws ParseException { 2098 assertNotNull("No router solicitation received on interface within timeout", 2099 mPacketReader.popPacket(PACKET_TIMEOUT_MS, this::isRouterSolicitation)); 2100 } 2101 2102 private void sendRouterAdvertisement(boolean waitForRs, short lifetime, int valid, 2103 int preferred) throws Exception { 2104 final ByteBuffer pio = buildPioOption(valid, preferred, "2001:db8:1::/64"); 2105 final ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); 2106 sendRouterAdvertisement(waitForRs, lifetime, pio, rdnss); 2107 } 2108 2109 private void sendRouterAdvertisement(boolean waitForRs, short lifetime, 2110 ByteBuffer... options) throws Exception { 2111 final ByteBuffer ra = buildRaPacket(lifetime, options); 2112 if (waitForRs) { 2113 waitForRouterSolicitation(); 2114 } 2115 mPacketReader.sendResponse(ra); 2116 } 2117 2118 private void sendBasicRouterAdvertisement(boolean waitForRs) throws Exception { 2119 sendRouterAdvertisement(waitForRs, (short) 1800 /* lifetime */, 3600 /* valid */, 2120 1800 /* preferred */); 2121 } 2122 2123 private void sendRouterAdvertisementWithZeroRouterLifetime() throws Exception { 2124 sendRouterAdvertisement(false /* waitForRs */, (short) 0 /* lifetime */, 3600 /* valid */, 2125 1800 /* preferred */); 2126 } 2127 2128 // TODO: move this and the following method to a common location and use them in ApfTest. 2129 private static ByteBuffer buildPioOption(int valid, int preferred, String prefixString) 2130 throws Exception { 2131 return PrefixInformationOption.build(new IpPrefix(prefixString), 2132 (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), valid, preferred); 2133 } 2134 2135 private static ByteBuffer buildRdnssOption(int lifetime, String... servers) throws Exception { 2136 return RdnssOption.build(lifetime, servers); 2137 } 2138 2139 private static ByteBuffer buildSllaOption() throws Exception { 2140 return LlaOption.build((byte) ICMPV6_ND_OPTION_SLLA, ROUTER_MAC); 2141 } 2142 2143 private static ByteBuffer buildRaPacket(short lifetime, ByteBuffer... options) 2144 throws Exception { 2145 final MacAddress dstMac = 2146 NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST); 2147 return Ipv6Utils.buildRaPacket(ROUTER_MAC /* srcMac */, dstMac, 2148 ROUTER_LINK_LOCAL /* srcIp */, IPV6_ADDR_ALL_NODES_MULTICAST /* dstIp */, 2149 (byte) 0 /* M=0, O=0 */, lifetime, 0 /* Reachable time, unspecified */, 2150 100 /* Retrans time 100ms */, options); 2151 } 2152 2153 private static ByteBuffer buildRaPacket(ByteBuffer... options) throws Exception { 2154 return buildRaPacket((short) 1800, options); 2155 } 2156 2157 private void disableIpv6ProvisioningDelays() throws Exception { 2158 // Speed up the test by disabling DAD and removing router_solicitation_delay. 2159 // We don't need to restore the default value because the interface is removed in tearDown. 2160 // TODO: speed up further by not waiting for RS but keying off first IPv6 packet. 2161 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "router_solicitation_delay", "0"); 2162 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits", "0"); 2163 } 2164 2165 private void assertHasAddressThat(String msg, LinkProperties lp, 2166 Predicate<LinkAddress> condition) { 2167 for (LinkAddress addr : lp.getLinkAddresses()) { 2168 if (condition.test(addr)) { 2169 return; 2170 } 2171 } 2172 fail(msg + " not found in: " + lp); 2173 } 2174 2175 private boolean hasFlag(LinkAddress addr, int flag) { 2176 return (addr.getFlags() & flag) == flag; 2177 } 2178 2179 private boolean isPrivacyAddress(LinkAddress addr) { 2180 return addr.isGlobalPreferred() && hasFlag(addr, IFA_F_TEMPORARY); 2181 } 2182 2183 private boolean isStablePrivacyAddress(LinkAddress addr) { 2184 return addr.isGlobalPreferred() && hasFlag(addr, IFA_F_STABLE_PRIVACY); 2185 } 2186 2187 private LinkProperties doIpv6OnlyProvisioning() throws Exception { 2188 final InOrder inOrder = inOrder(mCb); 2189 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64"); 2190 final ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); 2191 final ByteBuffer slla = buildSllaOption(); 2192 final ByteBuffer ra = buildRaPacket(pio, rdnss, slla); 2193 2194 return doIpv6OnlyProvisioning(inOrder, ra); 2195 } 2196 2197 private LinkProperties doIpv6OnlyProvisioning(InOrder inOrder, ByteBuffer ra) throws Exception { 2198 waitForRouterSolicitation(); 2199 mPacketReader.sendResponse(ra); 2200 2201 // The lambda below needs to write a LinkProperties to a local variable, but lambdas cannot 2202 // write to non-final local variables. So declare a final variable to write to. 2203 final AtomicReference<LinkProperties> lpRef = new AtomicReference<>(); 2204 2205 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 2206 verifyWithTimeout(inOrder, mCb).onProvisioningSuccess(captor.capture()); 2207 lpRef.set(captor.getValue()); 2208 2209 // Sometimes provisioning completes as soon as the link-local and the stable address appear, 2210 // before the privacy address appears. If so, wait here for the LinkProperties update that 2211 // contains all three address. Otherwise, future calls to verify() might get confused. 2212 if (captor.getValue().getLinkAddresses().size() == 2) { 2213 verifyWithTimeout(inOrder, mCb).onLinkPropertiesChange(argThat(lp -> { 2214 lpRef.set(lp); 2215 return lp.getLinkAddresses().size() == 3; 2216 })); 2217 } 2218 2219 LinkProperties lp = lpRef.get(); 2220 assertEquals("Should have 3 IPv6 addresses after provisioning: " + lp, 2221 3, lp.getLinkAddresses().size()); 2222 assertHasAddressThat("link-local address", lp, x -> x.getAddress().isLinkLocalAddress()); 2223 assertHasAddressThat("privacy address", lp, this::isPrivacyAddress); 2224 assertHasAddressThat("stable privacy address", lp, this::isStablePrivacyAddress); 2225 2226 return lp; 2227 } 2228 2229 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2230 public void testRaRdnss() throws Exception { 2231 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 2232 .withoutIpReachabilityMonitor() 2233 .withoutIPv4() 2234 .build(); 2235 startIpClientProvisioning(config); 2236 2237 InOrder inOrder = inOrder(mCb); 2238 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 2239 2240 final String dnsServer = "2001:4860:4860::64"; 2241 final String lowlifeDnsServer = "2001:4860:4860::6464"; 2242 2243 final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64"); 2244 ByteBuffer rdnss1 = buildRdnssOption(60, lowlifeDnsServer); 2245 ByteBuffer rdnss2 = buildRdnssOption(600, dnsServer); 2246 ByteBuffer ra = buildRaPacket(pio, rdnss1, rdnss2); 2247 2248 LinkProperties lp = doIpv6OnlyProvisioning(inOrder, ra); 2249 2250 // Expect that DNS servers with lifetimes below CONFIG_ACCEPT_RA_MIN_LFT are not accepted. 2251 assertNotNull(lp); 2252 assertEquals(1, lp.getDnsServers().size()); 2253 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer))); 2254 2255 // If the RDNSS lifetime is above the minimum, the DNS server is accepted. 2256 rdnss1 = buildRdnssOption(67, lowlifeDnsServer); 2257 ra = buildRaPacket(pio, rdnss1, rdnss2); 2258 mPacketReader.sendResponse(ra); 2259 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(captor.capture()); 2260 lp = captor.getValue(); 2261 assertNotNull(lp); 2262 assertEquals(2, lp.getDnsServers().size()); 2263 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer))); 2264 assertTrue(lp.getDnsServers().contains(InetAddress.getByName(lowlifeDnsServer))); 2265 2266 // Expect that setting RDNSS lifetime of 0 causes loss of provisioning. 2267 rdnss1 = buildRdnssOption(0, dnsServer); 2268 rdnss2 = buildRdnssOption(0, lowlifeDnsServer); 2269 ra = buildRaPacket(pio, rdnss1, rdnss2); 2270 mPacketReader.sendResponse(ra); 2271 2272 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); 2273 lp = captor.getValue(); 2274 assertNotNull(lp); 2275 assertEquals(0, lp.getDnsServers().size()); 2276 reset(mCb); 2277 } 2278 2279 private void runRaRdnssIpv6LinkLocalDnsTest() throws Exception { 2280 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 2281 .withoutIpReachabilityMonitor() 2282 .withoutIPv4() 2283 .build(); 2284 startIpClientProvisioning(config); 2285 2286 final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64"); 2287 // put an IPv6 link-local DNS server 2288 final ByteBuffer rdnss = buildRdnssOption(600, ROUTER_LINK_LOCAL.getHostAddress()); 2289 // put SLLA option to avoid address resolution for "fe80::1" 2290 final ByteBuffer slla = buildSllaOption(); 2291 final ByteBuffer ra = buildRaPacket(pio, rdnss, slla); 2292 2293 waitForRouterSolicitation(); 2294 mPacketReader.sendResponse(ra); 2295 } 2296 2297 @Test 2298 public void testRaRdnss_Ipv6LinkLocalDns() throws Exception { 2299 runRaRdnssIpv6LinkLocalDnsTest(); 2300 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 2301 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 2302 final LinkProperties lp = captor.getValue(); 2303 assertNotNull(lp); 2304 assertEquals(1, lp.getDnsServers().size()); 2305 assertEquals(ROUTER_LINK_LOCAL, (Inet6Address) lp.getDnsServers().get(0)); 2306 assertTrue(lp.isIpv6Provisioned()); 2307 } 2308 2309 private void expectNat64PrefixUpdate(InOrder inOrder, IpPrefix expected) throws Exception { 2310 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange( 2311 argThat(lp -> Objects.equals(expected, lp.getNat64Prefix()))); 2312 2313 } 2314 2315 private void expectNoNat64PrefixUpdate(InOrder inOrder, IpPrefix unchanged) throws Exception { 2316 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS).times(0)).onLinkPropertiesChange(argThat( 2317 lp -> !Objects.equals(unchanged, lp.getNat64Prefix()))); 2318 2319 } 2320 2321 @Test 2322 @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2323 public void testPref64Option() throws Exception { 2324 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 2325 .withoutIpReachabilityMonitor() 2326 .withoutIPv4() 2327 .build(); 2328 startIpClientProvisioning(config); 2329 2330 final IpPrefix prefix = new IpPrefix("64:ff9b::/96"); 2331 final IpPrefix otherPrefix = new IpPrefix("2001:db8:64::/96"); 2332 2333 final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64"); 2334 ByteBuffer rdnss = buildRdnssOption(600, IPV6_OFF_LINK_DNS_SERVER); 2335 ByteBuffer pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer(); 2336 ByteBuffer ra = buildRaPacket(pio, rdnss, pref64); 2337 2338 // The NAT64 prefix might be detected before or after provisioning success. 2339 // Don't test order between these two events. 2340 LinkProperties lp = doIpv6OnlyProvisioning(null /*inOrder*/, ra); 2341 expectAlarmSet(null /*inOrder*/, "PREF64", 600); 2342 2343 // From now on expect events in order. 2344 InOrder inOrder = inOrder(mCb, mAlarm); 2345 if (lp.getNat64Prefix() != null) { 2346 assertEquals(prefix, lp.getNat64Prefix()); 2347 } else { 2348 expectNat64PrefixUpdate(inOrder, prefix); 2349 } 2350 2351 // Increase the lifetime and expect the prefix not to change. 2352 pref64 = new StructNdOptPref64(prefix, 1800).toByteBuffer(); 2353 ra = buildRaPacket(pio, rdnss, pref64); 2354 mPacketReader.sendResponse(ra); 2355 OnAlarmListener pref64Alarm = expectAlarmSet(inOrder, "PREF64", 1800); 2356 expectNoNat64PrefixUpdate(inOrder, prefix); 2357 reset(mCb, mAlarm); 2358 2359 // Reduce the lifetime and expect to reschedule expiry. 2360 pref64 = new StructNdOptPref64(prefix, 1500).toByteBuffer(); 2361 ra = buildRaPacket(pio, rdnss, pref64); 2362 mPacketReader.sendResponse(ra); 2363 pref64Alarm = expectAlarmSet(inOrder, "PREF64", 1496); 2364 expectNoNat64PrefixUpdate(inOrder, prefix); 2365 reset(mCb, mAlarm); 2366 2367 // Withdraw the prefix and expect it to be set to null. 2368 pref64 = new StructNdOptPref64(prefix, 0).toByteBuffer(); 2369 ra = buildRaPacket(pio, rdnss, pref64); 2370 mPacketReader.sendResponse(ra); 2371 expectAlarmCancelled(inOrder, pref64Alarm); 2372 expectNat64PrefixUpdate(inOrder, null); 2373 reset(mCb, mAlarm); 2374 2375 // Re-announce the prefix. 2376 pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer(); 2377 ra = buildRaPacket(pio, rdnss, pref64); 2378 mPacketReader.sendResponse(ra); 2379 expectAlarmSet(inOrder, "PREF64", 600); 2380 expectNat64PrefixUpdate(inOrder, prefix); 2381 reset(mCb, mAlarm); 2382 2383 // Announce two prefixes. Don't expect any update because if there is already a NAT64 2384 // prefix, any new prefix is ignored. 2385 ByteBuffer otherPref64 = new StructNdOptPref64(otherPrefix, 1200).toByteBuffer(); 2386 ra = buildRaPacket(pio, rdnss, pref64, otherPref64); 2387 mPacketReader.sendResponse(ra); 2388 expectAlarmSet(inOrder, "PREF64", 600); 2389 expectNoNat64PrefixUpdate(inOrder, prefix); 2390 reset(mCb, mAlarm); 2391 2392 // Withdraw the old prefix and continue to announce the new one. Expect a prefix change. 2393 pref64 = new StructNdOptPref64(prefix, 0).toByteBuffer(); 2394 ra = buildRaPacket(pio, rdnss, pref64, otherPref64); 2395 mPacketReader.sendResponse(ra); 2396 expectAlarmCancelled(inOrder, pref64Alarm); 2397 // Need a different OnAlarmListener local variable because posting it to the handler in the 2398 // lambda below requires it to be final. 2399 final OnAlarmListener lastAlarm = expectAlarmSet(inOrder, "PREF64", 1200); 2400 expectNat64PrefixUpdate(inOrder, otherPrefix); 2401 reset(mCb, mAlarm); 2402 2403 // Simulate prefix expiry. 2404 mIpc.getHandler().post(() -> lastAlarm.onAlarm()); 2405 expectAlarmCancelled(inOrder, pref64Alarm); 2406 expectNat64PrefixUpdate(inOrder, null); 2407 2408 // Announce a non-/96 prefix and expect it to be ignored. 2409 IpPrefix invalidPrefix = new IpPrefix("64:ff9b::/64"); 2410 pref64 = new StructNdOptPref64(invalidPrefix, 1200).toByteBuffer(); 2411 ra = buildRaPacket(pio, rdnss, pref64); 2412 mPacketReader.sendResponse(ra); 2413 expectNoNat64PrefixUpdate(inOrder, invalidPrefix); 2414 2415 // Re-announce the prefix. 2416 pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer(); 2417 ra = buildRaPacket(pio, rdnss, pref64); 2418 mPacketReader.sendResponse(ra); 2419 final OnAlarmListener clearAlarm = expectAlarmSet(inOrder, "PREF64", 600); 2420 expectNat64PrefixUpdate(inOrder, prefix); 2421 reset(mCb, mAlarm); 2422 2423 // Check that the alarm is cancelled when IpClient is stopped. 2424 mIpc.stop(); 2425 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 2426 expectAlarmCancelled(inOrder, clearAlarm); 2427 expectNat64PrefixUpdate(inOrder, null); 2428 2429 // Check that even if the alarm was already in the message queue while it was cancelled, it 2430 // is safely ignored. 2431 mIpc.getHandler().post(() -> clearAlarm.onAlarm()); 2432 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 2433 } 2434 2435 private void addIpAddressAndWaitForIt(final String iface) throws Exception { 2436 final String addr1 = "192.0.2.99"; 2437 final String addr2 = "192.0.2.3"; 2438 final int prefixLength = 26; 2439 2440 // IpClient gets IP addresses directly from netlink instead of from netd, just 2441 // add the addresses directly and wait to see if IpClient has seen the address. 2442 mNetd.interfaceAddAddress(iface, addr1, prefixLength); 2443 mNetd.interfaceAddAddress(iface, addr2, prefixLength); 2444 2445 // Wait for IpClient to process the addition of the address. 2446 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 2447 } 2448 2449 private void doIPv4OnlyProvisioningAndExitWithLeftAddress() throws Exception { 2450 final long currentTime = System.currentTimeMillis(); 2451 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 2452 false /* shouldReplyRapidCommitAck */, 2453 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 2454 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2455 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 2456 2457 // Stop IpClient and expect a final LinkProperties callback with an empty LP. 2458 mIIpClient.stop(); 2459 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat( 2460 x -> x.getAddresses().size() == 0 2461 && x.getRoutes().size() == 0 2462 && x.getDnsServers().size() == 0)); 2463 reset(mCb); 2464 2465 // Pretend that something else (e.g., Tethering) used the interface and left an IP address 2466 // configured on it. When IpClient starts, it must clear this address before proceeding. 2467 // The address must be noticed before startProvisioning is called, or IpClient will 2468 // immediately declare provisioning success due to the presence of an IPv4 address. 2469 // The address must be IPv4 because IpClient clears IPv6 addresses on startup. 2470 addIpAddressAndWaitForIt(mIfaceName); 2471 } 2472 2473 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2474 public void testIpClientClearingIpAddressState() throws Exception { 2475 doIPv4OnlyProvisioningAndExitWithLeftAddress(); 2476 2477 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 2478 .withoutIpReachabilityMonitor() 2479 .build(); 2480 startIpClientProvisioning(config); 2481 2482 sendBasicRouterAdvertisement(true /*waitForRs*/); 2483 2484 // Check that the IPv4 addresses configured earlier are not in LinkProperties... 2485 ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 2486 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 2487 assertFalse(captor.getValue().hasIpv4Address()); 2488 2489 // ... or configured on the interface. 2490 InterfaceConfigurationParcel cfg = mNetd.interfaceGetCfg(mIfaceName); 2491 assertEquals("0.0.0.0", cfg.ipv4Addr); 2492 } 2493 2494 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2495 public void testIpClientClearingIpAddressState_enablePreconnection() throws Exception { 2496 doIPv4OnlyProvisioningAndExitWithLeftAddress(); 2497 2498 // Enter ClearingIpAddressesState to clear the remaining IPv4 addresses and transition to 2499 // PreconnectionState instead of RunningState. 2500 startIpClientProvisioning(false /* shouldReplyRapidCommitAck */, 2501 true /* isDhcpPreConnectionEnabled */, 2502 false /* isDhcpIpConflictDetectEnabled */); 2503 assertDiscoverPacketOnPreconnectionStart(); 2504 2505 // Force to enter RunningState. 2506 mIpc.notifyPreconnectionComplete(false /* abort */); 2507 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 2508 } 2509 2510 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2511 public void testDhcpClientPreconnection_success() throws Exception { 2512 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */, 2513 false /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */, 2514 false /* timeoutBeforePreconnectionComplete */); 2515 } 2516 2517 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2518 public void testDhcpClientPreconnection_SuccessWithoutRapidCommit() throws Exception { 2519 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */, 2520 false /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */, 2521 false /* timeoutBeforePreconnectionComplete */); 2522 } 2523 2524 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2525 public void testDhcpClientPreconnection_Abort() throws Exception { 2526 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */, 2527 true /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */, 2528 false /* timeoutBeforePreconnectionComplete */); 2529 } 2530 2531 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2532 public void testDhcpClientPreconnection_AbortWithoutRapiCommit() throws Exception { 2533 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */, 2534 true /* shouldAbortPreconnection */, false /* shouldFirePreconnectionTimeout */, 2535 false /* timeoutBeforePreconnectionComplete */); 2536 } 2537 2538 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2539 public void testDhcpClientPreconnection_TimeoutBeforeAbort() throws Exception { 2540 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */, 2541 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2542 true /* timeoutBeforePreconnectionComplete */); 2543 } 2544 2545 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2546 public void testDhcpClientPreconnection_TimeoutBeforeAbortWithoutRapidCommit() 2547 throws Exception { 2548 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */, 2549 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2550 true /* timeoutBeforePreconnectionComplete */); 2551 } 2552 2553 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2554 public void testDhcpClientPreconnection_TimeoutafterAbort() throws Exception { 2555 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */, 2556 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2557 false /* timeoutBeforePreconnectionComplete */); 2558 } 2559 2560 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2561 public void testDhcpClientPreconnection_TimeoutAfterAbortWithoutRapidCommit() throws Exception { 2562 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */, 2563 true /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2564 false /* timeoutBeforePreconnectionComplete */); 2565 } 2566 2567 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2568 public void testDhcpClientPreconnection_TimeoutBeforeSuccess() throws Exception { 2569 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */, 2570 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2571 true /* timeoutBeforePreconnectionComplete */); 2572 } 2573 2574 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2575 public void testDhcpClientPreconnection_TimeoutBeforeSuccessWithoutRapidCommit() 2576 throws Exception { 2577 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */, 2578 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2579 true /* timeoutBeforePreconnectionComplete */); 2580 } 2581 2582 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2583 public void testDhcpClientPreconnection_TimeoutAfterSuccess() throws Exception { 2584 doIpClientProvisioningWithPreconnectionTest(true /* shouldReplyRapidCommitAck */, 2585 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2586 false /* timeoutBeforePreconnectionComplete */); 2587 } 2588 2589 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2590 public void testDhcpClientPreconnection_TimeoutAfterSuccessWithoutRapidCommit() 2591 throws Exception { 2592 doIpClientProvisioningWithPreconnectionTest(false /* shouldReplyRapidCommitAck */, 2593 false /* shouldAbortPreconnection */, true /* shouldFirePreconnectionTimeout */, 2594 false /* timeoutBeforePreconnectionComplete */); 2595 } 2596 2597 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2598 public void testDhcpClientPreconnection_WithoutLayer2InfoWhenStartingProv() throws Exception { 2599 // For FILS connection, current bssid (also l2key and cluster) is still null when 2600 // starting provisioning since the L2 link hasn't been established yet. Ensure that 2601 // IpClient won't crash even if initializing an Layer2Info class with null members. 2602 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder() 2603 .withoutIpReachabilityMonitor() 2604 .withoutIPv6() 2605 .withPreconnection() 2606 .withLayer2Information(new Layer2Information(null /* l2key */, null /* cluster */, 2607 null /* bssid */)); 2608 2609 startIpClientProvisioning(prov.build()); 2610 assertDiscoverPacketOnPreconnectionStart(); 2611 verify(mCb).setNeighborDiscoveryOffload(true); 2612 2613 // Force IpClient transition to RunningState from PreconnectionState. 2614 mIIpClient.notifyPreconnectionComplete(false /* success */); 2615 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS); 2616 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(true); 2617 } 2618 2619 @Test 2620 @SignatureRequiredTest(reason = "needs mocked alarm and access to IpClient handler thread") 2621 public void testDhcpClientPreconnection_DelayedAbortAndTransitToStoppedState() 2622 throws Exception { 2623 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 2624 .withoutIpReachabilityMonitor() 2625 .withPreconnection() 2626 .build(); 2627 setDhcpFeatures(false /* shouldReplyRapidCommitAck */, 2628 false /* isDhcpIpConflictDetectEnabled */); 2629 startIpClientProvisioning(config); 2630 assertDiscoverPacketOnPreconnectionStart(); 2631 2632 // IpClient is in the PreconnectingState, simulate provisioning timeout event 2633 // and force IpClient state machine transit to StoppingState. 2634 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 2635 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 18, 2636 mIpc.getHandler()); 2637 mIpc.getHandler().post(() -> alarm.onAlarm()); 2638 2639 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); 2640 final LinkProperties lp = captor.getValue(); 2641 assertNotNull(lp); 2642 assertEquals(mIfaceName, lp.getInterfaceName()); 2643 assertEquals(0, lp.getLinkAddresses().size()); 2644 assertEquals(0, lp.getRoutes().size()); 2645 assertEquals(0, lp.getMtu()); 2646 assertEquals(0, lp.getDnsServers().size()); 2647 2648 // Send preconnection abort message, but IpClient should ignore it at this moment and 2649 // transit to StoppedState finally. 2650 mIpc.notifyPreconnectionComplete(false /* abort */); 2651 mIpc.stop(); 2652 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 2653 2654 reset(mCb); 2655 2656 // Start provisioning again to verify IpClient can process CMD_START correctly at 2657 // StoppedState. 2658 startIpClientProvisioning(false /* shouldReplyRapidCommitAck */, 2659 false /* isPreConnectionEnabled */, 2660 false /* isDhcpIpConflictDetectEnabled */); 2661 final DhcpPacket discover = getNextDhcpPacket(); 2662 assertTrue(discover instanceof DhcpDiscoverPacket); 2663 } 2664 2665 @Test 2666 public void testDhcpDecline_conflictByArpReply() throws Exception { 2667 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */, 2668 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */, 2669 true /* shouldResponseArpReply */); 2670 } 2671 2672 @Test 2673 public void testDhcpDecline_conflictByArpProbe() throws Exception { 2674 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */, 2675 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */, 2676 false /* shouldResponseArpReply */); 2677 } 2678 2679 @Test 2680 public void testDhcpDecline_EnableFlagWithoutIpConflict() throws Exception { 2681 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */, 2682 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */, 2683 false /* shouldResponseArpReply */); 2684 } 2685 2686 @Test 2687 public void testDhcpDecline_WithoutIpConflict() throws Exception { 2688 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */, 2689 false /* shouldReplyRapidCommitAck */, false /* isDhcpIpConflictDetectEnabled */, 2690 false /* shouldResponseArpReply */); 2691 } 2692 2693 @Test 2694 public void testDhcpDecline_WithRapidCommitWithoutIpConflict() throws Exception { 2695 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */, 2696 true /* shouldReplyRapidCommitAck */, false /* isDhcpIpConflictDetectEnabled */, 2697 false /* shouldResponseArpReply */); 2698 } 2699 2700 @Test 2701 public void testDhcpDecline_WithRapidCommitConflictByArpReply() throws Exception { 2702 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */, 2703 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */, 2704 true /* shouldResponseArpReply */); 2705 } 2706 2707 @Test 2708 public void testDhcpDecline_WithRapidCommitConflictByArpProbe() throws Exception { 2709 doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */, 2710 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */, 2711 false /* shouldResponseArpReply */); 2712 } 2713 2714 @Test 2715 public void testDhcpDecline_EnableFlagWithRapidCommitWithoutIpConflict() throws Exception { 2716 doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */, 2717 true /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */, 2718 false /* shouldResponseArpReply */); 2719 } 2720 2721 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2722 public void testHostname_enableConfig() throws Exception { 2723 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */, 2724 TEST_HOST_NAME); 2725 2726 final long currentTime = System.currentTimeMillis(); 2727 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */, 2728 TEST_LEASE_DURATION_S, false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, 2729 false /* isDhcpIpConflictDetectEnabled */); 2730 2731 assertEquals(2, sentPackets.size()); 2732 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2733 assertHostname(true, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets); 2734 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 2735 } 2736 2737 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2738 public void testHostname_disableConfig() throws Exception { 2739 mDependencies.setHostnameConfiguration(false /* isHostnameConfigurationEnabled */, 2740 TEST_HOST_NAME); 2741 2742 final long currentTime = System.currentTimeMillis(); 2743 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */, 2744 TEST_LEASE_DURATION_S, false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, 2745 false /* isDhcpIpConflictDetectEnabled */); 2746 2747 assertEquals(2, sentPackets.size()); 2748 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2749 assertHostname(false, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets); 2750 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 2751 } 2752 2753 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 2754 public void testHostname_enableConfigWithNullHostname() throws Exception { 2755 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */, 2756 null /* hostname */); 2757 2758 final long currentTime = System.currentTimeMillis(); 2759 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */, 2760 TEST_LEASE_DURATION_S, false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, 2761 false /* isDhcpIpConflictDetectEnabled */); 2762 2763 assertEquals(2, sentPackets.size()); 2764 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2765 assertHostname(true, null /* hostname */, null /* hostnameAfterTransliteration */, 2766 sentPackets); 2767 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 2768 } 2769 2770 private LinkProperties runDhcpClientCaptivePortalApiTest(boolean featureEnabled, 2771 boolean serverSendsOption) throws Exception { 2772 startIpClientProvisioning(false /* shouldReplyRapidCommitAck */, 2773 false /* isPreConnectionEnabled */, 2774 false /* isDhcpIpConflictDetectEnabled */); 2775 final DhcpPacket discover = getNextDhcpPacket(); 2776 assertTrue(discover instanceof DhcpDiscoverPacket); 2777 assertEquals(featureEnabled, discover.hasRequestedParam(DhcpPacket.DHCP_CAPTIVE_PORTAL)); 2778 2779 // Send Offer and handle Request -> Ack 2780 final String serverSentUrl = serverSendsOption ? TEST_CAPTIVE_PORTAL_URL : null; 2781 mPacketReader.sendResponse(buildDhcpOfferPacket(discover, CLIENT_ADDR, 2782 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, serverSentUrl)); 2783 final int testMtu = 1345; 2784 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 2785 false /* shouldReplyRapidCommitAck */, testMtu, serverSentUrl); 2786 2787 final Uri expectedUrl = featureEnabled && serverSendsOption 2788 ? Uri.parse(TEST_CAPTIVE_PORTAL_URL) : null; 2789 // LinkProperties will be updated multiple times. Wait for it to contain DHCP-obtained info, 2790 // such as MTU. 2791 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 2792 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange( 2793 argThat(lp -> lp.getMtu() == testMtu)); 2794 2795 // Ensure that the URL was set as expected in the callbacks. 2796 verify(mCb, atLeastOnce()).onLinkPropertiesChange(captor.capture()); 2797 final LinkProperties expectedLp = captor.getAllValues().stream().findFirst().get(); 2798 assertNotNull(expectedLp); 2799 assertEquals(expectedUrl, expectedLp.getCaptivePortalApiUrl()); 2800 return expectedLp; 2801 } 2802 2803 @Test 2804 public void testDhcpClientCaptivePortalApiEnabled() throws Exception { 2805 // Only run the test on platforms / builds where the API is enabled 2806 assumeTrue(CaptivePortalDataShimImpl.isSupported()); 2807 runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, true /* serverSendsOption */); 2808 } 2809 2810 @Test 2811 public void testDhcpClientCaptivePortalApiEnabled_NoUrl() throws Exception { 2812 // Only run the test on platforms / builds where the API is enabled 2813 assumeTrue(CaptivePortalDataShimImpl.isSupported()); 2814 runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, false /* serverSendsOption */); 2815 } 2816 2817 @Test 2818 public void testDhcpClientCaptivePortalApiEnabled_ParcelSensitiveFields() throws Exception { 2819 // Only run the test on platforms / builds where the API is enabled 2820 assumeTrue(CaptivePortalDataShimImpl.isSupported()); 2821 LinkProperties lp = runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, 2822 true /* serverSendsOption */); 2823 2824 // Integration test process runs in the same process with network stack module, there 2825 // won't be any IPC call happened on IpClientCallbacks, manually run parcelingRoundTrip 2826 // to parcel and unparcel the LinkProperties to simulate what happens during the binder 2827 // call. In this case lp should contain the senstive data but mParcelSensitiveFields is 2828 // false after round trip. 2829 if (useNetworkStackSignature()) { 2830 lp = parcelingRoundTrip(lp); 2831 } 2832 final Uri expectedUrl = Uri.parse(TEST_CAPTIVE_PORTAL_URL); 2833 assertEquals(expectedUrl, lp.getCaptivePortalApiUrl()); 2834 2835 // Parcel and unparcel the captured LinkProperties, mParcelSensitiveFields is false, 2836 // CaptivePortalApiUrl should be null after parceling round trip. 2837 final LinkProperties unparceled = parcelingRoundTrip(lp); 2838 assertNull(unparceled.getCaptivePortalApiUrl()); 2839 } 2840 2841 @Test 2842 public void testDhcpClientCaptivePortalApiDisabled() throws Exception { 2843 // Only run the test on platforms / builds where the API is disabled 2844 assumeFalse(CaptivePortalDataShimImpl.isSupported()); 2845 runDhcpClientCaptivePortalApiTest(false /* featureEnabled */, true /* serverSendsOption */); 2846 } 2847 2848 private ScanResultInfo makeScanResultInfo(final int id, final String ssid, 2849 final String bssid, final byte[] oui, final byte type, final byte[] data) { 2850 final ByteBuffer payload = ByteBuffer.allocate(4 + data.length); 2851 payload.put(oui); 2852 payload.put(type); 2853 payload.put(data); 2854 payload.flip(); 2855 final ScanResultInfo.InformationElement ie = 2856 new ScanResultInfo.InformationElement(id /* IE id */, payload); 2857 return new ScanResultInfo(ssid, bssid, Collections.singletonList(ie)); 2858 } 2859 2860 private ScanResultInfo makeScanResultInfo(final int id, final byte[] oui, final byte type) { 2861 byte[] data = new byte[10]; 2862 new Random().nextBytes(data); 2863 return makeScanResultInfo(id, TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID, oui, type, data); 2864 } 2865 2866 private ScanResultInfo makeScanResultInfo(final String ssid, final String bssid) { 2867 byte[] data = new byte[10]; 2868 new Random().nextBytes(data); 2869 return makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, ssid, bssid, TEST_AP_OUI, 2870 (byte) 0x06, data); 2871 } 2872 2873 private void doUpstreamHotspotDetectionTest(final int id, final String displayName, 2874 final String ssid, final byte[] oui, final byte type, final byte[] data, 2875 final boolean expectMetered) throws Exception { 2876 final ScanResultInfo info = makeScanResultInfo(id, ssid, TEST_DEFAULT_BSSID, oui, type, 2877 data); 2878 final long currentTime = System.currentTimeMillis(); 2879 final List<DhcpPacket> sentPackets = performDhcpHandshake(true /* isSuccessLease */, 2880 TEST_LEASE_DURATION_S, false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU, 2881 false /* isDhcpIpConflictDetectEnabled */, 2882 null /* captivePortalApiUrl */, displayName, info /* scanResultInfo */, 2883 null /* layer2Info */); 2884 assertEquals(2, sentPackets.size()); 2885 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2886 2887 ArgumentCaptor<DhcpResultsParcelable> captor = 2888 ArgumentCaptor.forClass(DhcpResultsParcelable.class); 2889 verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(captor.capture()); 2890 final DhcpResultsParcelable lease = captor.getValue(); 2891 assertNotNull(lease); 2892 assertEquals(CLIENT_ADDR, lease.baseConfiguration.getIpAddress().getAddress()); 2893 assertEquals(SERVER_ADDR, lease.baseConfiguration.getGateway()); 2894 assertEquals(1, lease.baseConfiguration.getDnsServers().size()); 2895 assertTrue(lease.baseConfiguration.getDnsServers().contains(SERVER_ADDR)); 2896 assertEquals(SERVER_ADDR, InetAddresses.parseNumericAddress(lease.serverAddress)); 2897 assertEquals(TEST_DEFAULT_MTU, lease.mtu); 2898 2899 if (expectMetered) { 2900 assertEquals(lease.vendorInfo, DhcpPacket.VENDOR_INFO_ANDROID_METERED); 2901 } else { 2902 assertNull(lease.vendorInfo); 2903 } 2904 2905 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 2906 } 2907 2908 @Test 2909 public void testUpstreamHotspotDetection() throws Exception { 2910 byte[] data = new byte[10]; 2911 new Random().nextBytes(data); 2912 doUpstreamHotspotDetectionTest(TEST_VENDOR_SPECIFIC_IE_ID, "\"ssid\"", "ssid", 2913 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, 2914 true /* expectMetered */); 2915 } 2916 2917 @Test 2918 public void testUpstreamHotspotDetection_incorrectIeId() throws Exception { 2919 byte[] data = new byte[10]; 2920 new Random().nextBytes(data); 2921 doUpstreamHotspotDetectionTest(0xdc, "\"ssid\"", "ssid", 2922 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, 2923 false /* expectMetered */); 2924 } 2925 2926 @Test 2927 public void testUpstreamHotspotDetection_incorrectOUI() throws Exception { 2928 byte[] data = new byte[10]; 2929 new Random().nextBytes(data); 2930 doUpstreamHotspotDetectionTest(TEST_VENDOR_SPECIFIC_IE_ID, "\"ssid\"", "ssid", 2931 new byte[] { (byte) 0x00, (byte) 0x1A, (byte) 0x11 }, (byte) 0x06, data, 2932 false /* expectMetered */); 2933 } 2934 2935 @Test 2936 public void testUpstreamHotspotDetection_incorrectSsid() throws Exception { 2937 byte[] data = new byte[10]; 2938 new Random().nextBytes(data); 2939 doUpstreamHotspotDetectionTest(TEST_VENDOR_SPECIFIC_IE_ID, "\"another ssid\"", "ssid", 2940 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, 2941 false /* expectMetered */); 2942 } 2943 2944 @Test 2945 public void testUpstreamHotspotDetection_incorrectType() throws Exception { 2946 byte[] data = new byte[10]; 2947 new Random().nextBytes(data); 2948 doUpstreamHotspotDetectionTest(TEST_VENDOR_SPECIFIC_IE_ID, "\"ssid\"", "ssid", 2949 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x0a, data, 2950 false /* expectMetered */); 2951 } 2952 2953 @Test 2954 public void testUpstreamHotspotDetection_zeroLengthData() throws Exception { 2955 byte[] data = new byte[0]; 2956 doUpstreamHotspotDetectionTest(TEST_VENDOR_SPECIFIC_IE_ID, "\"ssid\"", "ssid", 2957 new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xF2 }, (byte) 0x06, data, 2958 true /* expectMetered */); 2959 } 2960 2961 private void forceLayer2Roaming() throws Exception { 2962 final Layer2InformationParcelable roamingInfo = new Layer2InformationParcelable(); 2963 roamingInfo.bssid = MacAddress.fromString(TEST_DHCP_ROAM_BSSID); 2964 roamingInfo.l2Key = TEST_DHCP_ROAM_L2KEY; 2965 roamingInfo.cluster = TEST_DHCP_ROAM_CLUSTER; 2966 mIIpClient.updateLayer2Information(roamingInfo); 2967 } 2968 2969 private void assertDhcpRequestForReacquire(final DhcpPacket packet) { 2970 assertTrue(packet instanceof DhcpRequestPacket); 2971 assertEquals(packet.mClientIp, CLIENT_ADDR); // client IP 2972 assertNull(packet.mRequestedIp); // requested IP option 2973 assertNull(packet.mServerIdentifier); // server ID 2974 } 2975 2976 private void doDhcpRoamingTest(final boolean hasMismatchedIpAddress, final String displayName, 2977 final MacAddress bssid, final boolean expectRoaming, 2978 final boolean shouldReplyNakOnRoam) throws Exception { 2979 long currentTime = System.currentTimeMillis(); 2980 final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER, bssid); 2981 2982 doAnswer(invocation -> { 2983 // we don't rely on the Init-Reboot state to renew previous cached IP lease. 2984 // Just return null and force state machine enter INIT state. 2985 final String l2Key = invocation.getArgument(0); 2986 ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1)) 2987 .onNetworkAttributesRetrieved(new Status(SUCCESS), l2Key, null); 2988 return null; 2989 }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any()); 2990 2991 mDependencies.setHostnameConfiguration(true /* isHostnameConfigurationEnabled */, 2992 null /* hostname */); 2993 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 2994 false /* isDhcpRapidCommitEnabled */, 2995 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */, 2996 null /* captivePortalApiUrl */, displayName, null /* scanResultInfo */, 2997 layer2Info); 2998 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 2999 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 3000 3001 // simulate the roaming by updating bssid. 3002 forceLayer2Roaming(); 3003 3004 currentTime = System.currentTimeMillis(); 3005 reset(mIpMemoryStore); 3006 reset(mCb); 3007 if (!expectRoaming) { 3008 assertIpMemoryNeverStoreNetworkAttributes(); 3009 return; 3010 } 3011 // check DHCPREQUEST broadcast sent to renew IP address. 3012 final DhcpPacket packet = getNextDhcpPacket(); 3013 assertDhcpRequestForReacquire(packet); 3014 3015 final ByteBuffer packetBuffer = shouldReplyNakOnRoam 3016 ? buildDhcpNakPacket(packet, "request IP on a wrong subnet") 3017 : buildDhcpAckPacket(packet, 3018 hasMismatchedIpAddress ? CLIENT_ADDR_NEW : CLIENT_ADDR, 3019 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, 3020 false /* rapidCommit */, null /* captivePortalApiUrl */); 3021 mPacketReader.sendResponse(packetBuffer); 3022 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 3023 3024 if (shouldReplyNakOnRoam) { 3025 ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor = 3026 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class); 3027 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityFailure(lossInfoCaptor.capture()); 3028 assertEquals(ReachabilityLossReason.ROAM, lossInfoCaptor.getValue().reason); 3029 3030 // IPv4 address will be still deleted when DhcpClient state machine exits from 3031 // DhcpHaveLeaseState, a following onProvisioningFailure will be thrown then. 3032 // Also check DhcpClient won't send any DHCPDISCOVER packet. 3033 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any()); 3034 assertNull(getNextDhcpPacket(TEST_TIMEOUT_MS)); 3035 verify(mCb, never()).onNewDhcpResults(any()); 3036 } else if (hasMismatchedIpAddress) { 3037 ArgumentCaptor<DhcpResultsParcelable> resultsCaptor = 3038 ArgumentCaptor.forClass(DhcpResultsParcelable.class); 3039 verify(mCb, timeout(TEST_TIMEOUT_MS)).onNewDhcpResults(resultsCaptor.capture()); 3040 final DhcpResultsParcelable lease = resultsCaptor.getValue(); 3041 assertNull(lease); 3042 3043 // DhcpClient rolls back to StoppedState instead of INIT state after calling 3044 // notifyFailure, DHCPDISCOVER should not be sent out. 3045 assertNull(getNextDhcpPacket(TEST_TIMEOUT_MS)); 3046 } else { 3047 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, 3048 TEST_DEFAULT_MTU); 3049 } 3050 } 3051 3052 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3053 public void testDhcpRoaming() throws Exception { 3054 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, 3055 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */, 3056 false /* shouldReplyNakOnRoam */); 3057 } 3058 3059 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3060 public void testDhcpRoaming_invalidBssid() throws Exception { 3061 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, 3062 MacAddress.fromString(TEST_DHCP_ROAM_BSSID), false /* expectRoaming */, 3063 false/* shouldReplyNakOnRoam */); 3064 } 3065 3066 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3067 public void testDhcpRoaming_nullBssid() throws Exception { 3068 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, 3069 null /* BSSID */, false /* expectRoaming */, false /* shouldReplyNakOnRoam */); 3070 } 3071 3072 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3073 public void testDhcpRoaming_invalidDisplayName() throws Exception { 3074 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"test-ssid\"" /* display name */, 3075 MacAddress.fromString(TEST_DEFAULT_BSSID), false /* expectRoaming */, 3076 false /* shouldReplyNakOnRoam */); 3077 } 3078 3079 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3080 public void testDhcpRoaming_mismatchedLeasedIpAddress() throws Exception { 3081 doDhcpRoamingTest(true /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, 3082 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */, 3083 false /* shouldReplyNakOnRoam */); 3084 } 3085 3086 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3087 public void testDhcpRoaming_failureLeaseOnNak() throws Exception { 3088 doDhcpRoamingTest(false /* hasMismatchedIpAddress */, "\"0001docomo\"" /* display name */, 3089 MacAddress.fromString(TEST_DEFAULT_BSSID), true /* expectRoaming */, 3090 true /* shouldReplyNakOnRoam */); 3091 } 3092 3093 private LinkProperties performDualStackProvisioning() throws Exception { 3094 final Inet6Address dnsServer = ipv6Addr(IPV6_OFF_LINK_DNS_SERVER); 3095 final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64"); 3096 final ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); 3097 final ByteBuffer slla = buildSllaOption(); 3098 final ByteBuffer ra = buildRaPacket(pio, rdnss, slla); 3099 3100 return performDualStackProvisioning(ra, dnsServer); 3101 } 3102 3103 private LinkProperties performDualStackProvisioning(final ByteBuffer ra, 3104 final InetAddress dnsServer) throws Exception { 3105 final InOrder inOrder = inOrder(mCb); 3106 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>(); 3107 3108 // Start IPv4 provisioning first and wait IPv4 provisioning to succeed, and then start 3109 // IPv6 provisioning, which is more realistic and avoid the flaky case of both IPv4 and 3110 // IPv6 provisioning complete at the same time. 3111 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 3112 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */); 3113 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); 3114 3115 waitForRouterSolicitation(); 3116 mPacketReader.sendResponse(ra); 3117 3118 // Wait until we see both success IPv4 and IPv6 provisioning, then there would be 4 3119 // addresses in LinkProperties, they are IPv4 address, IPv6 link-local address, stable 3120 // privacy address and privacy address. 3121 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(argThat(x -> { 3122 if (!x.isIpv4Provisioned() || !x.isIpv6Provisioned()) return false; 3123 if (x.getLinkAddresses().size() != 4) return false; 3124 lpFuture.complete(x); 3125 return true; 3126 })); 3127 3128 final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); 3129 assertNotNull(lp); 3130 assertTrue(lp.getDnsServers().contains(dnsServer)); 3131 assertTrue(lp.getDnsServers().contains(SERVER_ADDR)); 3132 assertHasAddressThat("link-local address", lp, x -> x.getAddress().isLinkLocalAddress()); 3133 assertHasAddressThat("privacy address", lp, this::isPrivacyAddress); 3134 assertHasAddressThat("stable privacy address", lp, this::isStablePrivacyAddress); 3135 3136 return lp; 3137 } 3138 3139 private LinkProperties doDualStackProvisioning() throws Exception { 3140 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 3141 .withoutIpReachabilityMonitor() 3142 .build(); 3143 3144 // Enable rapid commit to accelerate DHCP handshake to shorten test duration, 3145 // not strictly necessary. 3146 setDhcpFeatures(true /* isRapidCommitEnabled */, false /* isDhcpIpConflictDetectEnabled */); 3147 // Both signature and root tests can use this function to do dual-stack provisioning. 3148 if (useNetworkStackSignature()) { 3149 mIpc.startProvisioning(config); 3150 } else { 3151 mIIpClient.startProvisioning(config.toStableParcelable()); 3152 } 3153 3154 return performDualStackProvisioning(); 3155 } 3156 3157 private boolean hasRouteTo(@NonNull final LinkProperties lp, @NonNull final String prefix) { 3158 return hasRouteTo(lp, prefix, RTN_UNICAST); 3159 } 3160 3161 private boolean hasRouteTo(@NonNull final LinkProperties lp, @NonNull final String prefix, 3162 int type) { 3163 for (RouteInfo r : lp.getRoutes()) { 3164 if (r.getDestination().equals(new IpPrefix(prefix))) return r.getType() == type; 3165 } 3166 return false; 3167 } 3168 3169 private boolean hasIpv6AddressPrefixedWith(@NonNull final LinkProperties lp, 3170 @NonNull final IpPrefix prefix) { 3171 for (LinkAddress la : lp.getLinkAddresses()) { 3172 final InetAddress addr = la.getAddress(); 3173 if ((addr instanceof Inet6Address) && !addr.isLinkLocalAddress()) { 3174 if (prefix.contains(addr)) return true; 3175 } 3176 } 3177 return false; 3178 } 3179 3180 @Test 3181 @SignatureRequiredTest(reason = "Out of SLO flakiness") 3182 public void testIgnoreIpv6ProvisioningLoss_disableAcceptRaDefrtr() throws Exception { 3183 LinkProperties lp = doDualStackProvisioning(); 3184 Log.d(TAG, "current LinkProperties: " + lp); 3185 3186 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>(); 3187 3188 // Send RA with 0-lifetime and wait until all global IPv6 addresses, IPv6-related default 3189 // route and DNS servers have been removed, then verify if there is IPv4-only, IPv6 link 3190 // local address and route to fe80::/64 info left in the LinkProperties. 3191 sendRouterAdvertisementWithZeroRouterLifetime(); 3192 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange( 3193 argThat(x -> { 3194 // Only IPv4 provisioned and IPv6 link-local address 3195 final boolean isIPv6LinkLocalAndIPv4OnlyProvisioned = 3196 (x.getLinkAddresses().size() == 2 3197 && x.getDnsServers().size() == 1 3198 && x.getAddresses().get(0) instanceof Inet4Address 3199 && x.getDnsServers().get(0) instanceof Inet4Address); 3200 3201 if (!isIPv6LinkLocalAndIPv4OnlyProvisioned) return false; 3202 lpFuture.complete(x); 3203 return true; 3204 })); 3205 lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); 3206 Log.d(TAG, "After receiving RA with 0 router lifetime, LinkProperties: " + lp); 3207 assertNotNull(lp); 3208 assertEquals(lp.getAddresses().get(0), CLIENT_ADDR); 3209 assertEquals(lp.getDnsServers().get(0), SERVER_ADDR); 3210 assertTrue(hasRouteTo(lp, IPV6_LINK_LOCAL_PREFIX)); // fe80::/64 3211 assertTrue(hasRouteTo(lp, IPV4_TEST_SUBNET_PREFIX)); // IPv4 directly-connected route 3212 assertTrue(hasRouteTo(lp, IPV4_ANY_ADDRESS_PREFIX)); // IPv4 default route 3213 assertTrue(lp.getAddresses().get(1).isLinkLocalAddress()); 3214 3215 clearInvocations(mCb); 3216 3217 // Wait for RS after IPv6 stack has been restarted and reply with a normal RA to verify 3218 // that device gains the IPv6 provisioning without default route and off-link DNS server. 3219 sendBasicRouterAdvertisement(true /* waitForRs */); 3220 verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(argThat( 3221 x -> x.hasGlobalIpv6Address() 3222 // IPv4, IPv6 link local, privacy and stable privacy 3223 && x.getLinkAddresses().size() == 4 3224 && !x.hasIpv6DefaultRoute() 3225 && x.getDnsServers().size() == 1 3226 && x.getDnsServers().get(0).equals(SERVER_ADDR))); 3227 } 3228 3229 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3230 public void testDualStackProvisioning() throws Exception { 3231 doDualStackProvisioning(); 3232 3233 verify(mCb, never()).onProvisioningFailure(any()); 3234 } 3235 3236 private DhcpPacket verifyDhcpPacketRequestsIPv6OnlyPreferredOption( 3237 Class<? extends DhcpPacket> packetType) throws Exception { 3238 final DhcpPacket packet = getNextDhcpPacket(); 3239 assertTrue(packetType.isInstance(packet)); 3240 assertTrue(packet.hasRequestedParam(DHCP_IPV6_ONLY_PREFERRED)); 3241 return packet; 3242 } 3243 3244 private void doIPv6OnlyPreferredOptionTest(final Integer ipv6OnlyWaitTime, 3245 final Inet4Address clientAddress) throws Exception { 3246 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 3247 .withoutIpReachabilityMonitor() 3248 .build(); 3249 setDhcpFeatures(false /* isRapidCommitEnabled */, 3250 false /* isDhcpIpConflictDetectEnabled */); 3251 startIpClientProvisioning(config); 3252 3253 final DhcpPacket packet = 3254 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class); 3255 3256 // Respond DHCPOFFER with IPv6-Only preferred option and offered address. 3257 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, clientAddress, 3258 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, null /* captivePortalUrl */, 3259 ipv6OnlyWaitTime, null /* domainName */, null /* domainSearchList */)); 3260 } 3261 3262 private void doDiscoverIPv6OnlyPreferredOptionTest(final int optionSecs, 3263 final long expectedWaitSecs) throws Exception { 3264 doIPv6OnlyPreferredOptionTest(optionSecs, CLIENT_ADDR); 3265 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 3266 expectedWaitSecs, mDependencies.mDhcpClient.getHandler()); 3267 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm()); 3268 // Implicitly check that the client never sent a DHCPREQUEST to request the offered address. 3269 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class); 3270 } 3271 3272 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3273 public void testDiscoverIPv6OnlyPreferredOption() throws Exception { 3274 doDiscoverIPv6OnlyPreferredOptionTest(TEST_IPV6_ONLY_WAIT_S, TEST_IPV6_ONLY_WAIT_S); 3275 } 3276 3277 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3278 public void testDiscoverIPv6OnlyPreferredOption_LowerIPv6OnlyWait() throws Exception { 3279 doDiscoverIPv6OnlyPreferredOptionTest(TEST_LOWER_IPV6_ONLY_WAIT_S, 3280 TEST_LOWER_IPV6_ONLY_WAIT_S); 3281 } 3282 3283 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3284 public void testDiscoverIPv6OnlyPreferredOption_ZeroIPv6OnlyWait() throws Exception { 3285 doDiscoverIPv6OnlyPreferredOptionTest(TEST_ZERO_IPV6_ONLY_WAIT_S, 3286 TEST_LOWER_IPV6_ONLY_WAIT_S); 3287 } 3288 3289 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3290 public void testDiscoverIPv6OnlyPreferredOption_MaxIPv6OnlyWait() throws Exception { 3291 doDiscoverIPv6OnlyPreferredOptionTest((int) TEST_MAX_IPV6_ONLY_WAIT_S, 0xffffffffL); 3292 } 3293 3294 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3295 public void testDiscoverIPv6OnlyPreferredOption_ZeroIPv6OnlyWaitWithOfferedAnyAddress() 3296 throws Exception { 3297 doIPv6OnlyPreferredOptionTest(TEST_ZERO_IPV6_ONLY_WAIT_S, IPV4_ADDR_ANY); 3298 3299 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 300, 3300 mDependencies.mDhcpClient.getHandler()); 3301 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm()); 3302 3303 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class); 3304 } 3305 3306 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3307 public void testDiscoverIPv6OnlyPreferredOption_enabledPreconnection() throws Exception { 3308 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 3309 .withoutIpReachabilityMonitor() 3310 .withPreconnection() 3311 .build(); 3312 3313 setDhcpFeatures(true /* isRapidCommitEnabled */, false /* isDhcpIpConflictDetectEnabled */); 3314 startIpClientProvisioning(config); 3315 3316 final DhcpPacket packet = assertDiscoverPacketOnPreconnectionStart(); 3317 verify(mCb).setNeighborDiscoveryOffload(true); 3318 3319 // Force IpClient transition to RunningState from PreconnectionState. 3320 mIpc.notifyPreconnectionComplete(true /* success */); 3321 HandlerUtils.waitForIdle(mDependencies.mDhcpClient.getHandler(), TEST_TIMEOUT_MS); 3322 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(true); 3323 3324 // DHCP server SHOULD NOT honor the Rapid-Commit option if the response would 3325 // contain the IPv6-only Preferred option to the client, instead respond with 3326 // a DHCPOFFER. 3327 mPacketReader.sendResponse(buildDhcpOfferPacket(packet, CLIENT_ADDR, TEST_LEASE_DURATION_S, 3328 (short) TEST_DEFAULT_MTU, null /* captivePortalUrl */, TEST_IPV6_ONLY_WAIT_S, 3329 null /* domainName */, null /* domainSearchList */)); 3330 3331 final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 1800, 3332 mDependencies.mDhcpClient.getHandler()); 3333 mDependencies.mDhcpClient.getHandler().post(() -> alarm.onAlarm()); 3334 3335 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpDiscoverPacket.class); 3336 } 3337 3338 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3339 public void testDiscoverIPv6OnlyPreferredOption_NoIPv6OnlyPreferredOption() throws Exception { 3340 doIPv6OnlyPreferredOptionTest(null /* ipv6OnlyWaitTime */, CLIENT_ADDR); 3341 3342 // The IPv6-only Preferred option SHOULD be included in the Parameter Request List option 3343 // in DHCPREQUEST messages after receiving a DHCPOFFER without this option. 3344 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpRequestPacket.class); 3345 } 3346 3347 private void setUpRetrievedNetworkAttributesForInitRebootState() { 3348 final NetworkAttributes na = new NetworkAttributes.Builder() 3349 .setAssignedV4Address(CLIENT_ADDR) 3350 .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid 3351 .setMtu(new Integer(TEST_DEFAULT_MTU)) 3352 .setCluster(TEST_CLUSTER) 3353 .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) 3354 .build(); 3355 storeNetworkAttributes(TEST_L2KEY, na); 3356 } 3357 3358 private void startFromInitRebootStateWithIPv6OnlyPreferredOption(final Integer ipv6OnlyWaitTime, 3359 final long expectedWaitSecs) throws Exception { 3360 setUpRetrievedNetworkAttributesForInitRebootState(); 3361 3362 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 3363 .withoutIpReachabilityMonitor() 3364 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER, 3365 MacAddress.fromString(TEST_DEFAULT_BSSID))) 3366 .build(); 3367 3368 setDhcpFeatures(false /* isRapidCommitEnabled */, 3369 false /* isDhcpIpConflictDetectEnabled */); 3370 startIpClientProvisioning(config); 3371 3372 final DhcpPacket packet = 3373 verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpRequestPacket.class); 3374 3375 // Respond DHCPACK with IPv6-Only preferred option. 3376 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, 3377 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, false /* rapidcommit */, 3378 null /* captivePortalUrl */, ipv6OnlyWaitTime, null /* domainName */, 3379 null /* domainSearchList */)); 3380 3381 if (ipv6OnlyWaitTime != null) { 3382 expectAlarmSet(null /* inOrder */, "TIMEOUT", expectedWaitSecs, 3383 mDependencies.mDhcpClient.getHandler()); 3384 } 3385 } 3386 3387 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3388 public void testRequestIPv6OnlyPreferredOption() throws Exception { 3389 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_IPV6_ONLY_WAIT_S, 3390 TEST_IPV6_ONLY_WAIT_S); 3391 3392 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid 3393 // IPv6-Only preferred option(default value) in the DHCPACK packet. 3394 assertIpMemoryNeverStoreNetworkAttributes(); 3395 } 3396 3397 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3398 public void testRequestIPv6OnlyPreferredOption_LowerIPv6OnlyWait() throws Exception { 3399 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_LOWER_IPV6_ONLY_WAIT_S, 3400 TEST_LOWER_IPV6_ONLY_WAIT_S); 3401 3402 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid 3403 // IPv6-Only preferred option(less than MIN_V6ONLY_WAIT_MS) in the DHCPACK packet. 3404 assertIpMemoryNeverStoreNetworkAttributes(); 3405 } 3406 3407 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3408 public void testRequestIPv6OnlyPreferredOption_ZeroIPv6OnlyWait() throws Exception { 3409 startFromInitRebootStateWithIPv6OnlyPreferredOption(TEST_ZERO_IPV6_ONLY_WAIT_S, 3410 TEST_LOWER_IPV6_ONLY_WAIT_S); 3411 3412 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid 3413 // IPv6-Only preferred option(0) in the DHCPACK packet. 3414 assertIpMemoryNeverStoreNetworkAttributes(); 3415 } 3416 3417 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3418 public void testRequestIPv6OnlyPreferredOption_MaxIPv6OnlyWait() throws Exception { 3419 startFromInitRebootStateWithIPv6OnlyPreferredOption((int) TEST_MAX_IPV6_ONLY_WAIT_S, 3420 0xffffffffL); 3421 3422 // Client transits to IPv6OnlyPreferredState from INIT-REBOOT state when receiving valid 3423 // IPv6-Only preferred option(MAX_UNSIGNED_INTEGER: 0xFFFFFFFF) in the DHCPACK packet. 3424 assertIpMemoryNeverStoreNetworkAttributes(); 3425 } 3426 3427 @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required") 3428 public void testRequestIPv6OnlyPreferredOption_NoIPv6OnlyPreferredOption() throws Exception { 3429 final long currentTime = System.currentTimeMillis(); 3430 startFromInitRebootStateWithIPv6OnlyPreferredOption(null /* ipv6OnlyWaitTime */, 3431 0 /* expectedWaitSecs */); 3432 3433 // Client processes DHCPACK packet normally and transits to the ConfiguringInterfaceState 3434 // due to the null V6ONLY_WAIT. 3435 assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU); 3436 } 3437 3438 private static int getNumOpenFds() { 3439 return new File("/proc/" + Os.getpid() + "/fd").listFiles().length; 3440 } 3441 3442 private void shutdownAndRecreateIpClient() throws Exception { 3443 clearInvocations(mCb); 3444 mIpc.shutdown(); 3445 awaitIpClientShutdown(); 3446 mIpc = makeIpClient(); 3447 } 3448 3449 @Test @SignatureRequiredTest(reason = "Only counts FDs from the current process. TODO: fix") 3450 public void testNoFdLeaks() throws Exception { 3451 // Shut down and restart IpClient once to ensure that any fds that are opened the first 3452 // time it runs do not cause the test to fail. 3453 doDualStackProvisioning(); 3454 shutdownAndRecreateIpClient(); 3455 3456 // Unfortunately we cannot use a large number of iterations as it would make the test run 3457 // too slowly. On crosshatch-eng each iteration takes ~250ms. 3458 final int iterations = 10; 3459 final int before = getNumOpenFds(); 3460 for (int i = 0; i < iterations; i++) { 3461 doDualStackProvisioning(); 3462 shutdownAndRecreateIpClient(); 3463 // The last time this loop runs, mIpc will be shut down in tearDown. 3464 } 3465 final int after = getNumOpenFds(); 3466 3467 // Check that the number of open fds is the same as before, within some tolerance (e.g., 3468 // garbage collection or other cleanups might have caused an fd to be closed). This 3469 // shouldn't make leak detection much less reliable, since it's likely that any leak would 3470 // at least leak one FD per loop. 3471 final int tolerance = 4; 3472 assertTrue( 3473 "FD leak detected after " + iterations + " iterations: expected " 3474 + before + " +/- " + tolerance + " fds, found " + after, 3475 Math.abs(after - before) <= tolerance); 3476 } 3477 3478 // TODO: delete when DhcpOption is @JavaOnlyImmutable. 3479 private static DhcpOption makeDhcpOption(final byte type, final byte[] value) { 3480 final DhcpOption opt = new DhcpOption(); 3481 opt.type = type; 3482 opt.value = value; 3483 return opt; 3484 } 3485 3486 private static final List<DhcpOption> TEST_OEM_DHCP_OPTIONS = Arrays.asList( 3487 // DHCP_USER_CLASS 3488 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO), 3489 // DHCP_VENDOR_CLASS_ID 3490 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()) 3491 ); 3492 3493 private DhcpPacket doCustomizedDhcpOptionsTest(final List<DhcpOption> options, 3494 final ScanResultInfo info) throws Exception { 3495 ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder() 3496 .withoutIpReachabilityMonitor() 3497 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER, 3498 MacAddress.fromString(TEST_DEFAULT_BSSID))) 3499 .withScanResultInfo(info) 3500 .withDhcpOptions(options) 3501 .withoutIPv6(); 3502 3503 setDhcpFeatures(false /* isRapidCommitEnabled */, 3504 false /* isDhcpIpConflictDetectEnabled */); 3505 3506 startIpClientProvisioning(prov.build()); 3507 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(true); 3508 verify(mCb, never()).onProvisioningFailure(any()); 3509 3510 return getNextDhcpPacket(); 3511 } 3512 3513 @Test 3514 public void testDiscoverCustomizedDhcpOptions() throws Exception { 3515 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3516 TEST_VENDOR_SPECIFIC_IE_TYPE); 3517 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3518 3519 assertTrue(packet instanceof DhcpDiscoverPacket); 3520 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID); 3521 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO); 3522 } 3523 3524 @Test 3525 public void testDiscoverCustomizedDhcpOptions_nullDhcpOptions() throws Exception { 3526 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3527 TEST_VENDOR_SPECIFIC_IE_TYPE); 3528 final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info); 3529 3530 assertTrue(packet instanceof DhcpDiscoverPacket); 3531 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3532 assertNull(packet.mUserClass); 3533 } 3534 3535 @Test 3536 public void testDiscoverCustomizedDhcpOptions_nullScanResultInfo() throws Exception { 3537 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, 3538 null /* scanResultInfo */); 3539 3540 assertTrue(packet instanceof DhcpDiscoverPacket); 3541 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3542 assertNull(packet.mUserClass); 3543 } 3544 3545 @Test 3546 public void testDiscoverCustomizedDhcpOptions_disallowedOui() throws Exception { 3547 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, 3548 new byte[]{ 0x00, 0x11, 0x22} /* oui */, TEST_VENDOR_SPECIFIC_IE_TYPE); 3549 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3550 3551 assertTrue(packet instanceof DhcpDiscoverPacket); 3552 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3553 assertNull(packet.mUserClass); 3554 } 3555 3556 @Test 3557 public void testDiscoverCustomizedDhcpOptions_invalidIeId() throws Exception { 3558 final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specific IE */, TEST_OEM_OUI, 3559 TEST_VENDOR_SPECIFIC_IE_TYPE); 3560 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3561 3562 assertTrue(packet instanceof DhcpDiscoverPacket); 3563 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3564 assertNull(packet.mUserClass); 3565 } 3566 3567 @Test 3568 public void testDiscoverCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception { 3569 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3570 (byte) 0x10 /* vendor-specific IE type */); 3571 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3572 3573 assertTrue(packet instanceof DhcpDiscoverPacket); 3574 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3575 assertNull(packet.mUserClass); 3576 } 3577 3578 @Test 3579 public void testDiscoverCustomizedDhcpOptions_legacyVendorSpecificType() throws Exception { 3580 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3581 LEGACY_TEST_VENDOR_SPECIFIC_IE_TYPE); 3582 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3583 3584 assertTrue(packet instanceof DhcpDiscoverPacket); 3585 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3586 assertNull(packet.mUserClass); 3587 } 3588 3589 @Test 3590 public void testDisoverCustomizedDhcpOptions_disallowedOption() throws Exception { 3591 final List<DhcpOption> options = Arrays.asList( 3592 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()), 3593 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO), 3594 // Option 26: MTU 3595 makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU))); 3596 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3597 TEST_VENDOR_SPECIFIC_IE_TYPE); 3598 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info); 3599 3600 assertTrue(packet instanceof DhcpDiscoverPacket); 3601 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID); 3602 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO); 3603 assertNull(packet.mMtu); 3604 } 3605 3606 @Test 3607 public void testDiscoverCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception { 3608 final List<DhcpOption> options = Arrays.asList( 3609 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()), 3610 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO), 3611 // NTP_SERVER 3612 makeDhcpOption((byte) 42, null)); 3613 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3614 TEST_VENDOR_SPECIFIC_IE_TYPE); 3615 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info); 3616 3617 assertTrue(packet instanceof DhcpDiscoverPacket); 3618 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID); 3619 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO); 3620 assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */)); 3621 } 3622 3623 @Test 3624 public void testDiscoverCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception { 3625 final List<DhcpOption> options = Arrays.asList( 3626 // DHCP_USER_CLASS 3627 makeDhcpOption((byte) 77, null)); 3628 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3629 TEST_VENDOR_SPECIFIC_IE_TYPE); 3630 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info); 3631 3632 assertTrue(packet instanceof DhcpDiscoverPacket); 3633 assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */)); 3634 assertNull(packet.mUserClass); 3635 } 3636 3637 @Test 3638 public void testRequestCustomizedDhcpOptions() throws Exception { 3639 setUpRetrievedNetworkAttributesForInitRebootState(); 3640 3641 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3642 TEST_VENDOR_SPECIFIC_IE_TYPE); 3643 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3644 3645 assertTrue(packet instanceof DhcpRequestPacket); 3646 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID); 3647 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO); 3648 } 3649 3650 @Test 3651 public void testRequestCustomizedDhcpOptions_nullDhcpOptions() throws Exception { 3652 setUpRetrievedNetworkAttributesForInitRebootState(); 3653 3654 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3655 TEST_VENDOR_SPECIFIC_IE_TYPE); 3656 final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info); 3657 3658 assertTrue(packet instanceof DhcpRequestPacket); 3659 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3660 assertNull(packet.mUserClass); 3661 } 3662 3663 @Test 3664 public void testRequestCustomizedDhcpOptions_nullScanResultInfo() throws Exception { 3665 setUpRetrievedNetworkAttributesForInitRebootState(); 3666 3667 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, 3668 null /* scanResultInfo */); 3669 3670 assertTrue(packet instanceof DhcpRequestPacket); 3671 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3672 assertNull(packet.mUserClass); 3673 } 3674 3675 @Test 3676 public void testRequestCustomizedDhcpOptions_disallowedOui() throws Exception { 3677 setUpRetrievedNetworkAttributesForInitRebootState(); 3678 3679 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, 3680 new byte[]{ 0x00, 0x11, 0x22} /* oui */, TEST_VENDOR_SPECIFIC_IE_TYPE); 3681 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3682 3683 assertTrue(packet instanceof DhcpRequestPacket); 3684 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3685 assertNull(packet.mUserClass); 3686 } 3687 3688 @Test 3689 public void testRequestCustomizedDhcpOptions_invalidIeId() throws Exception { 3690 setUpRetrievedNetworkAttributesForInitRebootState(); 3691 3692 final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specific IE */, TEST_OEM_OUI, 3693 TEST_VENDOR_SPECIFIC_IE_TYPE); 3694 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3695 3696 assertTrue(packet instanceof DhcpRequestPacket); 3697 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3698 assertNull(packet.mUserClass); 3699 } 3700 3701 @Test 3702 public void testRequestCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception { 3703 setUpRetrievedNetworkAttributesForInitRebootState(); 3704 3705 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3706 (byte) 0x20 /* vendor-specific IE type */); 3707 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3708 3709 assertTrue(packet instanceof DhcpRequestPacket); 3710 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3711 assertNull(packet.mUserClass); 3712 } 3713 3714 @Test 3715 public void testRequestCustomizedDhcpOptions_legacyVendorSpecificType() throws Exception { 3716 setUpRetrievedNetworkAttributesForInitRebootState(); 3717 3718 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3719 LEGACY_TEST_VENDOR_SPECIFIC_IE_TYPE); 3720 final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info); 3721 3722 assertTrue(packet instanceof DhcpRequestPacket); 3723 assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE)); 3724 assertNull(packet.mUserClass); 3725 } 3726 3727 @Test 3728 public void testRequestCustomizedDhcpOptions_disallowedOption() throws Exception { 3729 setUpRetrievedNetworkAttributesForInitRebootState(); 3730 3731 final List<DhcpOption> options = Arrays.asList( 3732 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()), 3733 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO), 3734 // Option 26: MTU 3735 makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU))); 3736 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3737 TEST_VENDOR_SPECIFIC_IE_TYPE); 3738 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info); 3739 3740 assertTrue(packet instanceof DhcpRequestPacket); 3741 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID); 3742 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO); 3743 assertNull(packet.mMtu); 3744 } 3745 3746 @Test 3747 public void testRequestCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception { 3748 setUpRetrievedNetworkAttributesForInitRebootState(); 3749 3750 final List<DhcpOption> options = Arrays.asList( 3751 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()), 3752 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO), 3753 // NTP_SERVER 3754 makeDhcpOption((byte) 42, null)); 3755 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3756 TEST_VENDOR_SPECIFIC_IE_TYPE); 3757 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info); 3758 3759 assertTrue(packet instanceof DhcpRequestPacket); 3760 assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID); 3761 assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO); 3762 assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */)); 3763 } 3764 3765 @Test 3766 public void testRequestCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception { 3767 setUpRetrievedNetworkAttributesForInitRebootState(); 3768 3769 final List<DhcpOption> options = Arrays.asList( 3770 // DHCP_USER_CLASS 3771 makeDhcpOption((byte) 77, null)); 3772 final ScanResultInfo info = makeScanResultInfo(TEST_VENDOR_SPECIFIC_IE_ID, TEST_OEM_OUI, 3773 TEST_VENDOR_SPECIFIC_IE_TYPE); 3774 final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info); 3775 3776 assertTrue(packet instanceof DhcpRequestPacket); 3777 assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */)); 3778 assertNull(packet.mUserClass); 3779 } 3780 3781 private void assertGratuitousNa(final NeighborAdvertisement na) throws Exception { 3782 final MacAddress etherMulticast = 3783 NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST); 3784 final LinkAddress target = new LinkAddress(na.naHdr.target, 64); 3785 3786 assertEquals(etherMulticast, na.ethHdr.dstMac); 3787 assertEquals(ETH_P_IPV6, na.ethHdr.etherType); 3788 assertEquals(IPPROTO_ICMPV6, na.ipv6Hdr.nextHeader); 3789 assertEquals(0xff, na.ipv6Hdr.hopLimit); 3790 assertTrue(na.ipv6Hdr.srcIp.isLinkLocalAddress()); 3791 assertEquals(IPV6_ADDR_ALL_ROUTERS_MULTICAST, na.ipv6Hdr.dstIp); 3792 assertEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, na.icmpv6Hdr.type); 3793 assertEquals(0, na.icmpv6Hdr.code); 3794 assertEquals(0, na.naHdr.flags); 3795 assertTrue(target.isGlobalPreferred()); 3796 } 3797 3798 private void assertMulticastNsFromIpv6Gua(final NeighborSolicitation ns) throws Exception { 3799 final Inet6Address solicitedNodeMulticast = 3800 NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast(ROUTER_LINK_LOCAL); 3801 final MacAddress etherMulticast = 3802 NetworkStackUtils.ipv6MulticastToEthernetMulticast(solicitedNodeMulticast); 3803 3804 assertEquals(etherMulticast, ns.ethHdr.dstMac); 3805 assertEquals(ETH_P_IPV6, ns.ethHdr.etherType); 3806 assertEquals(IPPROTO_ICMPV6, ns.ipv6Hdr.nextHeader); 3807 assertEquals(0xff, ns.ipv6Hdr.hopLimit); 3808 3809 final LinkAddress srcIp = new LinkAddress(ns.ipv6Hdr.srcIp.getHostAddress() + "/64"); 3810 assertTrue(srcIp.isGlobalPreferred()); 3811 assertEquals(solicitedNodeMulticast, ns.ipv6Hdr.dstIp); 3812 assertEquals(ICMPV6_NEIGHBOR_SOLICITATION, ns.icmpv6Hdr.type); 3813 assertEquals(0, ns.icmpv6Hdr.code); 3814 assertEquals(ROUTER_LINK_LOCAL, ns.nsHdr.target); 3815 } 3816 3817 @Test 3818 public void testGratuitousNaForNewGlobalUnicastAddresses() throws Exception { 3819 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 3820 .withoutIpReachabilityMonitor() 3821 .withoutIPv4() 3822 .build(); 3823 3824 startIpClientProvisioning(config); 3825 3826 doIpv6OnlyProvisioning(); 3827 3828 final List<NeighborAdvertisement> naList = new ArrayList<>(); 3829 NeighborAdvertisement packet; 3830 while ((packet = getNextNeighborAdvertisement()) != null) { 3831 assertGratuitousNa(packet); 3832 naList.add(packet); 3833 } 3834 assertEquals(2, naList.size()); // privacy address and stable privacy address 3835 } 3836 3837 private void startGratuitousArpAndNaAfterRoamingTest(boolean isGratuitousArpNaRoamingEnabled, 3838 boolean hasIpv4, boolean hasIpv6) throws Exception { 3839 final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER, 3840 MacAddress.fromString(TEST_DEFAULT_BSSID)); 3841 final ScanResultInfo scanResultInfo = 3842 makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID); 3843 final ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder() 3844 .withoutIpReachabilityMonitor() 3845 .withLayer2Information(layer2Info) 3846 .withScanResultInfo(scanResultInfo) 3847 .withDisplayName("ssid"); 3848 if (!hasIpv4) prov.withoutIPv4(); 3849 if (!hasIpv6) prov.withoutIPv6(); 3850 3851 // Enable rapid commit to accelerate DHCP handshake to shorten test duration, 3852 // not strictly necessary. 3853 setDhcpFeatures(true /* isRapidCommitEnabled */, 3854 false /* isDhcpIpConflictDetectEnabled */); 3855 3856 if (isGratuitousArpNaRoamingEnabled) { 3857 setFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, true); 3858 } else { 3859 setFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, false); 3860 } 3861 startIpClientProvisioning(prov.build()); 3862 } 3863 3864 private void waitForGratuitousArpAndNaPacket(final List<ArpPacket> arpList, 3865 final List<NeighborAdvertisement> naList) throws Exception { 3866 NeighborAdvertisement na; 3867 ArpPacket garp; 3868 do { 3869 na = getNextNeighborAdvertisement(); 3870 if (na != null) { 3871 assertGratuitousNa(na); 3872 naList.add(na); 3873 } 3874 garp = getNextArpPacket(TEST_TIMEOUT_MS); 3875 if (garp != null) { 3876 assertGratuitousARP(garp); 3877 arpList.add(garp); 3878 } 3879 } while (na != null || garp != null); 3880 } 3881 3882 @Test 3883 public void testGratuitousArpAndNaAfterRoaming() throws Exception { 3884 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */, 3885 true /* hasIpv4 */, true /* hasIpv6 */); 3886 performDualStackProvisioning(); 3887 forceLayer2Roaming(); 3888 3889 final List<ArpPacket> arpList = new ArrayList<>(); 3890 final List<NeighborAdvertisement> naList = new ArrayList<>(); 3891 waitForGratuitousArpAndNaPacket(arpList, naList); 3892 // 2 NAs sent due to RFC9131 implement and 2 NAs sent after roam 3893 assertEquals(4, naList.size()); // privacy address and stable privacy address 3894 assertEquals(1, arpList.size()); // IPv4 address 3895 } 3896 3897 @Test 3898 public void testGratuitousArpAndNaAfterRoaming_disableExpFlag() throws Exception { 3899 startGratuitousArpAndNaAfterRoamingTest(false /* isGratuitousArpNaRoamingEnabled */, 3900 true /* hasIpv4 */, true /* hasIpv6 */); 3901 performDualStackProvisioning(); 3902 forceLayer2Roaming(); 3903 3904 final List<ArpPacket> arpList = new ArrayList<>(); 3905 final List<NeighborAdvertisement> naList = new ArrayList<>(); 3906 waitForGratuitousArpAndNaPacket(arpList, naList); 3907 assertEquals(2, naList.size()); // NAs sent due to RFC9131 implement, not from roam 3908 assertEquals(0, arpList.size()); 3909 } 3910 3911 @Test 3912 public void testGratuitousArpAndNaAfterRoaming_IPv6OnlyNetwork() throws Exception { 3913 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */, 3914 false /* hasIpv4 */, true /* hasIpv6 */); 3915 doIpv6OnlyProvisioning(); 3916 forceLayer2Roaming(); 3917 3918 final List<ArpPacket> arpList = new ArrayList<>(); 3919 final List<NeighborAdvertisement> naList = new ArrayList<>(); 3920 waitForGratuitousArpAndNaPacket(arpList, naList); 3921 // 2 NAs sent due to RFC9131 implement and 2 NAs sent after roam 3922 assertEquals(4, naList.size()); 3923 assertEquals(0, arpList.size()); 3924 } 3925 3926 @Test 3927 public void testGratuitousArpAndNaAfterRoaming_IPv4OnlyNetwork() throws Exception { 3928 startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */, 3929 true /* hasIpv4 */, false /* hasIpv6 */); 3930 3931 // Start IPv4 provisioning and wait until entire provisioning completes. 3932 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 3933 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */); 3934 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 3935 forceLayer2Roaming(); 3936 3937 final List<ArpPacket> arpList = new ArrayList<>(); 3938 final List<NeighborAdvertisement> naList = new ArrayList<>(); 3939 waitForGratuitousArpAndNaPacket(arpList, naList); 3940 assertEquals(0, naList.size()); 3941 assertEquals(1, arpList.size()); 3942 } 3943 3944 private void assertNeighborSolicitation(final NeighborSolicitation ns, 3945 final Inet6Address target) { 3946 assertEquals(ETH_P_IPV6, ns.ethHdr.etherType); 3947 assertEquals(IPPROTO_ICMPV6, ns.ipv6Hdr.nextHeader); 3948 assertEquals(0xff, ns.ipv6Hdr.hopLimit); 3949 assertTrue(ns.ipv6Hdr.srcIp.isLinkLocalAddress()); 3950 assertEquals(ICMPV6_NEIGHBOR_SOLICITATION, ns.icmpv6Hdr.type); 3951 assertEquals(0, ns.icmpv6Hdr.code); 3952 assertEquals(0, ns.nsHdr.reserved); 3953 assertEquals(target, ns.nsHdr.target); 3954 assertEquals(ns.slla.linkLayerAddress, ns.ethHdr.srcMac); 3955 } 3956 3957 private void assertUnicastNeighborSolicitation(final NeighborSolicitation ns, 3958 final MacAddress dstMac, final Inet6Address dstIp, final Inet6Address target) { 3959 assertEquals(dstMac, ns.ethHdr.dstMac); 3960 assertEquals(dstIp, ns.ipv6Hdr.dstIp); 3961 assertNeighborSolicitation(ns, target); 3962 } 3963 3964 private void assertMulticastNeighborSolicitation(final NeighborSolicitation ns, 3965 final Inet6Address target) { 3966 final MacAddress etherMulticast = 3967 NetworkStackUtils.ipv6MulticastToEthernetMulticast(ns.ipv6Hdr.dstIp); 3968 assertEquals(etherMulticast, ns.ethHdr.dstMac); 3969 assertTrue(ns.ipv6Hdr.dstIp.isMulticastAddress()); 3970 assertNeighborSolicitation(ns, target); 3971 } 3972 3973 private NeighborSolicitation waitForUnicastNeighborSolicitation(final MacAddress dstMac, 3974 final Inet6Address dstIp, final Inet6Address targetIp) throws Exception { 3975 NeighborSolicitation ns; 3976 while ((ns = getNextNeighborSolicitation()) != null) { 3977 // Filter out the multicast NSes used for duplicate address detetction, the target 3978 // address is the global IPv6 address inside these NSes, and multicast NSes sent from 3979 // device's GUAs to force first-hop router to update the neighbor cache entry. 3980 if (ns.ipv6Hdr.srcIp.isLinkLocalAddress() && ns.nsHdr.target.isLinkLocalAddress()) { 3981 break; 3982 } 3983 } 3984 assertNotNull("No unicast Neighbor solicitation received on interface within timeout", ns); 3985 assertUnicastNeighborSolicitation(ns, dstMac, dstIp, targetIp); 3986 return ns; 3987 } 3988 3989 private List<NeighborSolicitation> waitForMultipleNeighborSolicitations() throws Exception { 3990 NeighborSolicitation ns; 3991 final List<NeighborSolicitation> nsList = new ArrayList<NeighborSolicitation>(); 3992 while ((ns = getNextNeighborSolicitation()) != null) { 3993 // Filter out the multicast NSes used for duplicate address detetction, the target 3994 // address is the global IPv6 address inside these NSes, and multicast NSes sent from 3995 // device's GUAs to force first-hop router to update the neighbor cache entry. 3996 if (ns.ipv6Hdr.srcIp.isLinkLocalAddress() && ns.nsHdr.target.isLinkLocalAddress()) { 3997 nsList.add(ns); 3998 } 3999 } 4000 assertFalse(nsList.isEmpty()); 4001 return nsList; 4002 } 4003 4004 private NeighborSolicitation expectDadNeighborSolicitationForLinkLocal(boolean shouldDisableDad) 4005 throws Exception { 4006 final NeighborSolicitation ns = getNextNeighborSolicitation(); 4007 if (!shouldDisableDad) { 4008 final Inet6Address solicitedNodeMulticast = 4009 NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast(ns.nsHdr.target); 4010 assertNotNull("No multicast NS received on interface within timeout", ns); 4011 assertEquals(IPV6_ADDR_ANY, ns.ipv6Hdr.srcIp); // srcIp: ::/ 4012 assertTrue(ns.ipv6Hdr.dstIp.isMulticastAddress()); // dstIp: solicited-node mcast 4013 assertTrue(ns.ipv6Hdr.dstIp.equals(solicitedNodeMulticast)); 4014 assertTrue(ns.nsHdr.target.isLinkLocalAddress()); // targetIp: IPv6 LL address 4015 } else { 4016 assertNull(ns); 4017 } 4018 return ns; 4019 } 4020 4021 // Override this function with disabled experiment flag by default, in order not to 4022 // affect those tests which are just related to basic IpReachabilityMonitor infra. 4023 private void prepareIpReachabilityMonitorTest() throws Exception { 4024 prepareIpReachabilityMonitorTest(false /* isMulticastResolicitEnabled */); 4025 } 4026 4027 private void assertNotifyNeighborLost(Inet6Address targetIp, NudEventType eventType) 4028 throws Exception { 4029 // For root test suite, rely on the IIpClient aidl interface version constant defined in 4030 // {@link IpClientRootTest.BinderCbWrapper}; for privileged integration test suite that 4031 // requires signature permission, use the mocked aidl version defined in {@link setUpMocks}, 4032 // which results in only new callbacks are verified. And add separate test cases to test the 4033 // legacy callbacks explicitly as well. 4034 assertNeighborReachabilityLoss(targetIp, eventType, 4035 useNetworkStackSignature() 4036 ? IpClient.VERSION_ADDED_REACHABILITY_FAILURE 4037 : mIIpClient.getInterfaceVersion()); 4038 } 4039 4040 private void assertNeighborReachabilityLoss(Inet6Address targetIp, NudEventType eventType, 4041 int targetAidlVersion) throws Exception { 4042 if (targetAidlVersion >= IpClient.VERSION_ADDED_REACHABILITY_FAILURE) { 4043 final ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor = 4044 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class); 4045 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityFailure(lossInfoCaptor.capture()); 4046 assertEquals(nudEventTypeToInt(eventType), lossInfoCaptor.getValue().reason); 4047 verify(mCb, never()).onReachabilityLost(any()); 4048 } else { 4049 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any()); 4050 verify(mCb, never()).onReachabilityFailure(any()); 4051 } 4052 } 4053 4054 private void assertNeverNotifyNeighborLost() throws Exception { 4055 verify(mCb, never()).onReachabilityFailure(any()); 4056 verify(mCb, never()).onReachabilityLost(any()); 4057 } 4058 4059 private void prepareIpReachabilityMonitorTest(boolean isMulticastResolicitEnabled) 4060 throws Exception { 4061 final ScanResultInfo info = makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID); 4062 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4063 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER, 4064 MacAddress.fromString(TEST_DEFAULT_BSSID))) 4065 .withScanResultInfo(info) 4066 .withDisplayName(TEST_DEFAULT_SSID) 4067 .withoutIPv4() 4068 .build(); 4069 setFeatureEnabled(NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION, 4070 isMulticastResolicitEnabled); 4071 startIpClientProvisioning(config); 4072 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(true); 4073 doIpv6OnlyProvisioning(); 4074 4075 // Simulate the roaming. 4076 forceLayer2Roaming(); 4077 } 4078 4079 private void runIpReachabilityMonitorProbeFailedTest() throws Exception { 4080 prepareIpReachabilityMonitorTest(); 4081 4082 final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations(); 4083 final int expectedNudSolicitNum = readNudSolicitNumPostRoamingFromResource(); 4084 assertEquals(expectedNudSolicitNum, nsList.size()); 4085 for (NeighborSolicitation ns : nsList) { 4086 assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */, 4087 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */); 4088 } 4089 } 4090 4091 @Test 4092 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4093 public void testIpReachabilityMonitor_probeFailed() throws Exception { 4094 runIpReachabilityMonitorProbeFailedTest(); 4095 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 4096 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL); 4097 } 4098 4099 @Test @SignatureRequiredTest(reason = "requires mock callback object") 4100 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4101 public void testIpReachabilityMonitor_probeFailed_legacyCallback() throws Exception { 4102 when(mCb.getInterfaceVersion()).thenReturn(12 /* assign an older interface aidl version */); 4103 4104 runIpReachabilityMonitorProbeFailedTest(); 4105 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any()); 4106 verify(mCb, never()).onReachabilityFailure(any()); 4107 } 4108 4109 @Test 4110 public void testIpReachabilityMonitor_probeReachable() throws Exception { 4111 prepareIpReachabilityMonitorTest(); 4112 4113 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */, 4114 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */); 4115 4116 // Reply Neighbor Advertisement and check notifyLost callback won't be triggered. 4117 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; 4118 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */, 4119 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */, 4120 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */); 4121 mPacketReader.sendResponse(na); 4122 assertNeverNotifyNeighborLost(); 4123 } 4124 4125 private void runIpReachabilityMonitorMcastResolicitProbeFailedTest() throws Exception { 4126 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */); 4127 4128 final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations(); 4129 final int expectedNudSolicitNum = readNudSolicitNumPostRoamingFromResource(); 4130 int expectedSize = expectedNudSolicitNum + NUD_MCAST_RESOLICIT_NUM; 4131 assertEquals(expectedSize, nsList.size()); 4132 for (NeighborSolicitation ns : nsList.subList(0, expectedNudSolicitNum)) { 4133 assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */, 4134 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */); 4135 } 4136 for (NeighborSolicitation ns : nsList.subList(expectedNudSolicitNum, nsList.size())) { 4137 assertMulticastNeighborSolicitation(ns, ROUTER_LINK_LOCAL /* targetIp */); 4138 } 4139 } 4140 4141 @Test 4142 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4143 public void testIpReachabilityMonitor_mcastResolicitProbeFailed() throws Exception { 4144 runIpReachabilityMonitorMcastResolicitProbeFailedTest(); 4145 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 4146 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL); 4147 } 4148 4149 @Test @SignatureRequiredTest(reason = "requires mock callback object") 4150 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4151 public void testIpReachabilityMonitor_mcastResolicitProbeFailed_legacyCallback() 4152 throws Exception { 4153 when(mCb.getInterfaceVersion()).thenReturn(12 /* assign an older interface aidl version */); 4154 4155 runIpReachabilityMonitorMcastResolicitProbeFailedTest(); 4156 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(any()); 4157 verify(mCb, never()).onReachabilityFailure(any()); 4158 } 4159 4160 @Test 4161 public void testIpReachabilityMonitor_mcastResolicitProbeReachableWithSameLinkLayerAddress() 4162 throws Exception { 4163 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */); 4164 4165 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */, 4166 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */); 4167 4168 // Reply Neighbor Advertisement and check notifyLost callback won't be triggered. 4169 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; 4170 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */, 4171 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */, 4172 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */); 4173 mPacketReader.sendResponse(na); 4174 assertNeverNotifyNeighborLost(); 4175 } 4176 4177 @Test 4178 public void testIpReachabilityMonitor_mcastResolicitProbeReachableWithDiffLinkLayerAddress() 4179 throws Exception { 4180 prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */); 4181 4182 final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */, 4183 ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */); 4184 4185 // Reply Neighbor Advertisement with a different link-layer address and check notifyLost 4186 // callback will be triggered. Override flag must be set, which indicates that the 4187 // advertisement should override an existing cache entry and update the cached link-layer 4188 // address, otherwise, kernel won't transit to REACHABLE state with a different link-layer 4189 // address. 4190 int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED 4191 | NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; 4192 final MacAddress newMac = MacAddress.fromString("00:1a:11:22:33:55"); 4193 final ByteBuffer na = NeighborAdvertisement.build(newMac /* srcMac */, 4194 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */, 4195 ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */); 4196 mPacketReader.sendResponse(na); 4197 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 4198 NudEventType.NUD_POST_ROAMING_MAC_ADDRESS_CHANGED); 4199 } 4200 4201 private void prepareIpReachabilityMonitorIpv4AddressResolutionTest() throws Exception { 4202 mNetworkAgentThread = 4203 new HandlerThread(IpClientIntegrationTestCommon.class.getSimpleName()); 4204 mNetworkAgentThread.start(); 4205 4206 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4207 .withoutIPv6() 4208 .build(); 4209 setDhcpFeatures(true /* isRapidCommitEnabled */, false /* isDhcpIpConflictDetectEnabled */); 4210 startIpClientProvisioning(config); 4211 4212 // Start IPv4 provisioning and wait until entire provisioning completes. 4213 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 4214 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */); 4215 final LinkProperties lp = 4216 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 4217 4218 runAsShell(MANAGE_TEST_NETWORKS, () -> createTestNetworkAgentAndRegister(lp)); 4219 4220 // Send a UDP packet to IPv4 DNS server to trigger address resolution process for IPv4 4221 // on-link DNS server or default router. 4222 final Random random = new Random(); 4223 final byte[] data = new byte[100]; 4224 random.nextBytes(data); 4225 sendUdpPacketToNetwork(mNetworkAgent.getNetwork(), SERVER_ADDR, 1234 /* port */, data); 4226 } 4227 4228 private void doTestIpReachabilityMonitor_replyBroadcastArpRequestWithDiffMacAddresses( 4229 boolean disconnect) throws Exception { 4230 prepareIpReachabilityMonitorIpv4AddressResolutionTest(); 4231 4232 // Respond to the broadcast ARP request. 4233 final ArpPacket request = getNextArpPacket(); 4234 assertArpRequest(request, SERVER_ADDR); 4235 sendArpReply(request.senderHwAddress.toByteArray() /* dst */, ROUTER_MAC_BYTES /* srcMac */, 4236 request.senderIp /* target IP */, SERVER_ADDR /* sender IP */); 4237 4238 Thread.sleep(1500); 4239 4240 // Reply with a different MAC address but the same server IP. 4241 final MacAddress gateway = MacAddress.fromString("00:11:22:33:44:55"); 4242 sendArpReply(request.senderHwAddress.toByteArray() /* dst */, 4243 gateway.toByteArray() /* srcMac */, 4244 request.senderIp /* target IP */, SERVER_ADDR /* sender IP */); 4245 4246 if (disconnect) { 4247 final ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor = 4248 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class); 4249 verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityFailure(lossInfoCaptor.capture()); 4250 assertEquals(ReachabilityLossReason.ORGANIC, lossInfoCaptor.getValue().reason); 4251 } else { 4252 verify(mCb, after(100).never()).onReachabilityFailure(any()); 4253 } 4254 } 4255 4256 @Test 4257 public void testIpReachabilityMonitor_macAddressChangedWithoutRoam_ok() 4258 throws Exception { 4259 setFeatureChickenedOut(IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, 4260 false); 4261 doTestIpReachabilityMonitor_replyBroadcastArpRequestWithDiffMacAddresses(false); 4262 } 4263 4264 @Test 4265 public void testIpReachabilityMonitor_macAddressChangedWithoutRoam_disconnect() 4266 throws Exception { 4267 setFeatureChickenedOut(IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, 4268 true); 4269 doTestIpReachabilityMonitor_replyBroadcastArpRequestWithDiffMacAddresses(true); 4270 } 4271 4272 @Test 4273 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true) 4274 public void testIpReachabilityMonitor_ignoreIpv4DefaultRouterOrganicNudFailure() 4275 throws Exception { 4276 prepareIpReachabilityMonitorIpv4AddressResolutionTest(); 4277 4278 ArpPacket packet; 4279 while ((packet = getNextArpPacket(TEST_TIMEOUT_MS)) != null) { 4280 // wait address resolution to complete. 4281 } 4282 verify(mCb, never()).onReachabilityFailure(any()); 4283 } 4284 4285 @Test 4286 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4287 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4288 public void testIpReachabilityMonitor_ignoreIpv4DefaultRouterOrganicNudFailure_flagoff() 4289 throws Exception { 4290 prepareIpReachabilityMonitorIpv4AddressResolutionTest(); 4291 4292 ArpPacket packet; 4293 while ((packet = getNextArpPacket(TEST_TIMEOUT_MS)) != null) { 4294 // wait address resolution to complete. 4295 } 4296 final ArgumentCaptor<ReachabilityLossInfoParcelable> lossInfoCaptor = 4297 ArgumentCaptor.forClass(ReachabilityLossInfoParcelable.class); 4298 verify(mCb).onReachabilityFailure(lossInfoCaptor.capture()); 4299 assertEquals(ReachabilityLossReason.ORGANIC, lossInfoCaptor.getValue().reason); 4300 } 4301 4302 private void sendUdpPacketToNetwork(final Network network, final InetAddress remoteIp, 4303 int port, final byte[] data) throws Exception { 4304 final InetAddress laddr = 4305 (remoteIp instanceof Inet6Address) ? Inet6Address.ANY : Inet4Address.ANY; 4306 final DatagramSocket socket = new DatagramSocket(0, laddr); 4307 final DatagramPacket pkt = new DatagramPacket(data, data.length, remoteIp, port); 4308 network.bindSocket(socket); 4309 socket.send(pkt); 4310 } 4311 4312 private void prepareIpReachabilityMonitorAddressResolutionTest(final String dnsServer, 4313 final Inet6Address targetIp) throws Exception { 4314 mNetworkAgentThread = 4315 new HandlerThread(IpClientIntegrationTestCommon.class.getSimpleName()); 4316 mNetworkAgentThread.start(); 4317 4318 setDhcpFeatures(true /* isRapidCommitEnabled */, 4319 false /* isDhcpIpConflictDetectEnabled */); 4320 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4321 // We've found that mCm.shouldAvoidBadWifi() has a flaky behavior in the root test, 4322 // probably due to the sim card in the DUT. it doesn't occur in the siganture test 4323 // since we mock the return value directly. As a result, sometimes 4324 // IpReachabilityMonitor#avoidingBadLinks() returns false, it caused the expected 4325 // onReachabilityFailure callback wasn't triggered on the test. In order to make 4326 // the root test more stable, do not use MultinetworkPolicyTracker only for IPv6 4327 // neighbor reachability checking relevant test cases, that guarantees 4328 // avoidingBadLinks() always returns true which is expected. 4329 .withoutMultinetworkPolicyTracker() 4330 // Make cluster as non-null to test the NUD failure event count query logic. 4331 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER, 4332 MacAddress.fromString(TEST_DEFAULT_BSSID))) 4333 .build(); 4334 startIpClientProvisioning(config); 4335 verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(true); 4336 4337 final List<ByteBuffer> options = new ArrayList<ByteBuffer>(); 4338 options.add(buildPioOption(3600, 1800, "2001:db8:1::/64")); // PIO 4339 options.add(buildRdnssOption(3600, dnsServer)); // RDNSS 4340 // If target IP of address resolution is default router's IPv6 link-local address, 4341 // then we should not take SLLA option in RA. 4342 if (!targetIp.equals(ROUTER_LINK_LOCAL)) { 4343 options.add(buildSllaOption()); // SLLA 4344 } 4345 final ByteBuffer ra = buildRaPacket(options.toArray(new ByteBuffer[options.size()])); 4346 final Inet6Address dnsServerIp = ipv6Addr(dnsServer); 4347 final LinkProperties lp = performDualStackProvisioning(ra, dnsServerIp); 4348 runAsShell(MANAGE_TEST_NETWORKS, () -> createTestNetworkAgentAndRegister(lp)); 4349 } 4350 4351 /** 4352 * Send a UDP packet to dstIp to trigger address resolution for targetIp, and possibly expect a 4353 * neighbor lost callback. 4354 * If dstIp is on-link, then dstIp and targetIp should be the same. 4355 * If dstIp is off-link, then targetIp should be the IPv6 default router. 4356 * The ND cache should not have an entry for targetIp. 4357 */ 4358 private void sendPacketToUnreachableNeighbor(Inet6Address dstIp) throws Exception { 4359 final Random random = new Random(); 4360 final byte[] data = new byte[100]; 4361 random.nextBytes(data); 4362 sendUdpPacketToNetwork(mNetworkAgent.getNetwork(), dstIp, 1234 /* port */, data); 4363 } 4364 4365 private void expectAndDropMulticastNses(Inet6Address targetIp, boolean expectNeighborLost) 4366 throws Exception { 4367 // Wait for the multicast NSes but never respond to them, that results in the on-link 4368 // DNS gets lost and onReachabilityLost callback will be invoked. 4369 final List<NeighborSolicitation> nsList = new ArrayList<NeighborSolicitation>(); 4370 NeighborSolicitation ns; 4371 while ((ns = getNextNeighborSolicitation()) != null) { 4372 // multicast NS for address resolution, IPv6 dst address in that NS is solicited-node 4373 // multicast address based on the target IP, the target IP is either on-link IPv6 DNS 4374 // server address or IPv6 link-local address of default gateway. 4375 final LinkAddress actual = new LinkAddress(ns.nsHdr.target, 64); 4376 final LinkAddress target = new LinkAddress(targetIp, 64); 4377 if (actual.equals(target) && ns.ipv6Hdr.dstIp.isMulticastAddress()) { 4378 nsList.add(ns); 4379 } 4380 } 4381 assertFalse(nsList.isEmpty()); 4382 4383 if (expectNeighborLost) { 4384 assertNotifyNeighborLost(targetIp, NudEventType.NUD_ORGANIC_FAILED_CRITICAL); 4385 } else { 4386 assertNeverNotifyNeighborLost(); 4387 } 4388 } 4389 4390 private void runIpReachabilityMonitorAddressResolutionTest(final String dnsServer, 4391 final Inet6Address targetIp, 4392 final boolean expectNeighborLost) throws Exception { 4393 prepareIpReachabilityMonitorAddressResolutionTest(dnsServer, targetIp); 4394 sendPacketToUnreachableNeighbor(ipv6Addr(dnsServer)); 4395 expectAndDropMulticastNses(targetIp, expectNeighborLost); 4396 } 4397 4398 @Test 4399 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = true) 4400 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4401 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4402 public void testIpReachabilityMonitor_incompleteIpv6DnsServerInDualStack() throws Exception { 4403 final Inet6Address targetIp = ipv6Addr(IPV6_ON_LINK_DNS_SERVER); 4404 runIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, targetIp, 4405 false /* expectNeighborLost */); 4406 } 4407 4408 @Test 4409 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4410 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4411 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4412 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4413 public void testIpReachabilityMonitor_incompleteIpv6DnsServerInDualStack_flagoff() 4414 throws Exception { 4415 final Inet6Address targetIp = ipv6Addr(IPV6_ON_LINK_DNS_SERVER); 4416 runIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, targetIp, 4417 true /* expectNeighborLost */); 4418 } 4419 4420 @Test 4421 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4422 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = true) 4423 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4424 public void testIpReachabilityMonitor_incompleteIpv6DefaultRouterInDualStack() 4425 throws Exception { 4426 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 4427 ROUTER_LINK_LOCAL /* targetIp */, 4428 false /* expectNeighborLost */); 4429 } 4430 4431 @Test 4432 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4433 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4434 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4435 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4436 public void testIpReachabilityMonitor_incompleteIpv6DefaultRouterInDualStack_flagoff() 4437 throws Exception { 4438 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 4439 ROUTER_LINK_LOCAL /* targetIp */, 4440 true /* expectNeighborLost */); 4441 } 4442 4443 @Test 4444 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4445 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4446 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true) 4447 public void testIpReachabilityMonitor_ignoreOnLinkIpv6DnsOrganicNudFailure() 4448 throws Exception { 4449 final Inet6Address targetIp = ipv6Addr(IPV6_ON_LINK_DNS_SERVER); 4450 runIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, targetIp, 4451 false /* expectNeighborLost */); 4452 } 4453 4454 @Test 4455 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4456 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4457 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4458 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4459 public void testIpReachabilityMonitor_ignoreOnLinkIpv6DnsOrganicNudFailure_flagoff() 4460 throws Exception { 4461 final Inet6Address targetIp = ipv6Addr(IPV6_ON_LINK_DNS_SERVER); 4462 runIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, targetIp, 4463 true /* expectNeighborLost */); 4464 } 4465 4466 @Test 4467 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4468 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4469 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true) 4470 public void testIpReachabilityMonitor_ignoreIpv6DefaultRouterOrganicNudFailure() 4471 throws Exception { 4472 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 4473 ROUTER_LINK_LOCAL /* targetIp */, 4474 false /* expectNeighborLost */); 4475 } 4476 4477 @Test 4478 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4479 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4480 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4481 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 4482 public void testIpReachabilityMonitor_ignoreIpv6DefaultRouterOrganicNudFailure_flagoff() 4483 throws Exception { 4484 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 4485 ROUTER_LINK_LOCAL /* targetIp */, 4486 true /* expectNeighborLost */); 4487 } 4488 4489 private void runIpReachabilityMonitorEverReachableIpv6NeighborTest(final String dnsServer, 4490 final Inet6Address targetIp) throws Exception { 4491 prepareIpReachabilityMonitorAddressResolutionTest(dnsServer, targetIp); 4492 sendPacketToUnreachableNeighbor(ipv6Addr(dnsServer)); 4493 4494 // Simulate the default router/DNS was reachable by responding to multicast NS(not for DAD). 4495 NeighborSolicitation ns; 4496 while ((ns = getNextNeighborSolicitation()) != null) { 4497 if (ns.ipv6Hdr.dstIp.isMulticastAddress() // Solicited-node multicast address 4498 && ns.nsHdr.target.equals(targetIp)) { 4499 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */, 4500 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */, 4501 ns.ipv6Hdr.srcIp /* dstIp */, 4502 NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED, 4503 targetIp); 4504 mPacketReader.sendResponse(na); 4505 break; 4506 } 4507 } 4508 4509 // Trigger the NUD probe manually by sending CMD_CONFIRM command, this will force to start 4510 // probing for all neighbors in the watchlist including default router and on-link DNS. 4511 mIIpClient.confirmConfiguration(); 4512 4513 // Wait for the next unicast NS probes, but don't respond to them, which should trigger 4514 // reachability failure callback because the probe status is from probed to failed, rather 4515 // than incomplete to failed. 4516 while ((ns = getNextNeighborSolicitation()) != null) { 4517 // Respond to NS for default router, it's used to avoid triggering multiple 4518 // onReachabilityFailure callbacks. 4519 if (!targetIp.equals(ROUTER_LINK_LOCAL)) { 4520 final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */, 4521 ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */, 4522 ns.ipv6Hdr.srcIp /* dstIp */, 4523 NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED, 4524 ROUTER_LINK_LOCAL); 4525 mPacketReader.sendResponse(na); 4526 } 4527 } 4528 assertNotifyNeighborLost(targetIp, NudEventType.NUD_CONFIRM_FAILED_CRITICAL); 4529 } 4530 4531 @Test 4532 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 4533 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = true) 4534 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4535 public void testIpReachabilityMonitor_ignoreIpv6DefaultRouter_everReachable() throws Exception { 4536 runIpReachabilityMonitorEverReachableIpv6NeighborTest(IPV6_OFF_LINK_DNS_SERVER, 4537 ROUTER_LINK_LOCAL /* targetIp */); 4538 } 4539 4540 @Test 4541 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = true) 4542 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 4543 @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = false) 4544 public void testIpReachabilityMonitor_ignoreIpv6Dns_everReachable() throws Exception { 4545 runIpReachabilityMonitorEverReachableIpv6NeighborTest(IPV6_ON_LINK_DNS_SERVER, 4546 ipv6Addr(IPV6_ON_LINK_DNS_SERVER) /* targetIp */); 4547 } 4548 4549 @Test 4550 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true) 4551 public void testIpReachabilityMonitor_ignoreNeverReachableIpv6Dns() throws Exception { 4552 runIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, 4553 ipv6Addr(IPV6_ON_LINK_DNS_SERVER), false /* expectNeighborLost */); 4554 } 4555 4556 @Test 4557 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true) 4558 public void testIpReachabilityMonitor_ignoreNeverReachableIpv6Dns_butEverReachable() 4559 throws Exception { 4560 runIpReachabilityMonitorEverReachableIpv6NeighborTest(IPV6_ON_LINK_DNS_SERVER, 4561 ipv6Addr(IPV6_ON_LINK_DNS_SERVER) /* targetIp */); 4562 } 4563 4564 @Test 4565 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true) 4566 public void testIpReachabilityMonitor_ignoreNeverReachableIpv6DefaultRouter() throws Exception { 4567 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 4568 ROUTER_LINK_LOCAL, false /* expectNeighborLost */); 4569 } 4570 4571 @Test 4572 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true) 4573 public void testIpReachabilityMonitor_ignoreNeverReachableIpv6DefaultRouter_butEverReachable() 4574 throws Exception { 4575 runIpReachabilityMonitorEverReachableIpv6NeighborTest(IPV6_ON_LINK_DNS_SERVER, 4576 ROUTER_LINK_LOCAL /* targetIp */); 4577 } 4578 4579 @Test 4580 public void testIPv6LinkLocalOnly() throws Exception { 4581 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4582 .withoutIPv4() 4583 .withIpv6LinkLocalOnly() 4584 .withRandomMacAddress() 4585 .build(); 4586 startIpClientProvisioning(config); 4587 4588 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 4589 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 4590 final LinkProperties lp = captor.getValue(); 4591 assertNotNull(lp); 4592 assertEquals(0, lp.getDnsServers().size()); 4593 final List<LinkAddress> addresses = lp.getLinkAddresses(); 4594 assertEquals(1, addresses.size()); 4595 assertTrue(addresses.get(0).getAddress().isLinkLocalAddress()); // only IPv6 link-local 4596 assertTrue(hasRouteTo(lp, IPV6_LINK_LOCAL_PREFIX)); // fe80::/64 -> :: iface mtu 0 4597 4598 // Check that if an RA is received, no IP addresses, routes, or DNS servers are configured. 4599 // Instead of waiting some period of time for the RA to be received and checking the 4600 // LinkProperties after that, tear down the interface and wait for it to go down. Then check 4601 // that no LinkProperties updates ever contained non-link-local information. 4602 sendBasicRouterAdvertisement(false /* waitForRs */); 4603 teardownTapInterface(); 4604 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any()); 4605 verify(mCb, never()).onLinkPropertiesChange(argThat(newLp -> 4606 // Ideally there should be only one route(fe80::/64 -> :: iface mtu 0) in the 4607 // LinkProperties, however, the multicast route(ff00::/8 -> :: iface mtu 0) may 4608 // appear on some old platforms where the kernel is still notifying the userspace 4609 // the multicast route. Therefore, we cannot assert that size of routes in the 4610 // LinkProperties is more than one, but other properties such as DNS or IPv6 4611 // default route or global IPv6 address should never appear in the IPv6 link-local 4612 // only mode. 4613 newLp.getDnsServers().size() != 0 4614 || newLp.hasIpv6DefaultRoute() 4615 || newLp.hasGlobalIpv6Address() 4616 )); 4617 } 4618 4619 @Test 4620 public void testIPv6LinkLocalOnly_verifyAcceptRaDefrtr() throws Exception { 4621 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4622 .withoutIPv4() 4623 .withIpv6LinkLocalOnly() 4624 .withRandomMacAddress() 4625 .build(); 4626 startIpClientProvisioning(config); 4627 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); 4628 4629 clearInvocations(mCb); 4630 4631 // accept_ra is set to 0 and accept_ra_defrtr is set to 1 in IPv6 link-local only mode, 4632 // send another RA to tap interface, to verify that we should not see any IPv6 provisioning 4633 // although accept_ra_defrtr is set to 1. 4634 sendBasicRouterAdvertisement(false /* waitForRs */); 4635 verify(mCb, never()).onLinkPropertiesChange(argThat(x -> x.isIpv6Provisioned())); 4636 } 4637 4638 @Test 4639 public void testIPv6LinkLocalOnlyAndThenGlobal() throws Exception { 4640 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4641 .withoutIPv4() 4642 .withIpv6LinkLocalOnly() 4643 .withRandomMacAddress() 4644 .build(); 4645 startIpClientProvisioning(config); 4646 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); 4647 mIIpClient.stop(); 4648 verifyAfterIpClientShutdown(); 4649 reset(mCb); 4650 4651 // Speed up provisioning by enabling rapid commit. TODO: why is this necessary? 4652 setDhcpFeatures(true /* isRapidCommitEnabled */, 4653 false /* isDhcpIpConflictDetectEnabled */); 4654 config = new ProvisioningConfiguration.Builder() 4655 .build(); 4656 startIpClientProvisioning(config); 4657 performDualStackProvisioning(); 4658 // No exceptions? Dual-stack provisioning worked. 4659 } 4660 4661 @Test 4662 public void testIPv6LinkLocalOnly_enableBothIPv4andIPv6LinkLocalOnly() throws Exception { 4663 assertThrows(IllegalArgumentException.class, 4664 () -> new ProvisioningConfiguration.Builder() 4665 .withoutIpReachabilityMonitor() 4666 .withIpv6LinkLocalOnly() 4667 .withRandomMacAddress() 4668 .build() 4669 ); 4670 } 4671 4672 private void runIpv6LinkLocalOnlyDadTransmitsCheckTest(boolean shouldDisableDad) 4673 throws Exception { 4674 ProvisioningConfiguration.Builder config = new ProvisioningConfiguration.Builder() 4675 .withoutIPv4() 4676 .withIpv6LinkLocalOnly() 4677 .withRandomMacAddress(); 4678 if (shouldDisableDad) config.withUniqueEui64AddressesOnly(); 4679 4680 // dad_transmits has been set to 0 in disableIpv6ProvisioningDelays, re-enable dad_transmits 4681 // for testing, but production code could disable dad again later, we should never see any 4682 // multicast NS for duplicate address detection then. 4683 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits", "1"); 4684 startIpClientProvisioning(config.build()); 4685 verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetEnableIPv6(mIfaceName, true); 4686 // Check dad_transmits should be set to 0 if UniqueEui64AddressesOnly mode is enabled. 4687 int dadTransmits = Integer.parseUnsignedInt( 4688 mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits")); 4689 if (shouldDisableDad) { 4690 assertEquals(0, dadTransmits); 4691 } else { 4692 assertEquals(1, dadTransmits); 4693 } 4694 4695 final NeighborSolicitation ns = 4696 expectDadNeighborSolicitationForLinkLocal(shouldDisableDad); 4697 if (shouldDisableDad) { 4698 assertNull(ns); 4699 } else { 4700 assertNotNull(ns); 4701 } 4702 4703 // Shutdown IpClient and check if the dad_transmits always equals to default value 1 (if 4704 // dad_transmit was set to 0 before, it should get recovered to default value 1 after 4705 // shutting down IpClient) 4706 mIpc.shutdown(); 4707 awaitIpClientShutdown(); 4708 dadTransmits = Integer.parseUnsignedInt( 4709 mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits")); 4710 assertEquals(1, dadTransmits); 4711 } 4712 4713 @Test 4714 @SignatureRequiredTest(reason = "requires mocked netd") 4715 public void testIPv6LinkLocalOnly_enableDad() throws Exception { 4716 runIpv6LinkLocalOnlyDadTransmitsCheckTest(false /* shouldDisableDad */); 4717 } 4718 4719 @Test 4720 @SignatureRequiredTest(reason = "requires mocked netd") 4721 public void testIPv6LinkLocalOnly_disableDad() throws Exception { 4722 runIpv6LinkLocalOnlyDadTransmitsCheckTest(true /* shouldDisableDad */); 4723 } 4724 4725 // Since createTapInterface(boolean, String) method was introduced since T, this method 4726 // cannot be found on Q/R/S platform, ignore this test on T- platform. 4727 @Test 4728 @IgnoreUpTo(Build.VERSION_CODES.S_V2) 4729 public void testIpClientLinkObserver_onClatInterfaceStateUpdate() throws Exception { 4730 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4731 .withoutIPv4() 4732 .build(); 4733 startIpClientProvisioning(config); 4734 doIpv6OnlyProvisioning(); 4735 4736 reset(mCb); 4737 4738 // Add the clat interface and check the callback. 4739 final TestNetworkInterface clatIface = setUpClatInterface(mIfaceName); 4740 assertNotNull(clatIface); 4741 assertTrue(clatIface.getInterfaceName().equals(CLAT_PREFIX + mIfaceName)); 4742 verify(mCb, timeout(TEST_TIMEOUT_MS)).setNeighborDiscoveryOffload(false); 4743 4744 // Remove the clat interface and check the callback. 4745 removeTestInterface(clatIface.getFileDescriptor().getFileDescriptor()); 4746 verify(mCb, timeout(TEST_TIMEOUT_MS)).setNeighborDiscoveryOffload(true); 4747 } 4748 4749 @Test @SignatureRequiredTest(reason = "requires mock callback object") 4750 public void testNetlinkSocketReceiveENOBUFS() throws Exception { 4751 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4752 .withoutIPv4() 4753 .build(); 4754 startIpClientProvisioning(config); 4755 doIpv6OnlyProvisioning(); 4756 HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); 4757 4758 final Handler handler = mIpc.getHandler(); 4759 // Block IpClient handler. 4760 final CountDownLatch latch = new CountDownLatch(1); 4761 handler.post(() -> { 4762 try { 4763 latch.await(10, TimeUnit.SECONDS); 4764 } catch (InterruptedException e) { 4765 fail("latch wait unexpectedly interrupted"); 4766 } 4767 }); 4768 4769 // Send large amount of RAs to overflow the netlink socket receive buffer. 4770 for (int i = 0; i < 200; i++) { 4771 sendBasicRouterAdvertisement(false /* waitRs */); 4772 } 4773 4774 // Send another RA with a different IPv6 global prefix. This PIO option should be dropped 4775 // due to the ENOBUFS happens, it means IpClient shouldn't see the new IPv6 global prefix. 4776 final String prefix = "2001:db8:dead:beef::/64"; 4777 final ByteBuffer pio = buildPioOption(3600, 1800, prefix); 4778 ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); 4779 sendRouterAdvertisement(false /* waitForRs */, (short) 1800, pio, rdnss); 4780 4781 // Unblock the IpClient handler and ENOBUFS should happen then. 4782 latch.countDown(); 4783 HandlerUtils.waitForIdle(handler, TEST_WAIT_ENOBUFS_TIMEOUT_MS); 4784 4785 reset(mCb); 4786 4787 // Send RA with 0 router lifetime to see if IpClient can see the loss of IPv6 default route. 4788 // Due to ignoring the ENOBUFS and wait until handler gets idle, IpClient should be still 4789 // able to see the RA with 0 router lifetime and the IPv6 default route will be removed. 4790 // LinkProperties should not include any route to the new prefix 2001:db8:dead:beef::/64. 4791 sendRouterAdvertisementWithZeroRouterLifetime(); 4792 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 4793 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); 4794 final LinkProperties lp = captor.getValue(); 4795 assertNotNull(lp); 4796 assertFalse(hasRouteTo(lp, prefix)); 4797 assertFalse(lp.hasIpv6DefaultRoute()); 4798 } 4799 4800 @Test 4801 public void testMulticastNsFromIPv6Gua() throws Exception { 4802 final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4803 .withoutIpReachabilityMonitor() 4804 .withoutIPv4() 4805 .build(); 4806 4807 startIpClientProvisioning(config); 4808 4809 doIpv6OnlyProvisioning(); 4810 4811 final List<NeighborSolicitation> nsList = new ArrayList<>(); 4812 NeighborSolicitation packet; 4813 while ((packet = getNextNeighborSolicitation()) != null) { 4814 // Filter out the NSes used for duplicate address detetction, whose target address 4815 // is the global IPv6 address inside these NSes. 4816 if (packet.nsHdr.target.isLinkLocalAddress()) { 4817 assertMulticastNsFromIpv6Gua(packet); 4818 nsList.add(packet); 4819 } 4820 } 4821 assertEquals(2, nsList.size()); // from privacy address and stable privacy address 4822 } 4823 4824 @Test 4825 public void testDeprecatedGlobalUnicastAddress() throws Exception { 4826 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4827 .withoutIPv4() 4828 .build(); 4829 startIpClientProvisioning(config); 4830 doIpv6OnlyProvisioning(); 4831 4832 // Send RA with PIO(0 preferred but valid lifetime) to deprecate the global IPv6 addresses. 4833 // Check all of global IPv6 addresses will become deprecated, but still valid. 4834 // NetworkStackUtils#isIPv6GUA() will return false for deprecated addresses, however, when 4835 // checking if the DNS is still reachable, deprecated addresses are not acceptable, that 4836 // results in the on-link DNS server gets lost from LinkProperties, and provisioning failure 4837 // happened. 4838 // TODO: update the logic of checking reachable on-link DNS server to accept the deprecated 4839 // addresses, then onProvisioningFailure callback should never happen. 4840 sendRouterAdvertisement(false /* waitForRs*/, (short) 1800 /* router lifetime */, 4841 3600 /* valid */, 0 /* preferred */); 4842 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 4843 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); 4844 final LinkProperties lp = captor.getValue(); 4845 assertNotNull(lp); 4846 assertFalse(lp.hasGlobalIpv6Address()); 4847 assertEquals(3, lp.getLinkAddresses().size()); // IPv6 privacy, stable privacy, link-local 4848 for (LinkAddress la : lp.getLinkAddresses()) { 4849 assertFalse(NetworkStackUtils.isIPv6GUA(la)); 4850 } 4851 } 4852 4853 @Test @SignatureRequiredTest(reason = "requires mNetd to delete IPv6 GUAs") 4854 public void testOnIpv6AddressRemoved() throws Exception { 4855 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4856 .withoutIPv4() 4857 .build(); 4858 startIpClientProvisioning(config); 4859 4860 LinkProperties lp = doIpv6OnlyProvisioning(); 4861 assertNotNull(lp); 4862 assertEquals(3, lp.getLinkAddresses().size()); // IPv6 privacy, stable privacy, link-local 4863 for (LinkAddress la : lp.getLinkAddresses()) { 4864 final Inet6Address address = (Inet6Address) la.getAddress(); 4865 if (address.isLinkLocalAddress()) continue; 4866 // Remove IPv6 GUAs from interface. 4867 mNetd.interfaceDelAddress(mIfaceName, address.getHostAddress(), la.getPrefixLength()); 4868 } 4869 4870 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 4871 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); 4872 lp = captor.getValue(); 4873 assertFalse(lp.hasGlobalIpv6Address()); 4874 assertEquals(1, lp.getLinkAddresses().size()); // only link-local 4875 } 4876 4877 @Test 4878 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) 4879 public void testMaxDtimMultiplier_IPv6OnlyNetwork() throws Exception { 4880 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4881 .withoutIPv4() 4882 .build(); 4883 startIpClientProvisioning(config); 4884 4885 verify(mCb, timeout(TEST_TIMEOUT_MS)).setMaxDtimMultiplier( 4886 IpClient.DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER); 4887 4888 LinkProperties lp = doIpv6OnlyProvisioning(); 4889 assertNotNull(lp); 4890 assertEquals(3, lp.getLinkAddresses().size()); // IPv6 privacy, stable privacy, link-local 4891 verify(mCb, timeout(TEST_TIMEOUT_MS)).setMaxDtimMultiplier( 4892 IpClient.DEFAULT_IPV6_ONLY_NETWORK_MAX_DTIM_MULTIPLIER); 4893 } 4894 4895 @Test 4896 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) 4897 public void testMaxDtimMultiplier_IPv6LinkLocalOnlyMode() throws Exception { 4898 final InOrder inOrder = inOrder(mCb); 4899 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 4900 .withoutIPv4() 4901 .withIpv6LinkLocalOnly() 4902 .build(); 4903 startIpClientProvisioning(config); 4904 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); 4905 // IPv6 DTIM grace period doesn't apply to IPv6 link-local only mode and the multiplier 4906 // has been initialized to DTIM_MULTIPLIER_RESET before starting provisioning, therefore, 4907 // the multiplier should not be updated neither. 4908 verify(mCb, never()).setMaxDtimMultiplier( 4909 IpClient.DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER); 4910 verify(mCb, never()).setMaxDtimMultiplier(DTIM_MULTIPLIER_RESET); 4911 } 4912 4913 @Test 4914 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) 4915 public void testMaxDtimMultiplier_IPv4OnlyNetwork() throws Exception { 4916 performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 4917 false /* shouldReplyRapidCommitAck */, 4918 TEST_DEFAULT_MTU, false /* isDhcpIpConflictDetectEnabled */); 4919 verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR)); 4920 verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setMaxDtimMultiplier( 4921 IpClient.DEFAULT_IPV4_ONLY_NETWORK_MAX_DTIM_MULTIPLIER); 4922 // IPv6 DTIM grace period doesn't apply to IPv4-only networks. 4923 verify(mCb, never()).setMaxDtimMultiplier( 4924 IpClient.DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER); 4925 } 4926 4927 private void runDualStackNetworkDtimMultiplierSetting(final InOrder inOrder) throws Exception { 4928 doDualStackProvisioning(); 4929 inOrder.verify(mCb).setMaxDtimMultiplier( 4930 IpClient.DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER); 4931 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).setMaxDtimMultiplier( 4932 IpClient.DEFAULT_DUAL_STACK_MAX_DTIM_MULTIPLIER); 4933 } 4934 4935 @Test 4936 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) 4937 public void testMaxDtimMultiplier_DualStackNetwork() throws Exception { 4938 final InOrder inOrder = inOrder(mCb); 4939 runDualStackNetworkDtimMultiplierSetting(inOrder); 4940 } 4941 4942 @Test 4943 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) 4944 public void testMaxDtimMultiplier_MulticastLock() throws Exception { 4945 final InOrder inOrder = inOrder(mCb); 4946 runDualStackNetworkDtimMultiplierSetting(inOrder); 4947 4948 // Simulate to hold the multicast lock by disabling the multicast filter. 4949 mIIpClient.setMulticastFilter(false); 4950 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).setMaxDtimMultiplier( 4951 IpClient.DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER); 4952 4953 // Simulate to disable the multicast lock again, then check the multiplier should be 4954 // changed to 2 (dual-stack setting) 4955 mIIpClient.setMulticastFilter(true); 4956 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).setMaxDtimMultiplier( 4957 IpClient.DEFAULT_DUAL_STACK_MAX_DTIM_MULTIPLIER); 4958 } 4959 4960 @Test 4961 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) 4962 public void testMaxDtimMultiplier_MulticastLockEnabled_StoppedState() throws Exception { 4963 // Simulate to hold the multicast lock by disabling the multicast filter at StoppedState, 4964 // verify no callback to be sent, start dual-stack provisioning and verify the multiplier 4965 // to be set to 1 (multicast lock setting) later. 4966 mIIpClient.setMulticastFilter(false); 4967 verify(mCb, after(10).never()).setMaxDtimMultiplier( 4968 IpClient.DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER); 4969 4970 doDualStackProvisioning(); 4971 verify(mCb, times(1)).setMaxDtimMultiplier( 4972 IpClient.DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER); 4973 } 4974 4975 @Test 4976 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) 4977 public void testMaxDtimMultiplier_resetMultiplier() throws Exception { 4978 final InOrder inOrder = inOrder(mCb); 4979 runDualStackNetworkDtimMultiplierSetting(inOrder); 4980 4981 verify(mCb, never()).setMaxDtimMultiplier(DTIM_MULTIPLIER_RESET); 4982 4983 // Stop IpClient and verify if the multiplier has been reset. 4984 mIIpClient.stop(); 4985 inOrder.verify(mCb, timeout(TEST_TIMEOUT_MS)).setMaxDtimMultiplier(DTIM_MULTIPLIER_RESET); 4986 } 4987 4988 private IaPrefixOption buildIaPrefixOption(final IpPrefix prefix, int preferred, 4989 int valid) { 4990 return new IaPrefixOption((short) IaPrefixOption.LENGTH, preferred, valid, 4991 (byte) prefix.getPrefixLength(), prefix.getRawAddress() /* prefix */); 4992 } 4993 4994 private void handleDhcp6Packets(final IpPrefix prefix, boolean shouldReplyRapidCommit) 4995 throws Exception { 4996 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 4500 /* preferred */, 4997 7200 /* valid */); 4998 handleDhcp6Packets(Collections.singletonList(ipo), 3600 /* t1 */, 4500 /* t2 */, 4999 shouldReplyRapidCommit); 5000 } 5001 5002 private void handleDhcp6Packets(final List<IaPrefixOption> ipos, int t1, int t2, 5003 boolean shouldReplyRapidCommit) throws Exception { 5004 ByteBuffer iapd; 5005 Dhcp6Packet packet; 5006 while ((packet = getNextDhcp6Packet()) != null) { 5007 final PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), t1, t2, ipos); 5008 iapd = pd.build(); 5009 if (packet instanceof Dhcp6SolicitPacket) { 5010 if (shouldReplyRapidCommit) { 5011 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5012 (Inet6Address) mClientIpAddress, true /* rapidCommit */)); 5013 } else { 5014 mPacketReader.sendResponse(buildDhcp6Advertise(packet, iapd.array(), mClientMac, 5015 (Inet6Address) mClientIpAddress)); 5016 } 5017 } else if (packet instanceof Dhcp6RequestPacket) { 5018 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5019 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5020 } else { 5021 fail("invalid DHCPv6 Packet"); 5022 } 5023 5024 if ((packet instanceof Dhcp6RequestPacket) || shouldReplyRapidCommit) { 5025 return; 5026 } 5027 } 5028 fail("No DHCPv6 packet received on interface within timeout"); 5029 } 5030 5031 private void prepareDhcp6PdTest() throws Exception { 5032 final String dnsServer = "2001:4860:4860::64"; 5033 final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer); 5034 final ByteBuffer ra = buildRaPacket(rdnss); 5035 5036 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 5037 .withoutIPv4() 5038 .build(); 5039 startIpClientProvisioning(config); 5040 5041 waitForRouterSolicitation(); 5042 mPacketReader.sendResponse(ra); 5043 } 5044 5045 @Test 5046 @Flag(name = IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION, enabled = true) 5047 public void testDhcp6Pd() throws Exception { 5048 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5049 prepareDhcp6PdTest(); 5050 handleDhcp6Packets(prefix, true /* shouldReplyRapidCommit */); 5051 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5052 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5053 final LinkProperties lp = captor.getValue(); 5054 assertTrue(hasIpv6AddressPrefixedWith(lp, prefix)); 5055 5056 final long now = SystemClock.elapsedRealtime(); 5057 long when = 0; 5058 for (LinkAddress la : lp.getLinkAddresses()) { 5059 if (la.getAddress().isLinkLocalAddress()) { 5060 assertLinkAddressPermanentLifetime(la); 5061 } else if (la.isGlobalPreferred()) { 5062 when = now + 4500 * 1000; // preferred=4500s 5063 assertLinkAddressDeprecationTime(la, when); 5064 when = now + 7200 * 1000; // valid=7200s 5065 assertLinkAddressExpirationTime(la, when); 5066 } 5067 } 5068 } 5069 5070 @Test 5071 public void testDhcp6Pd_disableRapidCommit() throws Exception { 5072 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5073 prepareDhcp6PdTest(); 5074 handleDhcp6Packets(prefix, false /* shouldReplyRapidCommit */); 5075 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5076 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5077 assertTrue(hasIpv6AddressPrefixedWith(captor.getValue(), prefix)); 5078 } 5079 5080 @Test 5081 public void testDhcp6Pd_longPrefixLength() throws Exception { 5082 prepareDhcp6PdTest(); 5083 final IpPrefix prefix = new IpPrefix("2001:db8:1::/80"); 5084 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 3600 /* preferred */, 5085 4000 /* valid */); 5086 handleDhcp6Packets(Collections.singletonList(ipo), 3600 /* t1 */, 4500 /* t2 */, 5087 true /* shouldReplyRapidCommit */); 5088 verify(mCb, never()).onProvisioningSuccess(any()); 5089 } 5090 5091 @Test 5092 public void testDhcp6Pd_shortPrefixLength() throws Exception { 5093 final IpPrefix prefix = new IpPrefix("2001:db8:1::/56"); 5094 prepareDhcp6PdTest(); 5095 handleDhcp6Packets(prefix, true /* shouldReplyRapidCommit */); 5096 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5097 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5098 assertTrue(hasIpv6AddressPrefixedWith(captor.getValue(), prefix)); 5099 } 5100 5101 @Test 5102 public void testDhcp6Pd_T1GreaterThanT2() throws Exception { 5103 prepareDhcp6PdTest(); 5104 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5105 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 3600 /* preferred */, 5106 4000 /* valid */); 5107 handleDhcp6Packets(Collections.singletonList(ipo), 4500 /* t1 */, 3600 /* t2 */, 5108 true /* shouldReplyRapidCommit */); 5109 verify(mCb, never()).onProvisioningSuccess(any()); 5110 } 5111 5112 @Test 5113 public void testDhcp6Pd_preferredLifetimeGreaterThanValidLifetime() throws Exception { 5114 prepareDhcp6PdTest(); 5115 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5116 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 7200 /* preferred */, 5117 4500 /* valid */); 5118 handleDhcp6Packets(Collections.singletonList(ipo), 3600 /* t1 */, 4500 /* t2 */, 5119 true /* shouldReplyRapidCommit */); 5120 verify(mCb, never()).onProvisioningSuccess(any()); 5121 } 5122 5123 @Test 5124 public void testDhcp6Pd_preferredLifetimeLessThanT2() throws Exception { 5125 prepareDhcp6PdTest(); 5126 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5127 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 3600 /* preferred */, 5128 4000 /* valid */); 5129 handleDhcp6Packets(Collections.singletonList(ipo), 3600 /* t1 */, 4500 /* t2 */, 5130 true /* shouldReplyRapidCommit */); 5131 verify(mCb, never()).onProvisioningSuccess(any()); 5132 } 5133 5134 private void runDhcp6PdNotStartInDualStackTest(final String prefix, final String dnsServer) 5135 throws Exception { 5136 final List<ByteBuffer> options = new ArrayList<>(); 5137 if (prefix != null) { 5138 options.add(buildPioOption(3600, 1800, prefix)); 5139 } 5140 if (dnsServer != null) { 5141 options.add(buildRdnssOption(3600, dnsServer)); 5142 } 5143 options.add(buildSllaOption()); 5144 final ByteBuffer ra = buildRaPacket(options.toArray(new ByteBuffer[options.size()])); 5145 5146 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 5147 .build(); 5148 setDhcpFeatures(true /* isRapidCommitEnabled */, 5149 false /* isDhcpIpConflictDetectEnabled */); 5150 startIpClientProvisioning(config); 5151 5152 waitForRouterSolicitation(); 5153 mPacketReader.sendResponse(ra); 5154 5155 // Start IPv4 provisioning and wait until entire provisioning completes. 5156 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 5157 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */); 5158 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); 5159 } 5160 5161 @Test 5162 public void testDhcp6Pd_notStartWithGlobalPio() throws Exception { 5163 runDhcp6PdNotStartInDualStackTest("2001:db8:1::/64" /* prefix */, 5164 "2001:4860:4860::64" /* dnsServer */); 5165 // Reply with a normal RA with global prefix and an off-link DNS for IPv6 provisioning, 5166 // DHCPv6 prefix delegation should not start. 5167 assertNull(getNextDhcp6Packet(PACKET_TIMEOUT_MS)); 5168 } 5169 5170 @Test 5171 public void testDhcp6Pd_notStartWithUlaPioAndDns() throws Exception { 5172 runDhcp6PdNotStartInDualStackTest("fd7c:9df8:7f39:dc89::/64" /* prefix */, 5173 "fd7c:9df8:7f39:dc89::1" /* dnsServer */); 5174 // Reply with a normal RA even with ULA prefix and on-link ULA DNS for IPv6 provisioning, 5175 // DHCPv6 prefix delegation should not start. 5176 assertNull(getNextDhcp6Packet(PACKET_TIMEOUT_MS)); 5177 } 5178 5179 @Test 5180 public void testDhcp6Pd_notStartWithUlaPioAndOffLinkDns() throws Exception { 5181 runDhcp6PdNotStartInDualStackTest("fd7c:9df8:7f39:dc89::/64" /* prefix */, 5182 "2001:4860:4860::64" /* dnsServer */); 5183 // Reply with a normal RA even with ULA prefix and off-link DNS for IPv6 provisioning, 5184 // DHCPv6 prefix delegation should not start. 5185 assertNull(getNextDhcp6Packet(PACKET_TIMEOUT_MS)); 5186 } 5187 5188 @Test 5189 public void testDhcp6Pd_startWithNoNonIpv6LinkLocalAddresses() throws Exception { 5190 runDhcp6PdNotStartInDualStackTest(null /* prefix */, 5191 "2001:4860:4860::64" /* dnsServer */); 5192 // Reply with a normal RA with only RDNSS but no PIO for IPv6 provisioning, 5193 // DHCPv6 prefix delegation should start. 5194 final Dhcp6Packet packet = getNextDhcp6Packet(PACKET_TIMEOUT_MS); 5195 assertTrue(packet instanceof Dhcp6SolicitPacket); 5196 } 5197 5198 @Test 5199 public void testDhcp6Pd_dualstack() throws Exception { 5200 final String dnsServer = "2001:4860:4860::64"; 5201 final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer); 5202 final ByteBuffer ra = buildRaPacket(rdnss); 5203 5204 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 5205 .build(); 5206 setDhcpFeatures(true /* isRapidCommitEnabled */, 5207 false /* isDhcpIpConflictDetectEnabled */); 5208 startIpClientProvisioning(config); 5209 5210 waitForRouterSolicitation(); 5211 mPacketReader.sendResponse(ra); 5212 5213 // Start IPv4 provisioning and wait until entire provisioning completes. 5214 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 5215 true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */); 5216 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); 5217 5218 // Start DHCPv6 Prefix Delegation. 5219 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5220 handleDhcp6Packets(prefix, false /* shouldReplyRapidCommit */); 5221 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat( 5222 x -> x.isIpv6Provisioned() 5223 && hasIpv6AddressPrefixedWith(x, prefix) 5224 && hasRouteTo(x, "2001:db8:1::/64", RTN_UNREACHABLE) 5225 // IPv4 address, IPv6 link-local, two global delegated IPv6 addresses 5226 && x.getLinkAddresses().size() == 4 5227 )); 5228 } 5229 5230 @Test 5231 public void testDhcp6Pd_multiplePrefixesWithInvalidPrefix() throws Exception { 5232 final IpPrefix valid = new IpPrefix("2001:db8:1::/64"); 5233 final IpPrefix invalid = new IpPrefix("2001:db8:2::/64"); // preferred lft > valid lft 5234 final IaPrefixOption validIpo = buildIaPrefixOption(valid, 4500 /* preferred */, 5235 7200 /* valid */); 5236 final IaPrefixOption invalidIpo = buildIaPrefixOption(invalid, 4500 /* preferred */, 5237 3000 /* valid */); 5238 5239 prepareDhcp6PdTest(); 5240 handleDhcp6Packets(Arrays.asList(invalidIpo, validIpo), 3600 /* t1 */, 4500 /* t2 */, 5241 true /* shouldReplyRapidCommit */); 5242 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5243 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5244 final LinkProperties lp = captor.getValue(); 5245 assertTrue(hasIpv6AddressPrefixedWith(lp, valid)); 5246 assertFalse(hasIpv6AddressPrefixedWith(lp, invalid)); 5247 } 5248 5249 @Test 5250 public void testDhcp6Pd_multiplePrefixesWithPrefixValidLifetimeOfZero() throws Exception { 5251 final IpPrefix valid = new IpPrefix("2001:db8:1::/64"); 5252 final IpPrefix invalid = new IpPrefix("2001:db8:2::/64"); // preferred/valid lft 0 5253 final IaPrefixOption validIpo = buildIaPrefixOption(valid, 4500 /* preferred */, 5254 7200 /* valid */); 5255 final IaPrefixOption invalidIpo = buildIaPrefixOption(invalid, 0 /* preferred */, 5256 0 /* valid */); 5257 5258 prepareDhcp6PdTest(); 5259 handleDhcp6Packets(Arrays.asList(invalidIpo, validIpo), 3600 /* t1 */, 4500 /* t2 */, 5260 true /* shouldReplyRapidCommit */); 5261 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5262 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5263 final LinkProperties lp = captor.getValue(); 5264 assertTrue(hasIpv6AddressPrefixedWith(lp, valid)); 5265 assertFalse(hasIpv6AddressPrefixedWith(lp, invalid)); 5266 } 5267 5268 private void prepareDhcp6PdRenewTest() throws Exception { 5269 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5270 prepareDhcp6PdTest(); 5271 handleDhcp6Packets(prefix, true /* shouldReplyRapidCommit */); 5272 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5273 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5274 assertTrue(hasIpv6AddressPrefixedWith(captor.getValue(), prefix)); 5275 } 5276 5277 @Test 5278 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5279 public void testDhcp6Pd_renewAndRebind() throws Exception { 5280 prepareDhcp6PdRenewTest(); 5281 5282 final InOrder inOrder = inOrder(mAlarm); 5283 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5284 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5285 final OnAlarmListener rebindAlarm = expectAlarmSet(inOrder, "REBIND", 4500, handler); 5286 5287 handler.post(() -> renewAlarm.onAlarm()); 5288 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5289 5290 Dhcp6Packet packet = getNextDhcp6Packet(); 5291 assertTrue(packet instanceof Dhcp6RenewPacket); 5292 5293 handler.post(() -> rebindAlarm.onAlarm()); 5294 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5295 5296 packet = getNextDhcp6Packet(); 5297 assertTrue(packet instanceof Dhcp6RebindPacket); 5298 } 5299 5300 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5301 @Test 5302 public void testDhcp6Pd_prefixMismatchOnRenew_newPrefix() throws Exception { 5303 prepareDhcp6PdRenewTest(); 5304 5305 final InOrder inOrder = inOrder(mAlarm); 5306 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5307 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5308 5309 handler.post(() -> renewAlarm.onAlarm()); 5310 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5311 5312 Dhcp6Packet packet = getNextDhcp6Packet(); 5313 assertTrue(packet instanceof Dhcp6RenewPacket); 5314 5315 // Reply with a new prefix apart of the requested one, per RFC8415#section-18.2.10.1 5316 // any new prefix should be added. 5317 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5318 final IpPrefix prefix1 = new IpPrefix("2001:db8:2::/64"); 5319 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 4500 /* preferred */, 5320 7200 /* valid */); 5321 final IaPrefixOption ipo1 = buildIaPrefixOption(prefix1, 5000 /* preferred */, 5322 6000 /* valid */); 5323 final PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 3600 /* t1 */, 5324 4500 /* t2 */, Arrays.asList(ipo, ipo1)); 5325 final ByteBuffer iapd = pd.build(); 5326 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5327 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5328 verify(mCb, never()).onProvisioningFailure(any()); 5329 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat( 5330 x -> x.isIpv6Provisioned() 5331 && hasIpv6AddressPrefixedWith(x, prefix) 5332 && hasIpv6AddressPrefixedWith(x, prefix1) 5333 && hasRouteTo(x, "2001:db8:1::/64", RTN_UNREACHABLE) 5334 && hasRouteTo(x, "2001:db8:2::/64", RTN_UNREACHABLE) 5335 // IPv6 link-local, four global delegated IPv6 addresses 5336 && x.getLinkAddresses().size() == 5 5337 )); 5338 } 5339 5340 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5341 @Test 5342 public void testDhcp6Pd_prefixMismatchOnRenew_requestedPrefixAbsent() throws Exception { 5343 prepareDhcp6PdRenewTest(); 5344 5345 final InOrder inOrder = inOrder(mAlarm); 5346 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5347 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5348 5349 handler.post(() -> renewAlarm.onAlarm()); 5350 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5351 5352 Dhcp6Packet packet = getNextDhcp6Packet(); 5353 assertTrue(packet instanceof Dhcp6RenewPacket); 5354 5355 // Reply with a new prefix but the requested one is absent, per RFC8415#section-18.2.10.1 5356 // the new prefix should be added and the absent prefix will expire in nature. 5357 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5358 final IpPrefix prefix1 = new IpPrefix("2001:db8:2::/64"); 5359 final IaPrefixOption ipo = buildIaPrefixOption(prefix1, 4500 /* preferred */, 5360 7200 /* valid */); 5361 final PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 3600 /* t1 */, 5362 4500 /* t2 */, Arrays.asList(ipo)); 5363 final ByteBuffer iapd = pd.build(); 5364 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5365 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5366 verify(mCb, never()).onProvisioningFailure(any()); 5367 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat( 5368 x -> x.isIpv6Provisioned() 5369 && hasIpv6AddressPrefixedWith(x, prefix) 5370 && hasIpv6AddressPrefixedWith(x, prefix1) 5371 && hasRouteTo(x, "2001:db8:1::/64", RTN_UNREACHABLE) 5372 && hasRouteTo(x, "2001:db8:2::/64", RTN_UNREACHABLE) 5373 // IPv6 link-local, four global delegated IPv6 addresses 5374 && x.getLinkAddresses().size() == 5 5375 )); 5376 } 5377 5378 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5379 @Test 5380 public void testDhcp6Pd_prefixMismatchOnRenew_allPrefixesAbsent() throws Exception { 5381 prepareDhcp6PdRenewTest(); 5382 5383 final InOrder inOrder = inOrder(mAlarm); 5384 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5385 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5386 5387 handler.post(() -> renewAlarm.onAlarm()); 5388 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5389 5390 Dhcp6Packet packet = getNextDhcp6Packet(); 5391 assertTrue(packet instanceof Dhcp6RenewPacket); 5392 5393 clearInvocations(mCb); 5394 5395 // Reply with IA_PD but IA_Prefix is absent, client should still stay at the RenewState 5396 // and restransmit the Renew message, that should not result in any LinkProperties update. 5397 final PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 3600 /* t1 */, 5398 4500 /* t2 */, new ArrayList<IaPrefixOption>(0)); 5399 final ByteBuffer iapd = pd.build(); 5400 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5401 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5402 verify(mCb, never()).onLinkPropertiesChange(any()); 5403 } 5404 5405 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5406 @Test 5407 public void testDhcp6Pd_renewInvalidPrefixes_zeroPreferredAndValidLifetime() throws Exception { 5408 prepareDhcp6PdRenewTest(); 5409 5410 final InOrder inOrder = inOrder(mAlarm); 5411 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5412 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5413 5414 handler.post(() -> renewAlarm.onAlarm()); 5415 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5416 5417 Dhcp6Packet packet = getNextDhcp6Packet(); 5418 assertTrue(packet instanceof Dhcp6RenewPacket); 5419 5420 // Reply with the requested prefix with preferred/valid lifetime of 0. 5421 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5422 final IpPrefix prefix1 = new IpPrefix("2001:db8:2::/64"); 5423 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 0 /* preferred */, 5424 0 /* valid */); 5425 final IaPrefixOption ipo1 = buildIaPrefixOption(prefix1, 5000 /* preferred */, 5426 6000 /* valid */); 5427 final PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 3600 /* t1 */, 5428 4500 /* t2 */, Arrays.asList(ipo, ipo1)); 5429 final ByteBuffer iapd = pd.build(); 5430 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5431 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5432 verify(mCb, never()).onProvisioningFailure(any()); 5433 // IPv6 addresses derived from prefix with 0 preferred/valid lifetime should be deleted. 5434 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat( 5435 x -> x.isIpv6Provisioned() 5436 && !hasIpv6AddressPrefixedWith(x, prefix) 5437 && hasIpv6AddressPrefixedWith(x, prefix1) 5438 && !hasRouteTo(x, "2001:db8:1::/64", RTN_UNREACHABLE) 5439 && hasRouteTo(x, "2001:db8:2::/64", RTN_UNREACHABLE) 5440 // IPv6 link-local, two global delegated IPv6 addresses with prefix1 5441 && x.getLinkAddresses().size() == 3 5442 )); 5443 5444 handler.post(() -> renewAlarm.onAlarm()); 5445 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5446 5447 packet = getNextDhcp6Packet(); 5448 assertTrue(packet instanceof Dhcp6RenewPacket); 5449 final List<IaPrefixOption> renewIpos = packet.getPrefixDelegation().ipos; 5450 assertEquals(1, renewIpos.size()); // don't renew prefix 2001:db8:1::/64 with 0 5451 // preferred/valid lifetime 5452 assertEquals(prefix1, renewIpos.get(0).getIpPrefix()); 5453 } 5454 5455 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5456 @Test 5457 public void testDhcp6Pd_renewInvalidPrefixes_theSameT1T2ValidLifetime() throws Exception { 5458 prepareDhcp6PdRenewTest(); 5459 5460 final InOrder inOrder = inOrder(mAlarm); 5461 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5462 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5463 5464 handler.post(() -> renewAlarm.onAlarm()); 5465 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5466 5467 Dhcp6Packet packet = getNextDhcp6Packet(); 5468 assertTrue(packet instanceof Dhcp6RenewPacket); 5469 5470 clearInvocations(mCb); 5471 5472 // Reply with the requested prefix with the same t1/t2/lifetime. 5473 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5474 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 3600 /* preferred */, 5475 3600 /* valid */); 5476 final PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 3600 /* t1 */, 5477 3600 /* t2 */, Collections.singletonList(ipo)); 5478 final ByteBuffer iapd = pd.build(); 5479 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5480 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5481 // The prefix doesn't change only the lifetime is updated, therefore, LinkProperties update 5482 // isn't expected. 5483 verify(mCb, never()).onProvisioningFailure(any()); 5484 verify(mCb, never()).onLinkPropertiesChange(any()); 5485 5486 handler.post(() -> renewAlarm.onAlarm()); 5487 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5488 5489 packet = getNextDhcp6Packet(TEST_TIMEOUT_MS); 5490 assertNull(packet); 5491 } 5492 5493 @Test 5494 public void testDhcp6Pd_multipleIaPrefixOptions() throws Exception { 5495 final InOrder inOrder = inOrder(mCb); 5496 final IpPrefix prefix1 = new IpPrefix("2001:db8:1::/64"); 5497 final IpPrefix prefix2 = new IpPrefix("2400:db8:100::/64"); 5498 final IpPrefix prefix3 = new IpPrefix("fd7c:9df8:7f39:dc89::/64"); 5499 final IaPrefixOption ipo1 = buildIaPrefixOption(prefix1, 4500 /* preferred */, 5500 7200 /* valid */); 5501 final IaPrefixOption ipo2 = buildIaPrefixOption(prefix2, 5600 /* preferred */, 5502 6000 /* valid */); 5503 final IaPrefixOption ipo3 = buildIaPrefixOption(prefix3, 7200 /* preferred */, 5504 14400 /* valid */); 5505 prepareDhcp6PdTest(); 5506 handleDhcp6Packets(Arrays.asList(ipo1, ipo2, ipo3), 3600 /* t1 */, 4500 /* t2 */, 5507 true /* shouldReplyRapidCommit */); 5508 5509 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5510 verifyWithTimeout(inOrder, mCb).onProvisioningSuccess(captor.capture()); 5511 LinkProperties lp = captor.getValue(); 5512 5513 // Sometimes privacy address or route may appear later along with onLinkPropertiesChange 5514 // callback, in this case we wait a bit longer to see all of these properties appeared and 5515 // then verify if they are what we are looking for. 5516 if (lp.getLinkAddresses().size() < 5) { // 1 IPv6 link-local and 4 global IPv6 addresses 5517 // derived from prefix1 and prefix2 5518 final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>(); 5519 verifyWithTimeout(inOrder, mCb).onLinkPropertiesChange(argThat(x -> { 5520 if (!x.isIpv6Provisioned()) return false; 5521 if (x.getLinkAddresses().size() != 5) return false; 5522 lpFuture.complete(x); 5523 return true; 5524 })); 5525 lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); 5526 } 5527 assertNotNull(lp); 5528 assertTrue(hasIpv6AddressPrefixedWith(lp, prefix1)); 5529 assertTrue(hasIpv6AddressPrefixedWith(lp, prefix2)); 5530 assertFalse(hasIpv6AddressPrefixedWith(lp, prefix3)); 5531 assertTrue(hasRouteTo(lp, prefix1.toString(), RTN_UNREACHABLE)); 5532 assertTrue(hasRouteTo(lp, prefix2.toString(), RTN_UNREACHABLE)); 5533 assertFalse(hasRouteTo(lp, prefix3.toString(), RTN_UNREACHABLE)); 5534 } 5535 5536 private void runDhcp6PacketWithNoPrefixAvailStatusCodeTest(boolean shouldReplyWithAdvertise) 5537 throws Exception { 5538 prepareDhcp6PdTest(); 5539 Dhcp6Packet packet = getNextDhcp6Packet(PACKET_TIMEOUT_MS); 5540 assertTrue(packet instanceof Dhcp6SolicitPacket); 5541 5542 final PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 0 /* t1 */, 0 /* t2 */, 5543 new ArrayList<IaPrefixOption>() /* ipos */, Dhcp6Packet.STATUS_NO_PREFIX_AVAIL); 5544 final ByteBuffer iapd = pd.build(); 5545 if (shouldReplyWithAdvertise) { 5546 mPacketReader.sendResponse(buildDhcp6Advertise(packet, iapd.array(), mClientMac, 5547 (Inet6Address) mClientIpAddress)); 5548 } else { 5549 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5550 (Inet6Address) mClientIpAddress, true /* rapidCommit */)); 5551 } 5552 5553 // Check if client will ignore Advertise or Reply for Rapid Commit Solicit and 5554 // retransmit Solicit. 5555 packet = getNextDhcp6Packet(PACKET_TIMEOUT_MS); 5556 assertTrue(packet instanceof Dhcp6SolicitPacket); 5557 } 5558 5559 @Test 5560 public void testDhcp6AdvertiseWithNoPrefixAvailStatusCode() throws Exception { 5561 // Advertise 5562 runDhcp6PacketWithNoPrefixAvailStatusCodeTest(true /* shouldReplyWithAdvertise */); 5563 } 5564 5565 @Test 5566 public void testDhcp6ReplyForRapidCommitSolicitWithNoPrefixAvailStatusCode() throws Exception { 5567 // Reply 5568 runDhcp6PacketWithNoPrefixAvailStatusCodeTest(false /* shouldReplyWithAdvertise */); 5569 } 5570 5571 @Test 5572 public void testDhcp6ReplyForRequestWithNoPrefixAvailStatusCode() throws Exception { 5573 prepareDhcp6PdTest(); 5574 Dhcp6Packet packet = getNextDhcp6Packet(PACKET_TIMEOUT_MS); 5575 assertTrue(packet instanceof Dhcp6SolicitPacket); 5576 5577 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5578 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 4500 /* preferred */, 5579 7200 /* valid */); 5580 PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 1000 /* t1 */, 5581 2000 /* t2 */, Arrays.asList(ipo)); 5582 ByteBuffer iapd = pd.build(); 5583 mPacketReader.sendResponse(buildDhcp6Advertise(packet, iapd.array(), mClientMac, 5584 (Inet6Address) mClientIpAddress)); 5585 5586 packet = getNextDhcp6Packet(PACKET_TIMEOUT_MS); 5587 assertTrue(packet instanceof Dhcp6RequestPacket); 5588 5589 // Reply for Request with NoPrefixAvail status code. Not sure if this is reasonable in 5590 // practice, but Server can do everything it wants. 5591 pd = new PrefixDelegation(packet.getIaId(), 0 /* t1 */, 0 /* t2 */, 5592 new ArrayList<IaPrefixOption>() /* ipos */, Dhcp6Packet.STATUS_NO_PREFIX_AVAIL); 5593 iapd = pd.build(); 5594 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5595 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5596 5597 // Check if client will ignore Reply for Request with NoPrefixAvail status code, and 5598 // rollback to SolicitState. 5599 packet = getNextDhcp6Packet(PACKET_TIMEOUT_MS); 5600 assertTrue(packet instanceof Dhcp6SolicitPacket); 5601 } 5602 5603 @Test 5604 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5605 public void testDhcp6ReplyForRenewWithNoPrefixAvailStatusCode() throws Exception { 5606 prepareDhcp6PdRenewTest(); 5607 5608 final InOrder inOrder = inOrder(mAlarm); 5609 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5610 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5611 5612 handler.post(() -> renewAlarm.onAlarm()); 5613 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5614 5615 Dhcp6Packet packet = getNextDhcp6Packet(); 5616 assertTrue(packet instanceof Dhcp6RenewPacket); 5617 5618 // Reply with normal IA_PD. 5619 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5620 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 4500 /* preferred */, 5621 7200 /* valid */); 5622 PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 1000 /* t1 */, 5623 2000 /* t2 */, Arrays.asList(ipo)); 5624 ByteBuffer iapd = pd.build(); 5625 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5626 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5627 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5628 5629 // Trigger another Renew message. 5630 handler.post(() -> renewAlarm.onAlarm()); 5631 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5632 5633 packet = getNextDhcp6Packet(); 5634 assertTrue(packet instanceof Dhcp6RenewPacket); 5635 5636 // Reply for Renew with NoPrefixAvail status code, check if client will retransmit the 5637 // Renew message. 5638 pd = new PrefixDelegation(packet.getIaId(), 3600 /* t1 */, 4500 /* t2 */, 5639 new ArrayList<IaPrefixOption>(0) /* ipos */, Dhcp6Packet.STATUS_NO_PREFIX_AVAIL); 5640 iapd = pd.build(); 5641 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5642 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5643 5644 packet = getNextDhcp6Packet(TEST_WAIT_RENEW_REBIND_RETRANSMIT_MS); 5645 assertTrue(packet instanceof Dhcp6RenewPacket); 5646 } 5647 5648 @Test 5649 @SignatureRequiredTest(reason = "Need to mock the DHCP6 renew/rebind alarms") 5650 public void testDhcp6ReplyForRebindWithNoPrefixAvailStatusCode() throws Exception { 5651 prepareDhcp6PdRenewTest(); 5652 5653 final InOrder inOrder = inOrder(mAlarm); 5654 final Handler handler = mDependencies.mDhcp6Client.getHandler(); 5655 final OnAlarmListener renewAlarm = expectAlarmSet(inOrder, "RENEW", 3600, handler); 5656 final OnAlarmListener rebindAlarm = expectAlarmSet(inOrder, "REBIND", 4500, handler); 5657 5658 handler.post(() -> renewAlarm.onAlarm()); 5659 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5660 5661 Dhcp6Packet packet = getNextDhcp6Packet(); 5662 assertTrue(packet instanceof Dhcp6RenewPacket); 5663 5664 handler.post(() -> rebindAlarm.onAlarm()); 5665 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5666 5667 packet = getNextDhcp6Packet(); 5668 assertTrue(packet instanceof Dhcp6RebindPacket); 5669 5670 // Reply with normal IA_PD. 5671 final IpPrefix prefix = new IpPrefix("2001:db8:1::/64"); 5672 final IaPrefixOption ipo = buildIaPrefixOption(prefix, 4500 /* preferred */, 5673 7200 /* valid */); 5674 PrefixDelegation pd = new PrefixDelegation(packet.getIaId(), 1000 /* t1 */, 5675 2000 /* t2 */, Arrays.asList(ipo)); 5676 ByteBuffer iapd = pd.build(); 5677 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5678 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5679 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5680 5681 // Trigger another Rebind message. 5682 handler.post(() -> renewAlarm.onAlarm()); 5683 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5684 5685 packet = getNextDhcp6Packet(); 5686 assertTrue(packet instanceof Dhcp6RenewPacket); 5687 5688 handler.post(() -> rebindAlarm.onAlarm()); 5689 HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); 5690 5691 packet = getNextDhcp6Packet(); 5692 assertTrue(packet instanceof Dhcp6RebindPacket); 5693 5694 // Reply for Rebind with NoPrefixAvail status code, check if client will retransmit the 5695 // Rebind message. 5696 pd = new PrefixDelegation(packet.getIaId(), 3600 /* t1 */, 5697 4500 /* t2 */, new ArrayList<IaPrefixOption>(0) /* ipos */, 5698 Dhcp6Packet.STATUS_NO_PREFIX_AVAIL); 5699 iapd = pd.build(); 5700 mPacketReader.sendResponse(buildDhcp6Reply(packet, iapd.array(), mClientMac, 5701 (Inet6Address) mClientIpAddress, false /* rapidCommit */)); 5702 5703 packet = getNextDhcp6Packet(TEST_WAIT_RENEW_REBIND_RETRANSMIT_MS); 5704 assertTrue(packet instanceof Dhcp6RebindPacket); 5705 } 5706 5707 @Test 5708 @SignatureRequiredTest(reason = "InterfaceParams.getByName requires CAP_NET_ADMIN") 5709 public void testSendRtmDelAddressMethod() throws Exception { 5710 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 5711 .withoutIPv4() 5712 .build(); 5713 startIpClientProvisioning(config); 5714 5715 final LinkProperties lp = doIpv6OnlyProvisioning(); 5716 assertNotNull(lp); 5717 assertEquals(3, lp.getLinkAddresses().size()); // IPv6 privacy, stable privacy, link-local 5718 5719 clearInvocations(mCb); 5720 5721 // Delete all global IPv6 addresses, then that will trigger onProvisioningFailure callback. 5722 final InterfaceParams params = InterfaceParams.getByName(mIfaceName); 5723 for (LinkAddress la : lp.getLinkAddresses()) { 5724 if (la.isGlobalPreferred()) { 5725 NetlinkUtils.sendRtmDelAddressRequest(params.index, (Inet6Address) la.getAddress(), 5726 (short) la.getPrefixLength()); 5727 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat( 5728 x -> !x.getLinkAddresses().contains(la) 5729 )); 5730 } 5731 } 5732 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(any()); 5733 } 5734 5735 @Test 5736 @SignatureRequiredTest(reason = "requires mocked netd to read/write IPv6 sysctl") 5737 public void testIpv6SysctlsRestAfterStoppingIpClient() throws Exception { 5738 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() 5739 .withoutIPv4() 5740 .build(); 5741 // dad_transmits has been set to 0 in disableIpv6ProvisioningDelays, re-enable 5742 // dad_transmits for testing, production code will restore all IPv6 sysctls at 5743 // StoppedState#enter anyway, read this parameter value after IpClient shutdown 5744 // to check if that's default value 1. 5745 mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits", "1"); 5746 startIpClientProvisioning(config); 5747 verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetEnableIPv6(mIfaceName, true); 5748 doIpv6OnlyProvisioning(); 5749 5750 // Shutdown IpClient and check if the IPv6 sysctls: accept_ra, accept_ra_defrtr and 5751 // dad_transmits have been reset to the default values. 5752 mIpc.shutdown(); 5753 awaitIpClientShutdown(); 5754 final int dadTransmits = Integer.parseUnsignedInt( 5755 mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "dad_transmits")); 5756 assertEquals(1, dadTransmits); 5757 final int acceptRa = Integer.parseUnsignedInt( 5758 mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "accept_ra")); 5759 assertEquals(2, acceptRa); 5760 final int acceptRaDefRtr = Integer.parseUnsignedInt( 5761 mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "accept_ra_defrtr")); 5762 assertEquals(1, acceptRaDefRtr); 5763 } 5764 5765 private void runDhcpDomainSearchListOptionTest(final String domainName, 5766 final List<String> domainSearchList, final String expectedDomain) throws Exception { 5767 when(mResources.getBoolean(R.bool.config_dhcp_client_domain_search_list)).thenReturn(true); 5768 final ProvisioningConfiguration cfg = new ProvisioningConfiguration.Builder() 5769 .withoutIpReachabilityMonitor() 5770 .withoutIPv6() 5771 .withCreatorUid(TEST_DEVICE_OWNER_APP_UID) 5772 .build(); 5773 5774 startIpClientProvisioning(cfg); 5775 handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, 5776 false /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, 5777 null /* captivePortalApiUrl */, null /* ipv6OnlyWaitTime */, 5778 domainName, domainSearchList); 5779 5780 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5781 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5782 final LinkProperties lp = captor.getValue(); 5783 assertNotNull(lp); 5784 assertEquals(expectedDomain, lp.getDomains()); 5785 } 5786 5787 @Test 5788 @SignatureRequiredTest(reason = "requires mocked DevicePolicyManager") 5789 public void testDhcpDomainSearchListOption() throws Exception { 5790 final String domainName = "google.com"; 5791 final List<String> searchList = List.of("suffix1.google.com", "suffix2.google.com"); 5792 final String expectedDomain = "google.com suffix1.google.com suffix2.google.com"; 5793 runDhcpDomainSearchListOptionTest(domainName, searchList, expectedDomain); 5794 } 5795 5796 @Test 5797 @SignatureRequiredTest(reason = "requires mocked DevicePolicyManager") 5798 public void testDhcpDomainSearchListOption_invalidSuffix() throws Exception { 5799 final String domainName = "google.com"; 5800 final List<String> searchList = List.of("google com"); 5801 runDhcpDomainSearchListOptionTest(domainName, searchList, domainName /* expectedDomain */); 5802 } 5803 5804 @Test 5805 @SignatureRequiredTest(reason = "requires mocked DevicePolicyManager") 5806 public void testDhcpDomainSearchListOption_onlySearchList() throws Exception { 5807 final List<String> searchList = List.of("google.com", "example.com"); 5808 final String expectedDomain = "google.com example.com"; 5809 runDhcpDomainSearchListOptionTest(null /* domainName */, searchList, 5810 expectedDomain); 5811 } 5812 5813 private void assertLinkAddressDeprecationTime(final LinkAddress la, final long when) { 5814 assertTrue(la.getDeprecationTime() != LinkAddress.LIFETIME_UNKNOWN); 5815 // Allow +/- 2 seconds to prevent flaky tests 5816 assertTrue(la.getDeprecationTime() < when + TEST_LIFETIME_TOLERANCE_MS); 5817 assertTrue(la.getDeprecationTime() > when - TEST_LIFETIME_TOLERANCE_MS); 5818 } 5819 5820 private void assertLinkAddressExpirationTime(final LinkAddress la, final long when) { 5821 assertTrue(la.getExpirationTime() != LinkAddress.LIFETIME_UNKNOWN); 5822 // Allow +/- 2 seconds to prevent flaky tests 5823 assertTrue(la.getExpirationTime() < when + TEST_LIFETIME_TOLERANCE_MS); 5824 assertTrue(la.getExpirationTime() > when - TEST_LIFETIME_TOLERANCE_MS); 5825 } 5826 5827 private void assertLinkAddressPermanentLifetime(final LinkAddress la) { 5828 assertEquals(LinkAddress.LIFETIME_PERMANENT, la.getDeprecationTime()); 5829 assertEquals(LinkAddress.LIFETIME_PERMANENT, la.getExpirationTime()); 5830 } 5831 5832 @Test 5833 @Flag(name = IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION, enabled = true) 5834 public void testPopulateLinkAddressLifetime() throws Exception { 5835 final LinkProperties lp = doDualStackProvisioning(); 5836 final long now = SystemClock.elapsedRealtime(); 5837 long when = 0; 5838 for (LinkAddress la : lp.getLinkAddresses()) { 5839 if (la.isIpv4()) { 5840 when = now + 3600 * 1000; // DHCP lease duration 5841 assertLinkAddressDeprecationTime(la, when); 5842 assertLinkAddressExpirationTime(la, when); 5843 } else if (la.isIpv6() && la.getAddress().isLinkLocalAddress()) { 5844 assertLinkAddressPermanentLifetime(la); 5845 } else if (la.isIpv6() && la.isGlobalPreferred()) { 5846 when = now + 1800 * 1000; // preferred=1800s 5847 assertLinkAddressDeprecationTime(la, when); 5848 when = now + 3600 * 1000; // valid=3600s 5849 assertLinkAddressExpirationTime(la, when); 5850 } 5851 } 5852 } 5853 5854 @Test 5855 @Flag(name = IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION, enabled = true) 5856 public void testPopulateLinkAddressLifetime_infiniteLeaseDuration() throws Exception { 5857 final ProvisioningConfiguration cfg = new ProvisioningConfiguration.Builder() 5858 .withoutIPv6() 5859 .build(); 5860 5861 startIpClientProvisioning(cfg); 5862 handleDhcpPackets(true /* isSuccessLease */, DhcpPacket.INFINITE_LEASE, 5863 false /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, 5864 null /* captivePortalApiUrl */, null /* ipv6OnlyWaitTime */, 5865 null /* domainName */, null /* domainSearchList */); 5866 5867 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5868 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5869 final LinkProperties lp = captor.getValue(); 5870 assertNotNull(lp); 5871 for (LinkAddress la : lp.getLinkAddresses()) { 5872 if (la.isIpv4()) { 5873 assertLinkAddressPermanentLifetime(la); 5874 } 5875 } 5876 } 5877 5878 @Test 5879 @Flag(name = IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION, enabled = true) 5880 public void testPopulateLinkAddressLifetime_minimalLeaseDuration() throws Exception { 5881 final ProvisioningConfiguration cfg = new ProvisioningConfiguration.Builder() 5882 .withoutIPv6() 5883 .build(); 5884 5885 startIpClientProvisioning(cfg); 5886 handleDhcpPackets(true /* isSuccessLease */, 59 /* lease duration */, 5887 false /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, 5888 null /* captivePortalApiUrl */, null /* ipv6OnlyWaitTime */, 5889 null /* domainName */, null /* domainSearchList */); 5890 5891 final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); 5892 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); 5893 final LinkProperties lp = captor.getValue(); 5894 assertNotNull(lp); 5895 for (LinkAddress la : lp.getLinkAddresses()) { 5896 if (la.isIpv4()) { 5897 final long now = SystemClock.elapsedRealtime(); 5898 final long when = now + 60 * 1000; // minimal lease duration 5899 assertLinkAddressDeprecationTime(la, when); 5900 assertLinkAddressExpirationTime(la, when); 5901 } 5902 } 5903 } 5904 5905 @Test 5906 @Flag(name = IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION, enabled = true) 5907 public void testPopulateLinkAddressLifetime_onDhcpRenew() throws Exception { 5908 final ProvisioningConfiguration cfg = new ProvisioningConfiguration.Builder() 5909 .withoutIPv6() 5910 .build(); 5911 setDeviceConfigProperty(CONFIG_MINIMUM_LEASE, 5/* default minimum lease */); 5912 startIpClientProvisioning(cfg); 5913 handleDhcpPackets(true /* isSuccessLease */, 4 /* lease duration */, 5914 false /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, 5915 null /* captivePortalApiUrl */, null /* ipv6OnlyWaitTime */, 5916 null /* domainName */, null /* domainSearchList */); 5917 5918 verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(any()); 5919 5920 // Device sends ARP request for address resolution of default gateway first. 5921 final ArpPacket request = getNextArpPacket(); 5922 assertArpRequest(request, SERVER_ADDR); 5923 sendArpReply(request.senderHwAddress.toByteArray() /* dst */, ROUTER_MAC_BYTES /* srcMac */, 5924 request.senderIp /* target IP */, SERVER_ADDR /* sender IP */); 5925 5926 // Then client sends unicast DHCPREQUEST to extend the IPv4 address lifetime, and we reply 5927 // with DHCPACK to refresh the DHCP lease. 5928 final DhcpPacket packet = getNextDhcpPacket(); 5929 assertTrue(packet instanceof DhcpRequestPacket); 5930 assertDhcpRequestForReacquire(packet); 5931 mPacketReader.sendResponse(buildDhcpAckPacket(packet, CLIENT_ADDR, 5932 TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, 5933 false /* rapidCommit */, null /* captivePortalApiUrl */)); 5934 5935 // Once the IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION flag is enabled, the IP 5936 // lease will be refreshed as well as the link address lifetime by transiting to 5937 // ConfiguringInterfaceState, where IpClient sends a new RTM_NEWADDR message to kernel 5938 // to update the IPv4 address, therefore, we should never see provisioning failure any 5939 // more. 5940 verify(mCb, never()).onProvisioningFailure(any()); 5941 } 5942 5943 private void doDhcpHostnameSettingTest(int hostnameSetting, 5944 boolean isHostnameConfigurationEnabled, boolean expectSendHostname) throws Exception { 5945 final ProvisioningConfiguration cfg = new ProvisioningConfiguration.Builder() 5946 .withoutIPv6() 5947 .withHostnameSetting(hostnameSetting) 5948 .build(); 5949 final String expectedHostname; 5950 final String expectedHostnameAfterTransliteration; 5951 if (mDependencies != null) { 5952 mDependencies.setHostnameConfiguration(isHostnameConfigurationEnabled, 5953 TEST_HOST_NAME); 5954 expectedHostname = TEST_HOST_NAME; 5955 expectedHostnameAfterTransliteration = TEST_HOST_NAME_TRANSLITERATION; 5956 } else { 5957 expectedHostname = Settings.Global.getString( 5958 InstrumentationRegistry.getInstrumentation().getContext().getContentResolver(), 5959 Settings.Global.DEVICE_NAME); 5960 expectedHostnameAfterTransliteration = new HostnameTransliterator() 5961 .transliterate(expectedHostname); 5962 } 5963 startIpClientProvisioning(cfg); 5964 5965 // perform DHCP handshake and capture the packets sent from client such as 5966 // DHCPDISCOVER and DHCPREQUEST. 5967 final List<DhcpPacket> sentPackets = handleDhcpPackets(true /* isSuccessLease */, 5968 DhcpPacket.INFINITE_LEASE, 5969 false /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, 5970 null /* captivePortalApiUrl */, null /* ipv6OnlyWaitTime */, 5971 null /* domainName */, null /* domainSearchList */); 5972 5973 // check if the DHCP packet sent from the client takes a hostname option per different 5974 // configs. Do not consider the null hostname case. 5975 assertHostname(expectSendHostname, expectedHostname, expectedHostnameAfterTransliteration, 5976 sentPackets); 5977 } 5978 5979 @Test 5980 @SignatureRequiredTest(reason = "need to mock setHostnameConfiguration") 5981 public void testHostname_hostnameSettingUnset_enableHostnameConfig() throws Exception { 5982 // If hostname setting is unset but legacy hostname overlay config is enabled, 5983 // we expect that the DHCP packet takes a hostname option. 5984 doDhcpHostnameSettingTest(IIpClient.HOSTNAME_SETTING_UNSET, 5985 true /* isHostnameConfigurationEnabled */, true /* expectSendHostname */); 5986 } 5987 5988 @Test 5989 @SignatureRequiredTest(reason = "need to mock setHostnameConfiguration") 5990 public void testHostname_hostnameSettingUnset_disableHostnameConfig() throws Exception { 5991 // If hostname setting is unset and legacy hostname overlay config is disabled, 5992 // we expect that the DHCP packet doesn't take a hostname option. 5993 doDhcpHostnameSettingTest(IIpClient.HOSTNAME_SETTING_UNSET, 5994 false /* isHostnameConfigurationEnabled */, false /* expectSendHostname */); 5995 } 5996 5997 @Test 5998 public void testHostname_hostnameSettingSend_enableHostnameConfig() throws Exception { 5999 // If hostname setting is set and legacy hostname overlay config is enabled, 6000 // we expect that the DHCP packet takes a hostname option. 6001 doDhcpHostnameSettingTest(IIpClient.HOSTNAME_SETTING_SEND, 6002 true /* isHostnameConfigurationEnabled */, true /* expectSendHostname */); 6003 } 6004 6005 @Test 6006 public void testHostname_hostnameSettingSend_disableHostnameConfig() throws Exception { 6007 // If hostname setting is set and legacy hostname overlay config is disabled, 6008 // we still expect that the DHCP packet takes a hostname option. 6009 doDhcpHostnameSettingTest(IIpClient.HOSTNAME_SETTING_SEND, 6010 false /* isHostnameConfigurationEnabled */, true /* expectSendHostname */); 6011 } 6012 6013 @Test 6014 public void testHostname_hostnameSettingNotSend_enableHostnameConfig() throws Exception { 6015 // If hostname setting is not send and even if legacy hostname overlay config is 6016 // enabled, we expect that the DHCP packet doesn't take a hostname option. 6017 doDhcpHostnameSettingTest(IIpClient.HOSTNAME_SETTING_DO_NOT_SEND, 6018 true /* isHostnameConfigurationEnabled */, false /* expectSendHostname */); 6019 } 6020 6021 @Test 6022 public void testHostname_hostnameSettingNotSend_disableHostnameConfig() throws Exception { 6023 // If hostname setting is not send and even if legacy hostname overlay config is 6024 // disabled, we expect that the DHCP packet doesn't take a hostname option. 6025 doDhcpHostnameSettingTest(IIpClient.HOSTNAME_SETTING_DO_NOT_SEND, 6026 false /* isHostnameConfigurationEnabled */, false /* expectSendHostname */); 6027 } 6028 6029 // Store the network event to database multiple times. 6030 private void storeNudFailureEvents(long when, long expiry, int times, int eventType) { 6031 for (int i = 0; i < times; i++) { 6032 storeNetworkEvent(TEST_CLUSTER, when, expiry, eventType); 6033 when += 60 * 1000; // event interval is 1min 6034 expiry += 60 * 1000; // expiry also delays 1min 6035 } 6036 } 6037 6038 @Test 6039 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = true) 6040 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6041 public void testIgnoreNudFailuresIfTooManyInPastDay() throws Exception { 6042 // // NUD failure event count exceeds daily threshold nor weekly. 6043 final long when = System.currentTimeMillis() - ONE_DAY_IN_MS / 2; // 12h ago 6044 final long expiry = when + ONE_WEEK_IN_MS; 6045 storeNudFailureEvents(when, expiry, 10, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6046 6047 runIpReachabilityMonitorProbeFailedTest(); 6048 assertNeverNotifyNeighborLost(); 6049 } 6050 6051 @Test 6052 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 6053 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = false) 6054 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6055 public void testIgnoreNudFailuresIfTooManyInPastDay_flagOff() throws Exception { 6056 // NUD failure event count exceeds daily threshold nor weekly. 6057 final long when = System.currentTimeMillis() - ONE_DAY_IN_MS / 2; // 12h ago 6058 final long expiry = when + ONE_WEEK_IN_MS; 6059 storeNudFailureEvents(when, expiry, 19, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6060 6061 runIpReachabilityMonitorProbeFailedTest(); 6062 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 6063 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL); 6064 } 6065 6066 @Test 6067 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 6068 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = true) 6069 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6070 public void testIgnoreNudFailuresIfTooManyInPastDay_notUpToThreshold() 6071 throws Exception { 6072 // NUD failure event count doesn't exceed either weekly threshold nor daily. 6073 final long when = System.currentTimeMillis() - ONE_DAY_IN_MS / 2; // 12h ago 6074 final long expiry = when + ONE_WEEK_IN_MS; 6075 storeNudFailureEvents(when, expiry, 9, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6076 6077 runIpReachabilityMonitorProbeFailedTest(); 6078 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 6079 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL); 6080 } 6081 6082 @Test 6083 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = true) 6084 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6085 public void testIgnoreNudFailuresIfTooManyInPastWeek() throws Exception { 6086 // NUD failure event count exceeds the weekly threshold, but not daily threshold in the past 6087 // day. 6088 long when = System.currentTimeMillis() - ONE_WEEK_IN_MS / 2; // half a week ago 6089 long expiry = when + ONE_WEEK_IN_MS; 6090 storeNudFailureEvents(when, expiry, 11, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6091 6092 when = System.currentTimeMillis() - ONE_DAY_IN_MS / 2; // 12h ago 6093 expiry = when + ONE_WEEK_IN_MS; 6094 storeNudFailureEvents(when, expiry, 9, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6095 6096 runIpReachabilityMonitorProbeFailedTest(); 6097 assertNeverNotifyNeighborLost(); 6098 } 6099 6100 @Test 6101 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 6102 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = false) 6103 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6104 public void testIgnoreNudFailuresIfTooManyInPastWeek_flagOff() throws Exception { 6105 // NUD failure event count exceeds the weekly threshold, but not daily threshold in the past 6106 // day. 6107 long when = System.currentTimeMillis() - ONE_WEEK_IN_MS / 2; // half a week ago 6108 long expiry = when + ONE_WEEK_IN_MS; 6109 storeNudFailureEvents(when, expiry, 11, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6110 6111 when = System.currentTimeMillis() - ONE_DAY_IN_MS / 2; // 12h ago 6112 expiry = when + ONE_WEEK_IN_MS; 6113 storeNudFailureEvents(when, expiry, 9, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6114 6115 runIpReachabilityMonitorProbeFailedTest(); 6116 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 6117 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL); 6118 } 6119 6120 @Test 6121 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 6122 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = true) 6123 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6124 public void testIgnoreNudFailuresIfTooManyInPastWeek_notUpToThreshold() throws Exception { 6125 // NUD failure event count doesn't exceed either weekly threshold nor daily. 6126 long when = System.currentTimeMillis() - ONE_WEEK_IN_MS / 2; // half a week ago 6127 long expiry = when + ONE_WEEK_IN_MS; 6128 storeNudFailureEvents(when, expiry, 10, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6129 6130 when = System.currentTimeMillis() - ONE_DAY_IN_MS / 2; // 12h ago 6131 expiry = when + ONE_WEEK_IN_MS; 6132 storeNudFailureEvents(when, expiry, 9, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM); 6133 6134 runIpReachabilityMonitorProbeFailedTest(); 6135 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 6136 NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL); 6137 } 6138 6139 @Test 6140 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = true) 6141 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6142 public void testIgnoreNudFailuresIfTooManyInPastWeek_stopWritingEvent() throws Exception { 6143 long when = (long) (System.currentTimeMillis() - SIX_HOURS_IN_MS * 0.9); 6144 long expiry = when + ONE_WEEK_IN_MS; 6145 storeNudFailureEvents(when, expiry, 10, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC); 6146 6147 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 6148 ROUTER_LINK_LOCAL /* targetIp */, 6149 false /* expectNeighborLost */); 6150 verify(mIpMemoryStore, never()).storeNetworkEvent(any(), anyLong(), anyLong(), 6151 eq(IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC), any()); 6152 } 6153 6154 @Test 6155 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, enabled = false) 6156 @Flag(name = IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, enabled = false) 6157 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 6158 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = true) 6159 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6160 public void testIgnoreNudFailuresStopWritingEvents() throws Exception { 6161 // Add enough failures that NUD failures are ignored. 6162 long when = (long) (System.currentTimeMillis() - SIX_HOURS_IN_MS * 1.1); 6163 long expiry = when + ONE_WEEK_IN_MS; 6164 storeNudFailureEvents(when, expiry, 10, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC); 6165 6166 // Add enough recent failures to almost, but not quite reach the 6-hour threshold. 6167 when = (long) (System.currentTimeMillis() - SIX_HOURS_IN_MS * 0.1); 6168 expiry = when + ONE_WEEK_IN_MS; 6169 storeNudFailureEvents(when, expiry, 9, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC); 6170 6171 prepareIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, 6172 ROUTER_LINK_LOCAL); 6173 6174 // The first new failure is ignored and written to the database. 6175 // The total is 10 failures in the last 6 hours. 6176 sendPacketToUnreachableNeighbor(ipv6Addr(IPV6_OFF_LINK_DNS_SERVER)); 6177 expectAndDropMulticastNses(ROUTER_LINK_LOCAL, false /* expectNeighborLost */); 6178 verify(mIpMemoryStore).storeNetworkEvent(any(), anyLong(), anyLong(), 6179 eq(IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC), any()); 6180 6181 // The second new failure is ignored, but not written. 6182 reset(mIpMemoryStore); 6183 sendPacketToUnreachableNeighbor(ipv6Addr(IPV6_ON_LINK_DNS_SERVER)); 6184 expectAndDropMulticastNses(ipv6Addr(IPV6_ON_LINK_DNS_SERVER), 6185 false /* expectNeighborLost */); 6186 verifyNoMoreInteractions(mIpMemoryStore); 6187 } 6188 6189 @Test 6190 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 6191 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = false) 6192 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6193 public void testIgnoreNudFailuresIfTooManyInPastWeek_stopWritingEvent_flagOff() 6194 throws Exception { 6195 long when = (long) (System.currentTimeMillis() - SIX_HOURS_IN_MS * 0.9); 6196 long expiry = when + ONE_WEEK_IN_MS; 6197 storeNudFailureEvents(when, expiry, 10, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC); 6198 6199 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 6200 ROUTER_LINK_LOCAL /* targetIp */, 6201 true /* expectNeighborLost */); 6202 verify(mIpMemoryStore, never()).storeNetworkEvent(any(), anyLong(), anyLong(), 6203 eq(IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC), any()); 6204 } 6205 6206 @Test 6207 @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = false) 6208 @Flag(name = IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION, enabled = true) 6209 @SignatureRequiredTest(reason = "need to delete cluster from real db in tearDown") 6210 public void testIgnoreNudFailuresIfTooManyInPastWeek_stopWritingEvent_notUpToThreshold() 6211 throws Exception { 6212 long when = (long) (System.currentTimeMillis() - SIX_HOURS_IN_MS * 0.9); 6213 long expiry = when + ONE_WEEK_IN_MS; 6214 storeNudFailureEvents(when, expiry, 9, IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC); 6215 6216 runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, 6217 ROUTER_LINK_LOCAL /* targetIp */, 6218 true /* expectNeighborLost */); 6219 assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */, 6220 NudEventType.NUD_ORGANIC_FAILED_CRITICAL); 6221 verify(mIpMemoryStore).storeNetworkEvent(any(), anyLong(), anyLong(), 6222 eq(IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC), any()); 6223 } 6224 } 6225