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.shared; 18 19 import static android.net.ip.IIpClient.HOSTNAME_SETTING_UNSET; 20 import static android.net.ip.IIpClient.PROV_IPV4_DHCP; 21 import static android.net.ip.IIpClient.PROV_IPV4_DISABLED; 22 import static android.net.ip.IIpClient.PROV_IPV4_STATIC; 23 import static android.net.ip.IIpClient.PROV_IPV6_DISABLED; 24 import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL; 25 import static android.net.ip.IIpClient.PROV_IPV6_SLAAC; 26 import static android.net.shared.ParcelableUtil.fromParcelableArray; 27 import static android.net.shared.ParcelableUtil.toParcelableArray; 28 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.net.InformationElementParcelable; 32 import android.net.Network; 33 import android.net.ProvisioningConfigurationParcelable; 34 import android.net.ScanResultInfoParcelable; 35 import android.net.StaticIpConfiguration; 36 import android.net.apf.ApfCapabilities; 37 import android.net.ip.IIpClient; 38 import android.net.networkstack.aidl.dhcp.DhcpOption; 39 import android.util.Log; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 43 import java.nio.BufferUnderflowException; 44 import java.nio.ByteBuffer; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.Collections; 48 import java.util.List; 49 import java.util.Objects; 50 import java.util.StringJoiner; 51 52 /** 53 * This class encapsulates parameters to be passed to 54 * IpClient#startProvisioning(). A defensive copy is made by IpClient 55 * and the values specified herein are in force until IpClient#stop() 56 * is called. 57 * 58 * Example use: 59 * 60 * final ProvisioningConfiguration config = 61 * new ProvisioningConfiguration.Builder() 62 * .withPreDhcpAction() 63 * .withProvisioningTimeoutMs(36 * 1000) 64 * .build(); 65 * mIpClient.startProvisioning(config.toStableParcelable()); 66 * ... 67 * mIpClient.stop(); 68 * 69 * The specified provisioning configuration will only be active until 70 * IIpClient#stop() is called. Future calls to IIpClient#startProvisioning() 71 * must specify the configuration again. 72 * @hide 73 */ 74 public class ProvisioningConfiguration { 75 private static final String TAG = "ProvisioningConfiguration"; 76 77 // TODO: Delete this default timeout once those callers that care are 78 // fixed to pass in their preferred timeout. 79 // 80 // We pick 18 seconds so we can send DHCP requests at 81 // 82 // t=0, t=1, t=3, t=7, t=16 83 // 84 // allowing for 10% jitter. 85 private static final int DEFAULT_TIMEOUT_MS = 18 * 1000; 86 87 // TODO: These cannot be imported from INetd.aidl, because networkstack-client cannot depend on 88 // INetd, as there are users of IpClient that depend on INetd directly (potentially at a 89 // different version, which is not allowed by the build system). 90 // Find a better way to express these constants. 91 public static final int IPV6_ADDR_GEN_MODE_EUI64 = 0; 92 public static final int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; 93 94 // ipv4ProvisioningMode and ipv6ProvisioningMode members are introduced since 95 // networkstack-aidl-interfaces-v12. 96 public static final int VERSION_ADDED_PROVISIONING_ENUM = 12; 97 98 /** 99 * Builder to create a {@link ProvisioningConfiguration}. 100 */ 101 public static class Builder { 102 protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration(); 103 104 /** 105 * Specify that the configuration should not enable IPv4. It is enabled by default. 106 */ withoutIPv4()107 public Builder withoutIPv4() { 108 mConfig.mIPv4ProvisioningMode = PROV_IPV4_DISABLED; 109 return this; 110 } 111 112 /** 113 * Specify that the configuration should not enable IPv6. It is enabled by default. 114 */ withoutIPv6()115 public Builder withoutIPv6() { 116 mConfig.mIPv6ProvisioningMode = PROV_IPV6_DISABLED; 117 return this; 118 } 119 120 /** 121 * Specify that the configuration should not use a MultinetworkPolicyTracker. It is used 122 * by default. 123 */ withoutMultinetworkPolicyTracker()124 public Builder withoutMultinetworkPolicyTracker() { 125 mConfig.mUsingMultinetworkPolicyTracker = false; 126 return this; 127 } 128 129 /** 130 * Specify that the configuration should not use a IpReachabilityMonitor. It is used by 131 * default. 132 */ withoutIpReachabilityMonitor()133 public Builder withoutIpReachabilityMonitor() { 134 mConfig.mUsingIpReachabilityMonitor = false; 135 return this; 136 } 137 138 /** 139 * Identical to {@link #withPreDhcpAction(int)}, using a default timeout. 140 * @see #withPreDhcpAction(int) 141 */ withPreDhcpAction()142 public Builder withPreDhcpAction() { 143 mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS; 144 return this; 145 } 146 147 /** 148 * Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must 149 * call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior 150 * is disabled by default. 151 * @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction(). 152 */ withPreDhcpAction(int dhcpActionTimeoutMs)153 public Builder withPreDhcpAction(int dhcpActionTimeoutMs) { 154 mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs; 155 return this; 156 } 157 158 /** 159 * Specify that preconnection feature would be enabled. It's not used by default. 160 */ withPreconnection()161 public Builder withPreconnection() { 162 mConfig.mEnablePreconnection = true; 163 return this; 164 } 165 166 /** 167 * Specify the initial provisioning configuration. 168 */ withInitialConfiguration(InitialConfiguration initialConfig)169 public Builder withInitialConfiguration(InitialConfiguration initialConfig) { 170 mConfig.mInitialConfig = initialConfig; 171 return this; 172 } 173 174 /** 175 * Specify a static configuration for provisioning. 176 */ withStaticConfiguration(StaticIpConfiguration staticConfig)177 public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) { 178 mConfig.mIPv4ProvisioningMode = PROV_IPV4_STATIC; 179 mConfig.mStaticIpConfig = staticConfig; 180 return this; 181 } 182 183 /** 184 * Specify ApfCapabilities. 185 */ withApfCapabilities(ApfCapabilities apfCapabilities)186 public Builder withApfCapabilities(ApfCapabilities apfCapabilities) { 187 mConfig.mApfCapabilities = apfCapabilities; 188 return this; 189 } 190 191 /** 192 * Specify the timeout to use for provisioning. 193 */ withProvisioningTimeoutMs(int timeoutMs)194 public Builder withProvisioningTimeoutMs(int timeoutMs) { 195 mConfig.mProvisioningTimeoutMs = timeoutMs; 196 return this; 197 } 198 199 /** 200 * Specify that IPv6 address generation should use a random MAC address. 201 */ withRandomMacAddress()202 public Builder withRandomMacAddress() { 203 mConfig.mIPv6AddrGenMode = IPV6_ADDR_GEN_MODE_EUI64; 204 return this; 205 } 206 207 /** 208 * Specify that IPv6 address generation should use a stable MAC address. 209 */ withStableMacAddress()210 public Builder withStableMacAddress() { 211 mConfig.mIPv6AddrGenMode = IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; 212 return this; 213 } 214 215 /** 216 * Specify the network to use for provisioning. 217 */ withNetwork(Network network)218 public Builder withNetwork(Network network) { 219 mConfig.mNetwork = network; 220 return this; 221 } 222 223 /** 224 * Specify the display name that the IpClient should use. 225 */ withDisplayName(String displayName)226 public Builder withDisplayName(String displayName) { 227 mConfig.mDisplayName = displayName; 228 return this; 229 } 230 231 /** 232 * Specify the UID of the remote entity that created this Network. 233 */ withCreatorUid(int creatoruid)234 public Builder withCreatorUid(int creatoruid) { 235 mConfig.mCreatorUid = creatoruid; 236 return this; 237 } 238 239 /** 240 * Specify the information elements included in wifi scan result that was obtained 241 * prior to connecting to the access point, if this is a WiFi network. 242 * 243 * <p>The scan result can be used to infer whether the network is metered. 244 */ withScanResultInfo(ScanResultInfo scanResultInfo)245 public Builder withScanResultInfo(ScanResultInfo scanResultInfo) { 246 mConfig.mScanResultInfo = scanResultInfo; 247 return this; 248 } 249 250 /** 251 * Specify the L2 information(bssid, l2key and cluster) that the IpClient should use. 252 */ withLayer2Information(Layer2Information layer2Info)253 public Builder withLayer2Information(Layer2Information layer2Info) { 254 mConfig.mLayer2Info = layer2Info; 255 return this; 256 } 257 258 /** 259 * Specify the customized DHCP options to be put in the PRL or in the DHCP packet. Options 260 * with null value will be put in the PRL. 261 * 262 * @param: options customized DHCP option stable parcelable list. 263 */ withDhcpOptions(@ullable List<DhcpOption> options)264 public Builder withDhcpOptions(@Nullable List<DhcpOption> options) { 265 mConfig.mDhcpOptions = options; 266 return this; 267 } 268 269 /** 270 * Specify that the configuration should enable IPv6 link-local only mode used for 271 * WiFi Neighbor Aware Networking and other link-local-only technologies. It's not 272 * used by default, and IPv4 must be disabled when this mode is enabled. 273 * 274 * @note This API is only supported since Android T. 275 */ withIpv6LinkLocalOnly()276 public Builder withIpv6LinkLocalOnly() { 277 mConfig.mIPv6ProvisioningMode = PROV_IPV6_LINKLOCAL; 278 return this; 279 } 280 281 /** 282 * Specify that the configuration is for a network that only uses unique EUI-64 283 * addresses (e.g., a link-local-only network where addresses are generated via 284 * EUI-64 and where MAC addresses are guaranteed to be unique). 285 * This will disable duplicate address detection if withLinkLocalOnly() and 286 * withRandomMacAddress are also called. 287 */ withUniqueEui64AddressesOnly()288 public Builder withUniqueEui64AddressesOnly() { 289 mConfig.mUniqueEui64AddressesOnly = true; 290 return this; 291 } 292 293 /** 294 * Specify the hostname setting to use during IP provisioning. 295 * - {@link IIpClient#HOSTNAME_SETTING_UNSET}: Default value. 296 * - {@link IIpClient#HOSTNAME_SETTING_SEND}: Send the hostname. 297 * - {@link IIpClient#HOSTNAME_SETTING_DO_NOT_SEND}: Don't send the hostname. 298 */ withHostnameSetting(int setting)299 public Builder withHostnameSetting(int setting) { 300 mConfig.mHostnameSetting = setting; 301 return this; 302 } 303 304 /** 305 * Build the configuration using previously specified parameters. 306 */ build()307 public ProvisioningConfiguration build() { 308 if (mConfig.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL 309 && mConfig.mIPv4ProvisioningMode != PROV_IPV4_DISABLED) { 310 throw new IllegalArgumentException("IPv4 must be disabled in IPv6 link-local" 311 + "only mode."); 312 } 313 return new ProvisioningConfiguration(mConfig); 314 } 315 } 316 317 /** 318 * Class wrapper of {@link android.net.wifi.ScanResult} to encapsulate the SSID and 319 * InformationElements fields of ScanResult. 320 */ 321 public static class ScanResultInfo { 322 @NonNull 323 private final String mSsid; 324 @NonNull 325 private final String mBssid; 326 @NonNull 327 private final List<InformationElement> mInformationElements; 328 329 /** 330 * Class wrapper of {@link android.net.wifi.ScanResult.InformationElement} to encapsulate 331 * the specific IE id and payload fields. 332 */ 333 public static class InformationElement { 334 private final int mId; 335 @NonNull 336 private final byte[] mPayload; 337 InformationElement(int id, @NonNull ByteBuffer payload)338 public InformationElement(int id, @NonNull ByteBuffer payload) { 339 mId = id; 340 mPayload = convertToByteArray(payload.asReadOnlyBuffer()); 341 } 342 343 /** 344 * Get the element ID of the information element. 345 */ getId()346 public int getId() { 347 return mId; 348 } 349 350 /** 351 * Get the specific content of the information element. 352 */ 353 @NonNull getPayload()354 public ByteBuffer getPayload() { 355 return ByteBuffer.wrap(mPayload).asReadOnlyBuffer(); 356 } 357 358 @Override equals(Object o)359 public boolean equals(Object o) { 360 if (o == this) return true; 361 if (!(o instanceof InformationElement)) return false; 362 InformationElement other = (InformationElement) o; 363 return mId == other.mId && Arrays.equals(mPayload, other.mPayload); 364 } 365 366 @Override hashCode()367 public int hashCode() { 368 return Objects.hash(mId, Arrays.hashCode(mPayload)); 369 } 370 371 @Override toString()372 public String toString() { 373 return "ID: " + mId + ", " + Arrays.toString(mPayload); 374 } 375 376 /** 377 * Convert this InformationElement to a {@link InformationElementParcelable}. 378 */ toStableParcelable()379 public InformationElementParcelable toStableParcelable() { 380 final InformationElementParcelable p = new InformationElementParcelable(); 381 p.id = mId; 382 p.payload = mPayload != null ? mPayload.clone() : null; 383 return p; 384 } 385 386 /** 387 * Create an instance of {@link InformationElement} based on the contents of the 388 * specified {@link InformationElementParcelable}. 389 */ 390 @Nullable fromStableParcelable(InformationElementParcelable p)391 public static InformationElement fromStableParcelable(InformationElementParcelable p) { 392 if (p == null) return null; 393 return new InformationElement(p.id, 394 ByteBuffer.wrap(p.payload.clone()).asReadOnlyBuffer()); 395 } 396 } 397 ScanResultInfo(@onNull String ssid, @NonNull String bssid, @NonNull List<InformationElement> informationElements)398 public ScanResultInfo(@NonNull String ssid, @NonNull String bssid, 399 @NonNull List<InformationElement> informationElements) { 400 Objects.requireNonNull(ssid, "ssid must not be null."); 401 Objects.requireNonNull(bssid, "bssid must not be null."); 402 mSsid = ssid; 403 mBssid = bssid; 404 mInformationElements = 405 Collections.unmodifiableList(new ArrayList<>(informationElements)); 406 } 407 408 /** 409 * Get the scanned network name. 410 */ 411 @NonNull getSsid()412 public String getSsid() { 413 return mSsid; 414 } 415 416 /** 417 * Get the address of the access point. 418 */ 419 @NonNull getBssid()420 public String getBssid() { 421 return mBssid; 422 } 423 424 /** 425 * Get all information elements found in the beacon. 426 */ 427 @NonNull getInformationElements()428 public List<InformationElement> getInformationElements() { 429 return mInformationElements; 430 } 431 432 @Override toString()433 public String toString() { 434 StringBuffer str = new StringBuffer(); 435 str.append("SSID: ").append(mSsid); 436 str.append(", BSSID: ").append(mBssid); 437 str.append(", Information Elements: {"); 438 for (InformationElement ie : mInformationElements) { 439 str.append("[").append(ie.toString()).append("]"); 440 } 441 str.append("}"); 442 return str.toString(); 443 } 444 445 @Override equals(Object o)446 public boolean equals(Object o) { 447 if (o == this) return true; 448 if (!(o instanceof ScanResultInfo)) return false; 449 ScanResultInfo other = (ScanResultInfo) o; 450 return Objects.equals(mSsid, other.mSsid) 451 && Objects.equals(mBssid, other.mBssid) 452 && mInformationElements.equals(other.mInformationElements); 453 } 454 455 @Override hashCode()456 public int hashCode() { 457 return Objects.hash(mSsid, mBssid, mInformationElements); 458 } 459 460 /** 461 * Convert this ScanResultInfo to a {@link ScanResultInfoParcelable}. 462 */ toStableParcelable()463 public ScanResultInfoParcelable toStableParcelable() { 464 final ScanResultInfoParcelable p = new ScanResultInfoParcelable(); 465 p.ssid = mSsid; 466 p.bssid = mBssid; 467 p.informationElements = toParcelableArray(mInformationElements, 468 InformationElement::toStableParcelable, InformationElementParcelable.class); 469 return p; 470 } 471 472 /** 473 * Create an instance of {@link ScanResultInfo} based on the contents of the specified 474 * {@link ScanResultInfoParcelable}. 475 */ fromStableParcelable(ScanResultInfoParcelable p)476 public static ScanResultInfo fromStableParcelable(ScanResultInfoParcelable p) { 477 if (p == null) return null; 478 final List<InformationElement> ies = new ArrayList<InformationElement>(); 479 ies.addAll(fromParcelableArray(p.informationElements, 480 InformationElement::fromStableParcelable)); 481 return new ScanResultInfo(p.ssid, p.bssid, ies); 482 } 483 convertToByteArray(@onNull final ByteBuffer buffer)484 private static byte[] convertToByteArray(@NonNull final ByteBuffer buffer) { 485 final byte[] bytes = new byte[buffer.limit()]; 486 final ByteBuffer copy = buffer.asReadOnlyBuffer(); 487 try { 488 copy.position(0); 489 copy.get(bytes); 490 } catch (BufferUnderflowException e) { 491 Log.wtf(TAG, "Buffer under flow exception should never happen."); 492 } finally { 493 return bytes; 494 } 495 } 496 } 497 498 public boolean mUniqueEui64AddressesOnly = false; 499 public boolean mEnablePreconnection = false; 500 public boolean mUsingMultinetworkPolicyTracker = true; 501 public boolean mUsingIpReachabilityMonitor = true; 502 public int mRequestedPreDhcpActionMs; 503 public InitialConfiguration mInitialConfig; 504 public StaticIpConfiguration mStaticIpConfig; 505 public ApfCapabilities mApfCapabilities; 506 public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS; 507 public int mIPv6AddrGenMode = IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; 508 public Network mNetwork = null; 509 public String mDisplayName = null; 510 public ScanResultInfo mScanResultInfo; 511 public Layer2Information mLayer2Info; 512 public List<DhcpOption> mDhcpOptions; 513 public int mIPv4ProvisioningMode = PROV_IPV4_DHCP; 514 public int mIPv6ProvisioningMode = PROV_IPV6_SLAAC; 515 public int mCreatorUid; 516 public int mHostnameSetting = HOSTNAME_SETTING_UNSET; 517 ProvisioningConfiguration()518 public ProvisioningConfiguration() {} // used by Builder 519 ProvisioningConfiguration(ProvisioningConfiguration other)520 public ProvisioningConfiguration(ProvisioningConfiguration other) { 521 mUniqueEui64AddressesOnly = other.mUniqueEui64AddressesOnly; 522 mEnablePreconnection = other.mEnablePreconnection; 523 mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker; 524 mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor; 525 mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs; 526 mInitialConfig = InitialConfiguration.copy(other.mInitialConfig); 527 mStaticIpConfig = other.mStaticIpConfig == null 528 ? null 529 : new StaticIpConfiguration(other.mStaticIpConfig); 530 mApfCapabilities = other.mApfCapabilities; 531 mProvisioningTimeoutMs = other.mProvisioningTimeoutMs; 532 mIPv6AddrGenMode = other.mIPv6AddrGenMode; 533 mNetwork = other.mNetwork; 534 mDisplayName = other.mDisplayName; 535 mCreatorUid = other.mCreatorUid; 536 mScanResultInfo = other.mScanResultInfo; 537 mLayer2Info = other.mLayer2Info; 538 mDhcpOptions = other.mDhcpOptions; 539 mIPv4ProvisioningMode = other.mIPv4ProvisioningMode; 540 mIPv6ProvisioningMode = other.mIPv6ProvisioningMode; 541 mHostnameSetting = other.mHostnameSetting; 542 } 543 544 /** 545 * Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration. 546 */ toStableParcelable()547 public ProvisioningConfigurationParcelable toStableParcelable() { 548 final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable(); 549 p.enableIPv4 = (mIPv4ProvisioningMode != PROV_IPV4_DISABLED); 550 p.ipv4ProvisioningMode = mIPv4ProvisioningMode; 551 p.enableIPv6 = (mIPv6ProvisioningMode != PROV_IPV6_DISABLED); 552 p.ipv6ProvisioningMode = mIPv6ProvisioningMode; 553 p.uniqueEui64AddressesOnly = mUniqueEui64AddressesOnly; 554 p.enablePreconnection = mEnablePreconnection; 555 p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker; 556 p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor; 557 p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs; 558 p.initialConfig = (mInitialConfig == null) ? null : mInitialConfig.toStableParcelable(); 559 p.staticIpConfig = (mStaticIpConfig == null) 560 ? null 561 : new StaticIpConfiguration(mStaticIpConfig); 562 p.apfCapabilities = mApfCapabilities; // ApfCapabilities is immutable 563 p.provisioningTimeoutMs = mProvisioningTimeoutMs; 564 p.ipv6AddrGenMode = mIPv6AddrGenMode; 565 p.network = mNetwork; 566 p.displayName = mDisplayName; 567 p.creatorUid = mCreatorUid; 568 p.scanResultInfo = (mScanResultInfo == null) ? null : mScanResultInfo.toStableParcelable(); 569 p.layer2Info = (mLayer2Info == null) ? null : mLayer2Info.toStableParcelable(); 570 p.options = (mDhcpOptions == null) ? null : new ArrayList<>(mDhcpOptions); 571 p.hostnameSetting = mHostnameSetting; 572 return p; 573 } 574 575 /** 576 * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable. 577 * 578 * @param p stable parcelable instance to be converted to a {@link ProvisioningConfiguration}. 579 * @param interfaceVersion IIpClientCallbacks interface version called by the remote peer, 580 * which is used to determine the appropriate parcelable members for 581 * backwards compatibility. 582 */ fromStableParcelable( @ullable ProvisioningConfigurationParcelable p, int interfaceVersion)583 public static ProvisioningConfiguration fromStableParcelable( 584 @Nullable ProvisioningConfigurationParcelable p, int interfaceVersion) { 585 if (p == null) return null; 586 final ProvisioningConfiguration config = new ProvisioningConfiguration(); 587 config.mUniqueEui64AddressesOnly = p.uniqueEui64AddressesOnly; 588 config.mEnablePreconnection = p.enablePreconnection; 589 config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker; 590 config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor; 591 config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs; 592 config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig); 593 config.mStaticIpConfig = (p.staticIpConfig == null) 594 ? null 595 : new StaticIpConfiguration(p.staticIpConfig); 596 config.mApfCapabilities = p.apfCapabilities; // ApfCapabilities is immutable 597 config.mProvisioningTimeoutMs = p.provisioningTimeoutMs; 598 config.mIPv6AddrGenMode = p.ipv6AddrGenMode; 599 config.mNetwork = p.network; 600 config.mDisplayName = p.displayName; 601 config.mCreatorUid = p.creatorUid; 602 config.mScanResultInfo = ScanResultInfo.fromStableParcelable(p.scanResultInfo); 603 config.mLayer2Info = Layer2Information.fromStableParcelable(p.layer2Info); 604 config.mDhcpOptions = (p.options == null) ? null : new ArrayList<>(p.options); 605 if (interfaceVersion < VERSION_ADDED_PROVISIONING_ENUM) { 606 config.mIPv4ProvisioningMode = p.enableIPv4 ? PROV_IPV4_DHCP : PROV_IPV4_DISABLED; 607 config.mIPv6ProvisioningMode = p.enableIPv6 ? PROV_IPV6_SLAAC : PROV_IPV6_DISABLED; 608 } else { 609 config.mIPv4ProvisioningMode = p.ipv4ProvisioningMode; 610 config.mIPv6ProvisioningMode = p.ipv6ProvisioningMode; 611 } 612 config.mHostnameSetting = p.hostnameSetting; 613 return config; 614 } 615 616 @VisibleForTesting ipv4ProvisioningModeToString(int mode)617 static String ipv4ProvisioningModeToString(int mode) { 618 switch (mode) { 619 case PROV_IPV4_DISABLED: 620 return "disabled"; 621 case PROV_IPV4_STATIC: 622 return "static"; 623 case PROV_IPV4_DHCP: 624 return "dhcp"; 625 default: 626 return "unknown"; 627 } 628 } 629 630 @VisibleForTesting ipv6ProvisioningModeToString(int mode)631 static String ipv6ProvisioningModeToString(int mode) { 632 switch (mode) { 633 case PROV_IPV6_DISABLED: 634 return "disabled"; 635 case PROV_IPV6_SLAAC: 636 return "slaac"; 637 case PROV_IPV6_LINKLOCAL: 638 return "link-local"; 639 default: 640 return "unknown"; 641 } 642 } 643 644 @Override toString()645 public String toString() { 646 final String ipv4ProvisioningMode = ipv4ProvisioningModeToString(mIPv4ProvisioningMode); 647 final String ipv6ProvisioningMode = ipv6ProvisioningModeToString(mIPv6ProvisioningMode); 648 return new StringJoiner(", ", getClass().getSimpleName() + "{", "}") 649 .add("mUniqueEui64AddressesOnly: " + mUniqueEui64AddressesOnly) 650 .add("mEnablePreconnection: " + mEnablePreconnection) 651 .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker) 652 .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor) 653 .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs) 654 .add("mInitialConfig: " + mInitialConfig) 655 .add("mStaticIpConfig: " + mStaticIpConfig) 656 .add("mApfCapabilities: " + mApfCapabilities) 657 .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs) 658 .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode) 659 .add("mNetwork: " + mNetwork) 660 .add("mDisplayName: " + mDisplayName) 661 .add("mCreatorUid:" + mCreatorUid) 662 .add("mScanResultInfo: " + mScanResultInfo) 663 .add("mLayer2Info: " + mLayer2Info) 664 .add("mDhcpOptions: " + mDhcpOptions) 665 .add("mIPv4ProvisioningMode: " + ipv4ProvisioningMode) 666 .add("mIPv6ProvisioningMode: " + ipv6ProvisioningMode) 667 .add("mHostnameSetting: " + mHostnameSetting) 668 .toString(); 669 } 670 671 // TODO: mark DhcpOption stable parcelable with @JavaDerive(equals=true, toString=true) 672 // and @JavaOnlyImmutable. dhcpOptionEquals(@ullable DhcpOption obj1, @Nullable DhcpOption obj2)673 private static boolean dhcpOptionEquals(@Nullable DhcpOption obj1, @Nullable DhcpOption obj2) { 674 if (obj1 == obj2) return true; 675 if (obj1 == null || obj2 == null) return false; 676 return obj1.type == obj2.type && Arrays.equals(obj1.value, obj2.value); 677 } 678 679 // TODO: use Objects.equals(List<DhcpOption>, List<DhcpOption>) method instead once 680 // auto-generated equals() method of stable parcelable is supported in mainline-prod. dhcpOptionListEquals(@ullable List<DhcpOption> l1, @Nullable List<DhcpOption> l2)681 private static boolean dhcpOptionListEquals(@Nullable List<DhcpOption> l1, 682 @Nullable List<DhcpOption> l2) { 683 if (l1 == l2) return true; 684 if (l1 == null || l2 == null) return false; 685 if (l1.size() != l2.size()) return false; 686 687 for (int i = 0; i < l1.size(); i++) { 688 if (!dhcpOptionEquals(l1.get(i), l2.get(i))) return false; 689 } 690 return true; 691 } 692 693 @Override equals(Object obj)694 public boolean equals(Object obj) { 695 if (!(obj instanceof ProvisioningConfiguration)) return false; 696 final ProvisioningConfiguration other = (ProvisioningConfiguration) obj; 697 return mUniqueEui64AddressesOnly == other.mUniqueEui64AddressesOnly 698 && mEnablePreconnection == other.mEnablePreconnection 699 && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker 700 && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor 701 && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs 702 && Objects.equals(mInitialConfig, other.mInitialConfig) 703 && Objects.equals(mStaticIpConfig, other.mStaticIpConfig) 704 && Objects.equals(mApfCapabilities, other.mApfCapabilities) 705 && mProvisioningTimeoutMs == other.mProvisioningTimeoutMs 706 && mIPv6AddrGenMode == other.mIPv6AddrGenMode 707 && Objects.equals(mNetwork, other.mNetwork) 708 && Objects.equals(mDisplayName, other.mDisplayName) 709 && Objects.equals(mScanResultInfo, other.mScanResultInfo) 710 && Objects.equals(mLayer2Info, other.mLayer2Info) 711 && dhcpOptionListEquals(mDhcpOptions, other.mDhcpOptions) 712 && mIPv4ProvisioningMode == other.mIPv4ProvisioningMode 713 && mIPv6ProvisioningMode == other.mIPv6ProvisioningMode 714 && mCreatorUid == other.mCreatorUid 715 && mHostnameSetting == other.mHostnameSetting; 716 } 717 isValid()718 public boolean isValid() { 719 return (mInitialConfig == null) || mInitialConfig.isValid(); 720 } 721 } 722