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