1 /* 2 * Copyright (C) 2010 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; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.annotation.TestApi; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.net.util.LinkPropertiesUtils; 25 import android.net.util.LinkPropertiesUtils.CompareResult; 26 import android.os.Build; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.text.TextUtils; 30 31 import java.net.Inet4Address; 32 import java.net.Inet6Address; 33 import java.net.InetAddress; 34 import java.net.UnknownHostException; 35 import java.util.ArrayList; 36 import java.util.Collection; 37 import java.util.Collections; 38 import java.util.Hashtable; 39 import java.util.List; 40 import java.util.Objects; 41 import java.util.StringJoiner; 42 43 /** 44 * Describes the properties of a network link. 45 * 46 * A link represents a connection to a network. 47 * It may have multiple addresses and multiple gateways, 48 * multiple dns servers but only one http proxy and one 49 * network interface. 50 * 51 * Note that this is just a holder of data. Modifying it 52 * does not affect live networks. 53 * 54 */ 55 public final class LinkProperties implements Parcelable { 56 // The interface described by the network link. 57 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 58 private String mIfaceName; 59 private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>(); 60 private final ArrayList<InetAddress> mDnses = new ArrayList<>(); 61 // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service. 62 private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>(); 63 private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>(); 64 private boolean mUsePrivateDns; 65 private String mPrivateDnsServerName; 66 private String mDomains; 67 private ArrayList<RouteInfo> mRoutes = new ArrayList<>(); 68 private Inet4Address mDhcpServerAddress; 69 private ProxyInfo mHttpProxy; 70 private int mMtu; 71 // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" 72 private String mTcpBufferSizes; 73 private IpPrefix mNat64Prefix; 74 private boolean mWakeOnLanSupported; 75 private Uri mCaptivePortalApiUrl; 76 private CaptivePortalData mCaptivePortalData; 77 78 /** 79 * Indicates whether parceling should preserve fields that are set based on permissions of 80 * the process receiving the {@link LinkProperties}. 81 */ 82 private final transient boolean mParcelSensitiveFields; 83 84 private static final int MIN_MTU = 68; 85 /* package-visibility - Used in other files (such as Ikev2VpnProfile) as minimum iface MTU. */ 86 static final int MIN_MTU_V6 = 1280; 87 private static final int MAX_MTU = 10000; 88 89 private static final int INET6_ADDR_LENGTH = 16; 90 91 // Stores the properties of links that are "stacked" above this link. 92 // Indexed by interface name to allow modification and to prevent duplicates being added. 93 private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>(); 94 95 /** 96 * @hide 97 */ 98 @UnsupportedAppUsage(implicitMember = 99 "values()[Landroid/net/LinkProperties$ProvisioningChange;") 100 public enum ProvisioningChange { 101 @UnsupportedAppUsage 102 STILL_NOT_PROVISIONED, 103 @UnsupportedAppUsage 104 LOST_PROVISIONING, 105 @UnsupportedAppUsage 106 GAINED_PROVISIONING, 107 @UnsupportedAppUsage 108 STILL_PROVISIONED, 109 } 110 111 /** 112 * Compare the provisioning states of two LinkProperties instances. 113 * 114 * @hide 115 */ 116 @UnsupportedAppUsage compareProvisioning( LinkProperties before, LinkProperties after)117 public static ProvisioningChange compareProvisioning( 118 LinkProperties before, LinkProperties after) { 119 if (before.isProvisioned() && after.isProvisioned()) { 120 // On dual-stack networks, DHCPv4 renewals can occasionally fail. 121 // When this happens, IPv6-reachable services continue to function 122 // normally but IPv4-only services (naturally) fail. 123 // 124 // When an application using an IPv4-only service reports a bad 125 // network condition to the framework, attempts to re-validate 126 // the network succeed (since we support IPv6-only networks) and 127 // nothing is changed. 128 // 129 // For users, this is confusing and unexpected behaviour, and is 130 // not necessarily easy to diagnose. Therefore, we treat changing 131 // from a dual-stack network to an IPv6-only network equivalent to 132 // a total loss of provisioning. 133 // 134 // For one such example of this, see b/18867306. 135 // 136 // Additionally, losing IPv6 provisioning can result in TCP 137 // connections getting stuck until timeouts fire and other 138 // baffling failures. Therefore, loss of either IPv4 or IPv6 on a 139 // previously dual-stack network is deemed a lost of provisioning. 140 if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned()) 141 || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) { 142 return ProvisioningChange.LOST_PROVISIONING; 143 } 144 return ProvisioningChange.STILL_PROVISIONED; 145 } else if (before.isProvisioned() && !after.isProvisioned()) { 146 return ProvisioningChange.LOST_PROVISIONING; 147 } else if (!before.isProvisioned() && after.isProvisioned()) { 148 return ProvisioningChange.GAINED_PROVISIONING; 149 } else { // !before.isProvisioned() && !after.isProvisioned() 150 return ProvisioningChange.STILL_NOT_PROVISIONED; 151 } 152 } 153 154 /** 155 * Constructs a new {@code LinkProperties} with default values. 156 */ LinkProperties()157 public LinkProperties() { 158 mParcelSensitiveFields = false; 159 } 160 161 /** 162 * @hide 163 */ 164 @SystemApi 165 @TestApi LinkProperties(@ullable LinkProperties source)166 public LinkProperties(@Nullable LinkProperties source) { 167 this(source, false /* parcelSensitiveFields */); 168 } 169 170 /** 171 * Create a copy of a {@link LinkProperties} that may preserve fields that were set 172 * based on the permissions of the process that originally received it. 173 * 174 * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as 175 * they should not be shared outside of the process that receives them without appropriate 176 * checks. 177 * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling 178 * @hide 179 */ 180 @SystemApi 181 @TestApi LinkProperties(@ullable LinkProperties source, boolean parcelSensitiveFields)182 public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) { 183 mParcelSensitiveFields = parcelSensitiveFields; 184 if (source == null) return; 185 mIfaceName = source.mIfaceName; 186 mLinkAddresses.addAll(source.mLinkAddresses); 187 mDnses.addAll(source.mDnses); 188 mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses); 189 mUsePrivateDns = source.mUsePrivateDns; 190 mPrivateDnsServerName = source.mPrivateDnsServerName; 191 mPcscfs.addAll(source.mPcscfs); 192 mDomains = source.mDomains; 193 mRoutes.addAll(source.mRoutes); 194 mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy); 195 for (LinkProperties l: source.mStackedLinks.values()) { 196 addStackedLink(l); 197 } 198 setMtu(source.mMtu); 199 setDhcpServerAddress(source.getDhcpServerAddress()); 200 mTcpBufferSizes = source.mTcpBufferSizes; 201 mNat64Prefix = source.mNat64Prefix; 202 mWakeOnLanSupported = source.mWakeOnLanSupported; 203 mCaptivePortalApiUrl = source.mCaptivePortalApiUrl; 204 mCaptivePortalData = source.mCaptivePortalData; 205 } 206 207 /** 208 * Sets the interface name for this link. All {@link RouteInfo} already set for this 209 * will have their interface changed to match this new value. 210 * 211 * @param iface The name of the network interface used for this link. 212 */ setInterfaceName(@ullable String iface)213 public void setInterfaceName(@Nullable String iface) { 214 mIfaceName = iface; 215 ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size()); 216 for (RouteInfo route : mRoutes) { 217 newRoutes.add(routeWithInterface(route)); 218 } 219 mRoutes = newRoutes; 220 } 221 222 /** 223 * Gets the interface name for this link. May be {@code null} if not set. 224 * 225 * @return The interface name set for this link or {@code null}. 226 */ getInterfaceName()227 public @Nullable String getInterfaceName() { 228 return mIfaceName; 229 } 230 231 /** 232 * @hide 233 */ 234 @SystemApi getAllInterfaceNames()235 public @NonNull List<String> getAllInterfaceNames() { 236 List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1); 237 if (mIfaceName != null) interfaceNames.add(mIfaceName); 238 for (LinkProperties stacked: mStackedLinks.values()) { 239 interfaceNames.addAll(stacked.getAllInterfaceNames()); 240 } 241 return interfaceNames; 242 } 243 244 /** 245 * Returns all the addresses on this link. We often think of a link having a single address, 246 * however, particularly with Ipv6 several addresses are typical. Note that the 247 * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include 248 * prefix lengths for each address. This is a simplified utility alternative to 249 * {@link LinkProperties#getLinkAddresses}. 250 * 251 * @return An unmodifiable {@link List} of {@link InetAddress} for this link. 252 * @hide 253 */ 254 @SystemApi getAddresses()255 public @NonNull List<InetAddress> getAddresses() { 256 final List<InetAddress> addresses = new ArrayList<>(); 257 for (LinkAddress linkAddress : mLinkAddresses) { 258 addresses.add(linkAddress.getAddress()); 259 } 260 return Collections.unmodifiableList(addresses); 261 } 262 263 /** 264 * Returns all the addresses on this link and all the links stacked above it. 265 * @hide 266 */ 267 @UnsupportedAppUsage getAllAddresses()268 public @NonNull List<InetAddress> getAllAddresses() { 269 List<InetAddress> addresses = new ArrayList<>(); 270 for (LinkAddress linkAddress : mLinkAddresses) { 271 addresses.add(linkAddress.getAddress()); 272 } 273 for (LinkProperties stacked: mStackedLinks.values()) { 274 addresses.addAll(stacked.getAllAddresses()); 275 } 276 return addresses; 277 } 278 findLinkAddressIndex(LinkAddress address)279 private int findLinkAddressIndex(LinkAddress address) { 280 for (int i = 0; i < mLinkAddresses.size(); i++) { 281 if (mLinkAddresses.get(i).isSameAddressAs(address)) { 282 return i; 283 } 284 } 285 return -1; 286 } 287 288 /** 289 * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the 290 * same address/prefix does not already exist. If it does exist it is replaced. 291 * @param address The {@code LinkAddress} to add. 292 * @return true if {@code address} was added or updated, false otherwise. 293 * @hide 294 */ 295 @SystemApi 296 @TestApi addLinkAddress(@onNull LinkAddress address)297 public boolean addLinkAddress(@NonNull LinkAddress address) { 298 if (address == null) { 299 return false; 300 } 301 int i = findLinkAddressIndex(address); 302 if (i < 0) { 303 // Address was not present. Add it. 304 mLinkAddresses.add(address); 305 return true; 306 } else if (mLinkAddresses.get(i).equals(address)) { 307 // Address was present and has same properties. Do nothing. 308 return false; 309 } else { 310 // Address was present and has different properties. Update it. 311 mLinkAddresses.set(i, address); 312 return true; 313 } 314 } 315 316 /** 317 * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches 318 * and {@link LinkAddress} with the same address and prefix. 319 * 320 * @param toRemove A {@link LinkAddress} specifying the address to remove. 321 * @return true if the address was removed, false if it did not exist. 322 * @hide 323 */ 324 @SystemApi 325 @TestApi removeLinkAddress(@onNull LinkAddress toRemove)326 public boolean removeLinkAddress(@NonNull LinkAddress toRemove) { 327 int i = findLinkAddressIndex(toRemove); 328 if (i >= 0) { 329 mLinkAddresses.remove(i); 330 return true; 331 } 332 return false; 333 } 334 335 /** 336 * Returns all the {@link LinkAddress} on this link. Typically a link will have 337 * one IPv4 address and one or more IPv6 addresses. 338 * 339 * @return An unmodifiable {@link List} of {@link LinkAddress} for this link. 340 */ getLinkAddresses()341 public @NonNull List<LinkAddress> getLinkAddresses() { 342 return Collections.unmodifiableList(mLinkAddresses); 343 } 344 345 /** 346 * Returns all the addresses on this link and all the links stacked above it. 347 * @hide 348 */ 349 @SystemApi getAllLinkAddresses()350 public @NonNull List<LinkAddress> getAllLinkAddresses() { 351 List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses); 352 for (LinkProperties stacked: mStackedLinks.values()) { 353 addresses.addAll(stacked.getAllLinkAddresses()); 354 } 355 return addresses; 356 } 357 358 /** 359 * Replaces the {@link LinkAddress} in this {@code LinkProperties} with 360 * the given {@link Collection} of {@link LinkAddress}. 361 * 362 * @param addresses The {@link Collection} of {@link LinkAddress} to set in this 363 * object. 364 */ setLinkAddresses(@onNull Collection<LinkAddress> addresses)365 public void setLinkAddresses(@NonNull Collection<LinkAddress> addresses) { 366 mLinkAddresses.clear(); 367 for (LinkAddress address: addresses) { 368 addLinkAddress(address); 369 } 370 } 371 372 /** 373 * Adds the given {@link InetAddress} to the list of DNS servers, if not present. 374 * 375 * @param dnsServer The {@link InetAddress} to add to the list of DNS servers. 376 * @return true if the DNS server was added, false if it was already present. 377 * @hide 378 */ 379 @TestApi 380 @SystemApi addDnsServer(@onNull InetAddress dnsServer)381 public boolean addDnsServer(@NonNull InetAddress dnsServer) { 382 if (dnsServer != null && !mDnses.contains(dnsServer)) { 383 mDnses.add(dnsServer); 384 return true; 385 } 386 return false; 387 } 388 389 /** 390 * Removes the given {@link InetAddress} from the list of DNS servers. 391 * 392 * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers. 393 * @return true if the DNS server was removed, false if it did not exist. 394 * @hide 395 */ 396 @TestApi 397 @SystemApi removeDnsServer(@onNull InetAddress dnsServer)398 public boolean removeDnsServer(@NonNull InetAddress dnsServer) { 399 return mDnses.remove(dnsServer); 400 } 401 402 /** 403 * Replaces the DNS servers in this {@code LinkProperties} with 404 * the given {@link Collection} of {@link InetAddress} objects. 405 * 406 * @param dnsServers The {@link Collection} of DNS servers to set in this object. 407 */ setDnsServers(@onNull Collection<InetAddress> dnsServers)408 public void setDnsServers(@NonNull Collection<InetAddress> dnsServers) { 409 mDnses.clear(); 410 for (InetAddress dnsServer: dnsServers) { 411 addDnsServer(dnsServer); 412 } 413 } 414 415 /** 416 * Returns all the {@link InetAddress} for DNS servers on this link. 417 * 418 * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on 419 * this link. 420 */ getDnsServers()421 public @NonNull List<InetAddress> getDnsServers() { 422 return Collections.unmodifiableList(mDnses); 423 } 424 425 /** 426 * Set whether private DNS is currently in use on this network. 427 * 428 * @param usePrivateDns The private DNS state. 429 * @hide 430 */ 431 @TestApi 432 @SystemApi setUsePrivateDns(boolean usePrivateDns)433 public void setUsePrivateDns(boolean usePrivateDns) { 434 mUsePrivateDns = usePrivateDns; 435 } 436 437 /** 438 * Returns whether private DNS is currently in use on this network. When 439 * private DNS is in use, applications must not send unencrypted DNS 440 * queries as doing so could reveal private user information. Furthermore, 441 * if private DNS is in use and {@link #getPrivateDnsServerName} is not 442 * {@code null}, DNS queries must be sent to the specified DNS server. 443 * 444 * @return {@code true} if private DNS is in use, {@code false} otherwise. 445 */ isPrivateDnsActive()446 public boolean isPrivateDnsActive() { 447 return mUsePrivateDns; 448 } 449 450 /** 451 * Set the name of the private DNS server to which private DNS queries 452 * should be sent when in strict mode. This value should be {@code null} 453 * when private DNS is off or in opportunistic mode. 454 * 455 * @param privateDnsServerName The private DNS server name. 456 * @hide 457 */ 458 @TestApi 459 @SystemApi setPrivateDnsServerName(@ullable String privateDnsServerName)460 public void setPrivateDnsServerName(@Nullable String privateDnsServerName) { 461 mPrivateDnsServerName = privateDnsServerName; 462 } 463 464 /** 465 * Set DHCP server address. 466 * 467 * @param serverAddress the server address to set. 468 */ setDhcpServerAddress(@ullable Inet4Address serverAddress)469 public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) { 470 mDhcpServerAddress = serverAddress; 471 } 472 473 /** 474 * Get DHCP server address 475 * 476 * @return The current DHCP server address. 477 */ getDhcpServerAddress()478 public @Nullable Inet4Address getDhcpServerAddress() { 479 return mDhcpServerAddress; 480 } 481 482 /** 483 * Returns the private DNS server name that is in use. If not {@code null}, 484 * private DNS is in strict mode. In this mode, applications should ensure 485 * that all DNS queries are encrypted and sent to this hostname and that 486 * queries are only sent if the hostname's certificate is valid. If 487 * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private 488 * DNS is in opportunistic mode, and applications should ensure that DNS 489 * queries are encrypted and sent to a DNS server returned by 490 * {@link #getDnsServers}. System DNS will handle each of these cases 491 * correctly, but applications implementing their own DNS lookups must make 492 * sure to follow these requirements. 493 * 494 * @return The private DNS server name. 495 */ getPrivateDnsServerName()496 public @Nullable String getPrivateDnsServerName() { 497 return mPrivateDnsServerName; 498 } 499 500 /** 501 * Adds the given {@link InetAddress} to the list of validated private DNS servers, 502 * if not present. This is distinct from the server name in that these are actually 503 * resolved addresses. 504 * 505 * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers. 506 * @return true if the DNS server was added, false if it was already present. 507 * @hide 508 */ addValidatedPrivateDnsServer(@onNull InetAddress dnsServer)509 public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) { 510 if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) { 511 mValidatedPrivateDnses.add(dnsServer); 512 return true; 513 } 514 return false; 515 } 516 517 /** 518 * Removes the given {@link InetAddress} from the list of validated private DNS servers. 519 * 520 * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS 521 * servers. 522 * @return true if the DNS server was removed, false if it did not exist. 523 * @hide 524 */ removeValidatedPrivateDnsServer(@onNull InetAddress dnsServer)525 public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) { 526 return mValidatedPrivateDnses.remove(dnsServer); 527 } 528 529 /** 530 * Replaces the validated private DNS servers in this {@code LinkProperties} with 531 * the given {@link Collection} of {@link InetAddress} objects. 532 * 533 * @param dnsServers The {@link Collection} of validated private DNS servers to set in this 534 * object. 535 * @hide 536 */ 537 @TestApi 538 @SystemApi setValidatedPrivateDnsServers(@onNull Collection<InetAddress> dnsServers)539 public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) { 540 mValidatedPrivateDnses.clear(); 541 for (InetAddress dnsServer: dnsServers) { 542 addValidatedPrivateDnsServer(dnsServer); 543 } 544 } 545 546 /** 547 * Returns all the {@link InetAddress} for validated private DNS servers on this link. 548 * These are resolved from the private DNS server name. 549 * 550 * @return An unmodifiable {@link List} of {@link InetAddress} for validated private 551 * DNS servers on this link. 552 * @hide 553 */ 554 @TestApi 555 @SystemApi getValidatedPrivateDnsServers()556 public @NonNull List<InetAddress> getValidatedPrivateDnsServers() { 557 return Collections.unmodifiableList(mValidatedPrivateDnses); 558 } 559 560 /** 561 * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present. 562 * 563 * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers. 564 * @return true if the PCSCF server was added, false otherwise. 565 * @hide 566 */ 567 @SystemApi addPcscfServer(@onNull InetAddress pcscfServer)568 public boolean addPcscfServer(@NonNull InetAddress pcscfServer) { 569 if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) { 570 mPcscfs.add(pcscfServer); 571 return true; 572 } 573 return false; 574 } 575 576 /** 577 * Removes the given {@link InetAddress} from the list of PCSCF servers. 578 * 579 * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers. 580 * @return true if the PCSCF server was removed, false otherwise. 581 * @hide 582 */ removePcscfServer(@onNull InetAddress pcscfServer)583 public boolean removePcscfServer(@NonNull InetAddress pcscfServer) { 584 return mPcscfs.remove(pcscfServer); 585 } 586 587 /** 588 * Replaces the PCSCF servers in this {@code LinkProperties} with 589 * the given {@link Collection} of {@link InetAddress} objects. 590 * 591 * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object. 592 * @hide 593 */ 594 @SystemApi 595 @TestApi setPcscfServers(@onNull Collection<InetAddress> pcscfServers)596 public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) { 597 mPcscfs.clear(); 598 for (InetAddress pcscfServer: pcscfServers) { 599 addPcscfServer(pcscfServer); 600 } 601 } 602 603 /** 604 * Returns all the {@link InetAddress} for PCSCF servers on this link. 605 * 606 * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on 607 * this link. 608 * @hide 609 */ 610 @SystemApi 611 @TestApi getPcscfServers()612 public @NonNull List<InetAddress> getPcscfServers() { 613 return Collections.unmodifiableList(mPcscfs); 614 } 615 616 /** 617 * Sets the DNS domain search path used on this link. 618 * 619 * @param domains A {@link String} listing in priority order the comma separated 620 * domains to search when resolving host names on this link. 621 */ setDomains(@ullable String domains)622 public void setDomains(@Nullable String domains) { 623 mDomains = domains; 624 } 625 626 /** 627 * Get the DNS domains search path set for this link. May be {@code null} if not set. 628 * 629 * @return A {@link String} containing the comma separated domains to search when resolving host 630 * names on this link or {@code null}. 631 */ getDomains()632 public @Nullable String getDomains() { 633 return mDomains; 634 } 635 636 /** 637 * Sets the Maximum Transmission Unit size to use on this link. This should not be used 638 * unless the system default (1500) is incorrect. Values less than 68 or greater than 639 * 10000 will be ignored. 640 * 641 * @param mtu The MTU to use for this link. 642 */ setMtu(int mtu)643 public void setMtu(int mtu) { 644 mMtu = mtu; 645 } 646 647 /** 648 * Gets any non-default MTU size set for this link. Note that if the default is being used 649 * this will return 0. 650 * 651 * @return The mtu value set for this link. 652 */ getMtu()653 public int getMtu() { 654 return mMtu; 655 } 656 657 /** 658 * Sets the tcp buffers sizes to be used when this link is the system default. 659 * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max". 660 * 661 * @param tcpBufferSizes The tcp buffers sizes to use. 662 * 663 * @hide 664 */ 665 @TestApi 666 @SystemApi setTcpBufferSizes(@ullable String tcpBufferSizes)667 public void setTcpBufferSizes(@Nullable String tcpBufferSizes) { 668 mTcpBufferSizes = tcpBufferSizes; 669 } 670 671 /** 672 * Gets the tcp buffer sizes. May be {@code null} if not set. 673 * 674 * @return the tcp buffer sizes to use when this link is the system default or {@code null}. 675 * 676 * @hide 677 */ 678 @TestApi 679 @SystemApi getTcpBufferSizes()680 public @Nullable String getTcpBufferSizes() { 681 return mTcpBufferSizes; 682 } 683 routeWithInterface(RouteInfo route)684 private RouteInfo routeWithInterface(RouteInfo route) { 685 return new RouteInfo( 686 route.getDestination(), 687 route.getGateway(), 688 mIfaceName, 689 route.getType(), 690 route.getMtu()); 691 } 692 findRouteIndexByRouteKey(RouteInfo route)693 private int findRouteIndexByRouteKey(RouteInfo route) { 694 for (int i = 0; i < mRoutes.size(); i++) { 695 if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) { 696 return i; 697 } 698 } 699 return -1; 700 } 701 702 /** 703 * Adds a {@link RouteInfo} to this {@code LinkProperties}, if a {@link RouteInfo} 704 * with the same {@link RouteInfo.RouteKey} with different properties 705 * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an 706 * interface name set and that differs from the interface set for this 707 * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. 708 * The proper course is to add either un-named or properly named {@link RouteInfo}. 709 * 710 * @param route A {@link RouteInfo} to add to this object. 711 * @return {@code true} was added or updated, false otherwise. 712 */ addRoute(@onNull RouteInfo route)713 public boolean addRoute(@NonNull RouteInfo route) { 714 String routeIface = route.getInterface(); 715 if (routeIface != null && !routeIface.equals(mIfaceName)) { 716 throw new IllegalArgumentException( 717 "Route added with non-matching interface: " + routeIface 718 + " vs. " + mIfaceName); 719 } 720 route = routeWithInterface(route); 721 722 int i = findRouteIndexByRouteKey(route); 723 if (i == -1) { 724 // Route was not present. Add it. 725 mRoutes.add(route); 726 return true; 727 } else if (mRoutes.get(i).equals(route)) { 728 // Route was present and has same properties. Do nothing. 729 return false; 730 } else { 731 // Route was present and has different properties. Update it. 732 mRoutes.set(i, route); 733 return true; 734 } 735 } 736 737 /** 738 * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must 739 * specify an interface and the interface must match the interface of this 740 * {@code LinkProperties}, or it will not be removed. 741 * 742 * @param route A {@link RouteInfo} specifying the route to remove. 743 * @return {@code true} if the route was removed, {@code false} if it was not present. 744 * 745 * @hide 746 */ 747 @TestApi 748 @SystemApi removeRoute(@onNull RouteInfo route)749 public boolean removeRoute(@NonNull RouteInfo route) { 750 return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route); 751 } 752 753 /** 754 * Returns all the {@link RouteInfo} set on this link. 755 * 756 * @return An unmodifiable {@link List} of {@link RouteInfo} for this link. 757 */ getRoutes()758 public @NonNull List<RouteInfo> getRoutes() { 759 return Collections.unmodifiableList(mRoutes); 760 } 761 762 /** 763 * Make sure this LinkProperties instance contains routes that cover the local subnet 764 * of its link addresses. Add any route that is missing. 765 * @hide 766 */ ensureDirectlyConnectedRoutes()767 public void ensureDirectlyConnectedRoutes() { 768 for (LinkAddress addr : mLinkAddresses) { 769 addRoute(new RouteInfo(addr, null, mIfaceName)); 770 } 771 } 772 773 /** 774 * Returns all the routes on this link and all the links stacked above it. 775 * @hide 776 */ 777 @SystemApi getAllRoutes()778 public @NonNull List<RouteInfo> getAllRoutes() { 779 List<RouteInfo> routes = new ArrayList<>(mRoutes); 780 for (LinkProperties stacked: mStackedLinks.values()) { 781 routes.addAll(stacked.getAllRoutes()); 782 } 783 return routes; 784 } 785 786 /** 787 * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none. 788 * Note that Http Proxies are only a hint - the system recommends their use, but it does 789 * not enforce it and applications may ignore them. 790 * 791 * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link. 792 */ setHttpProxy(@ullable ProxyInfo proxy)793 public void setHttpProxy(@Nullable ProxyInfo proxy) { 794 mHttpProxy = proxy; 795 } 796 797 /** 798 * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link. 799 * 800 * @return The {@link ProxyInfo} set on this link or {@code null}. 801 */ getHttpProxy()802 public @Nullable ProxyInfo getHttpProxy() { 803 return mHttpProxy; 804 } 805 806 /** 807 * Returns the NAT64 prefix in use on this link, if any. 808 * 809 * @return the NAT64 prefix or {@code null}. 810 */ getNat64Prefix()811 public @Nullable IpPrefix getNat64Prefix() { 812 return mNat64Prefix; 813 } 814 815 /** 816 * Sets the NAT64 prefix in use on this link. 817 * 818 * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the 819 * 128-bit IPv6 address) are supported or {@code null} for no prefix. 820 * 821 * @param prefix the NAT64 prefix. 822 */ setNat64Prefix(@ullable IpPrefix prefix)823 public void setNat64Prefix(@Nullable IpPrefix prefix) { 824 if (prefix != null && prefix.getPrefixLength() != 96) { 825 throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix); 826 } 827 mNat64Prefix = prefix; // IpPrefix objects are immutable. 828 } 829 830 /** 831 * Adds a stacked link. 832 * 833 * If there is already a stacked link with the same interface name as link, 834 * that link is replaced with link. Otherwise, link is added to the list 835 * of stacked links. 836 * 837 * @param link The link to add. 838 * @return true if the link was stacked, false otherwise. 839 * @hide 840 */ 841 @UnsupportedAppUsage addStackedLink(@onNull LinkProperties link)842 public boolean addStackedLink(@NonNull LinkProperties link) { 843 if (link.getInterfaceName() != null) { 844 mStackedLinks.put(link.getInterfaceName(), link); 845 return true; 846 } 847 return false; 848 } 849 850 /** 851 * Removes a stacked link. 852 * 853 * If there is a stacked link with the given interface name, it is 854 * removed. Otherwise, nothing changes. 855 * 856 * @param iface The interface name of the link to remove. 857 * @return true if the link was removed, false otherwise. 858 * @hide 859 */ removeStackedLink(@onNull String iface)860 public boolean removeStackedLink(@NonNull String iface) { 861 LinkProperties removed = mStackedLinks.remove(iface); 862 return removed != null; 863 } 864 865 /** 866 * Returns all the links stacked on top of this link. 867 * @hide 868 */ 869 @UnsupportedAppUsage getStackedLinks()870 public @NonNull List<LinkProperties> getStackedLinks() { 871 if (mStackedLinks.isEmpty()) { 872 return Collections.emptyList(); 873 } 874 final List<LinkProperties> stacked = new ArrayList<>(); 875 for (LinkProperties link : mStackedLinks.values()) { 876 stacked.add(new LinkProperties(link)); 877 } 878 return Collections.unmodifiableList(stacked); 879 } 880 881 /** 882 * Clears this object to its initial state. 883 */ clear()884 public void clear() { 885 if (mParcelSensitiveFields) { 886 throw new UnsupportedOperationException( 887 "Cannot clear LinkProperties when parcelSensitiveFields is set"); 888 } 889 890 mIfaceName = null; 891 mLinkAddresses.clear(); 892 mDnses.clear(); 893 mUsePrivateDns = false; 894 mPrivateDnsServerName = null; 895 mPcscfs.clear(); 896 mDomains = null; 897 mRoutes.clear(); 898 mHttpProxy = null; 899 mStackedLinks.clear(); 900 mMtu = 0; 901 mDhcpServerAddress = null; 902 mTcpBufferSizes = null; 903 mNat64Prefix = null; 904 mWakeOnLanSupported = false; 905 mCaptivePortalApiUrl = null; 906 mCaptivePortalData = null; 907 } 908 909 /** 910 * Implement the Parcelable interface 911 */ describeContents()912 public int describeContents() { 913 return 0; 914 } 915 916 @Override toString()917 public String toString() { 918 // Space as a separator, so no need for spaces at start/end of the individual fragments. 919 final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}"); 920 921 if (mIfaceName != null) { 922 resultJoiner.add("InterfaceName:"); 923 resultJoiner.add(mIfaceName); 924 } 925 926 resultJoiner.add("LinkAddresses: ["); 927 if (!mLinkAddresses.isEmpty()) { 928 resultJoiner.add(TextUtils.join(",", mLinkAddresses)); 929 } 930 resultJoiner.add("]"); 931 932 resultJoiner.add("DnsAddresses: ["); 933 if (!mDnses.isEmpty()) { 934 resultJoiner.add(TextUtils.join(",", mDnses)); 935 } 936 resultJoiner.add("]"); 937 938 if (mUsePrivateDns) { 939 resultJoiner.add("UsePrivateDns: true"); 940 } 941 942 if (mPrivateDnsServerName != null) { 943 resultJoiner.add("PrivateDnsServerName:"); 944 resultJoiner.add(mPrivateDnsServerName); 945 } 946 947 if (!mPcscfs.isEmpty()) { 948 resultJoiner.add("PcscfAddresses: ["); 949 resultJoiner.add(TextUtils.join(",", mPcscfs)); 950 resultJoiner.add("]"); 951 } 952 953 if (!mValidatedPrivateDnses.isEmpty()) { 954 final StringJoiner validatedPrivateDnsesJoiner = 955 new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]"); 956 for (final InetAddress addr : mValidatedPrivateDnses) { 957 validatedPrivateDnsesJoiner.add(addr.getHostAddress()); 958 } 959 resultJoiner.add(validatedPrivateDnsesJoiner.toString()); 960 } 961 962 resultJoiner.add("Domains:"); 963 resultJoiner.add(mDomains); 964 965 resultJoiner.add("MTU:"); 966 resultJoiner.add(Integer.toString(mMtu)); 967 968 if (mWakeOnLanSupported) { 969 resultJoiner.add("WakeOnLanSupported: true"); 970 } 971 972 if (mDhcpServerAddress != null) { 973 resultJoiner.add("ServerAddress:"); 974 resultJoiner.add(mDhcpServerAddress.toString()); 975 } 976 977 if (mCaptivePortalApiUrl != null) { 978 resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl); 979 } 980 981 if (mCaptivePortalData != null) { 982 resultJoiner.add("CaptivePortalData: " + mCaptivePortalData); 983 } 984 985 if (mTcpBufferSizes != null) { 986 resultJoiner.add("TcpBufferSizes:"); 987 resultJoiner.add(mTcpBufferSizes); 988 } 989 990 resultJoiner.add("Routes: ["); 991 if (!mRoutes.isEmpty()) { 992 resultJoiner.add(TextUtils.join(",", mRoutes)); 993 } 994 resultJoiner.add("]"); 995 996 if (mHttpProxy != null) { 997 resultJoiner.add("HttpProxy:"); 998 resultJoiner.add(mHttpProxy.toString()); 999 } 1000 1001 if (mNat64Prefix != null) { 1002 resultJoiner.add("Nat64Prefix:"); 1003 resultJoiner.add(mNat64Prefix.toString()); 1004 } 1005 1006 final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values(); 1007 if (!stackedLinksValues.isEmpty()) { 1008 final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]"); 1009 for (final LinkProperties lp : stackedLinksValues) { 1010 stackedLinksJoiner.add("[ " + lp + " ]"); 1011 } 1012 resultJoiner.add(stackedLinksJoiner.toString()); 1013 } 1014 1015 return resultJoiner.toString(); 1016 } 1017 1018 /** 1019 * Returns true if this link has an IPv4 address. 1020 * 1021 * @return {@code true} if there is an IPv4 address, {@code false} otherwise. 1022 * @hide 1023 */ 1024 @TestApi 1025 @SystemApi hasIpv4Address()1026 public boolean hasIpv4Address() { 1027 for (LinkAddress address : mLinkAddresses) { 1028 if (address.getAddress() instanceof Inet4Address) { 1029 return true; 1030 } 1031 } 1032 return false; 1033 } 1034 1035 /** 1036 * For backward compatibility. 1037 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 1038 * just yet. 1039 * @return {@code true} if there is an IPv4 address, {@code false} otherwise. 1040 * @hide 1041 */ 1042 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) hasIPv4Address()1043 public boolean hasIPv4Address() { 1044 return hasIpv4Address(); 1045 } 1046 1047 /** 1048 * Returns true if this link or any of its stacked interfaces has an IPv4 address. 1049 * 1050 * @return {@code true} if there is an IPv4 address, {@code false} otherwise. 1051 */ hasIpv4AddressOnInterface(String iface)1052 private boolean hasIpv4AddressOnInterface(String iface) { 1053 // mIfaceName can be null. 1054 return (Objects.equals(iface, mIfaceName) && hasIpv4Address()) 1055 || (iface != null && mStackedLinks.containsKey(iface) 1056 && mStackedLinks.get(iface).hasIpv4Address()); 1057 } 1058 1059 /** 1060 * Returns true if this link has a global preferred IPv6 address. 1061 * 1062 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. 1063 * @hide 1064 */ 1065 @TestApi 1066 @SystemApi hasGlobalIpv6Address()1067 public boolean hasGlobalIpv6Address() { 1068 for (LinkAddress address : mLinkAddresses) { 1069 if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) { 1070 return true; 1071 } 1072 } 1073 return false; 1074 } 1075 1076 /** 1077 * Returns true if this link has an IPv4 unreachable default route. 1078 * 1079 * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise. 1080 * @hide 1081 */ hasIpv4UnreachableDefaultRoute()1082 public boolean hasIpv4UnreachableDefaultRoute() { 1083 for (RouteInfo r : mRoutes) { 1084 if (r.isIPv4UnreachableDefault()) { 1085 return true; 1086 } 1087 } 1088 return false; 1089 } 1090 1091 /** 1092 * For backward compatibility. 1093 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 1094 * just yet. 1095 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. 1096 * @hide 1097 */ 1098 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) hasGlobalIPv6Address()1099 public boolean hasGlobalIPv6Address() { 1100 return hasGlobalIpv6Address(); 1101 } 1102 1103 /** 1104 * Returns true if this link has an IPv4 default route. 1105 * 1106 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. 1107 * @hide 1108 */ 1109 @SystemApi hasIpv4DefaultRoute()1110 public boolean hasIpv4DefaultRoute() { 1111 for (RouteInfo r : mRoutes) { 1112 if (r.isIPv4Default()) { 1113 return true; 1114 } 1115 } 1116 return false; 1117 } 1118 1119 /** 1120 * Returns true if this link has an IPv6 unreachable default route. 1121 * 1122 * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise. 1123 * @hide 1124 */ hasIpv6UnreachableDefaultRoute()1125 public boolean hasIpv6UnreachableDefaultRoute() { 1126 for (RouteInfo r : mRoutes) { 1127 if (r.isIPv6UnreachableDefault()) { 1128 return true; 1129 } 1130 } 1131 return false; 1132 } 1133 1134 /** 1135 * For backward compatibility. 1136 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 1137 * just yet. 1138 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. 1139 * @hide 1140 */ 1141 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) hasIPv4DefaultRoute()1142 public boolean hasIPv4DefaultRoute() { 1143 return hasIpv4DefaultRoute(); 1144 } 1145 1146 /** 1147 * Returns true if this link has an IPv6 default route. 1148 * 1149 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. 1150 * @hide 1151 */ 1152 @TestApi 1153 @SystemApi hasIpv6DefaultRoute()1154 public boolean hasIpv6DefaultRoute() { 1155 for (RouteInfo r : mRoutes) { 1156 if (r.isIPv6Default()) { 1157 return true; 1158 } 1159 } 1160 return false; 1161 } 1162 1163 /** 1164 * For backward compatibility. 1165 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 1166 * just yet. 1167 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. 1168 * @hide 1169 */ 1170 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) hasIPv6DefaultRoute()1171 public boolean hasIPv6DefaultRoute() { 1172 return hasIpv6DefaultRoute(); 1173 } 1174 1175 /** 1176 * Returns true if this link has an IPv4 DNS server. 1177 * 1178 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. 1179 * @hide 1180 */ 1181 @SystemApi hasIpv4DnsServer()1182 public boolean hasIpv4DnsServer() { 1183 for (InetAddress ia : mDnses) { 1184 if (ia instanceof Inet4Address) { 1185 return true; 1186 } 1187 } 1188 return false; 1189 } 1190 1191 /** 1192 * For backward compatibility. 1193 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 1194 * just yet. 1195 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. 1196 * @hide 1197 */ 1198 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) hasIPv4DnsServer()1199 public boolean hasIPv4DnsServer() { 1200 return hasIpv4DnsServer(); 1201 } 1202 1203 /** 1204 * Returns true if this link has an IPv6 DNS server. 1205 * 1206 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. 1207 * @hide 1208 */ 1209 @SystemApi hasIpv6DnsServer()1210 public boolean hasIpv6DnsServer() { 1211 for (InetAddress ia : mDnses) { 1212 if (ia instanceof Inet6Address) { 1213 return true; 1214 } 1215 } 1216 return false; 1217 } 1218 1219 /** 1220 * For backward compatibility. 1221 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 1222 * just yet. 1223 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. 1224 * @hide 1225 */ 1226 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) hasIPv6DnsServer()1227 public boolean hasIPv6DnsServer() { 1228 return hasIpv6DnsServer(); 1229 } 1230 1231 /** 1232 * Returns true if this link has an IPv4 PCSCF server. 1233 * 1234 * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise. 1235 * @hide 1236 */ hasIpv4PcscfServer()1237 public boolean hasIpv4PcscfServer() { 1238 for (InetAddress ia : mPcscfs) { 1239 if (ia instanceof Inet4Address) { 1240 return true; 1241 } 1242 } 1243 return false; 1244 } 1245 1246 /** 1247 * Returns true if this link has an IPv6 PCSCF server. 1248 * 1249 * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise. 1250 * @hide 1251 */ hasIpv6PcscfServer()1252 public boolean hasIpv6PcscfServer() { 1253 for (InetAddress ia : mPcscfs) { 1254 if (ia instanceof Inet6Address) { 1255 return true; 1256 } 1257 } 1258 return false; 1259 } 1260 1261 /** 1262 * Returns true if this link is provisioned for global IPv4 connectivity. 1263 * This requires an IP address, default route, and DNS server. 1264 * 1265 * @return {@code true} if the link is provisioned, {@code false} otherwise. 1266 * @hide 1267 */ 1268 @TestApi 1269 @SystemApi isIpv4Provisioned()1270 public boolean isIpv4Provisioned() { 1271 return (hasIpv4Address() 1272 && hasIpv4DefaultRoute() 1273 && hasIpv4DnsServer()); 1274 } 1275 1276 /** 1277 * Returns true if this link is provisioned for global IPv6 connectivity. 1278 * This requires an IP address, default route, and DNS server. 1279 * 1280 * @return {@code true} if the link is provisioned, {@code false} otherwise. 1281 * @hide 1282 */ 1283 @TestApi 1284 @SystemApi isIpv6Provisioned()1285 public boolean isIpv6Provisioned() { 1286 return (hasGlobalIpv6Address() 1287 && hasIpv6DefaultRoute() 1288 && hasIpv6DnsServer()); 1289 } 1290 1291 /** 1292 * For backward compatibility. 1293 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 1294 * just yet. 1295 * @return {@code true} if the link is provisioned, {@code false} otherwise. 1296 * @hide 1297 */ 1298 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) isIPv6Provisioned()1299 public boolean isIPv6Provisioned() { 1300 return isIpv6Provisioned(); 1301 } 1302 1303 1304 /** 1305 * Returns true if this link is provisioned for global connectivity, 1306 * for at least one Internet Protocol family. 1307 * 1308 * @return {@code true} if the link is provisioned, {@code false} otherwise. 1309 * @hide 1310 */ 1311 @TestApi 1312 @SystemApi isProvisioned()1313 public boolean isProvisioned() { 1314 return (isIpv4Provisioned() || isIpv6Provisioned()); 1315 } 1316 1317 /** 1318 * Evaluate whether the {@link InetAddress} is considered reachable. 1319 * 1320 * @return {@code true} if the given {@link InetAddress} is considered reachable, 1321 * {@code false} otherwise. 1322 * @hide 1323 */ 1324 @TestApi 1325 @SystemApi isReachable(@onNull InetAddress ip)1326 public boolean isReachable(@NonNull InetAddress ip) { 1327 final List<RouteInfo> allRoutes = getAllRoutes(); 1328 // If we don't have a route to this IP address, it's not reachable. 1329 final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip); 1330 if (bestRoute == null) { 1331 return false; 1332 } 1333 1334 // TODO: better source address evaluation for destination addresses. 1335 1336 if (ip instanceof Inet4Address) { 1337 // For IPv4, it suffices for now to simply have any address. 1338 return hasIpv4AddressOnInterface(bestRoute.getInterface()); 1339 } else if (ip instanceof Inet6Address) { 1340 if (ip.isLinkLocalAddress()) { 1341 // For now, just make sure link-local destinations have 1342 // scopedIds set, since transmits will generally fail otherwise. 1343 // TODO: verify it matches the ifindex of one of the interfaces. 1344 return (((Inet6Address)ip).getScopeId() != 0); 1345 } else { 1346 // For non-link-local destinations check that either the best route 1347 // is directly connected or that some global preferred address exists. 1348 // TODO: reconsider all cases (disconnected ULA networks, ...). 1349 return (!bestRoute.hasGateway() || hasGlobalIpv6Address()); 1350 } 1351 } 1352 1353 return false; 1354 } 1355 1356 /** 1357 * Compares this {@code LinkProperties} interface name against the target 1358 * 1359 * @param target LinkProperties to compare. 1360 * @return {@code true} if both are identical, {@code false} otherwise. 1361 * @hide 1362 */ 1363 @UnsupportedAppUsage isIdenticalInterfaceName(@onNull LinkProperties target)1364 public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) { 1365 return LinkPropertiesUtils.isIdenticalInterfaceName(target, this); 1366 } 1367 1368 /** 1369 * Compares this {@code LinkProperties} DHCP server address against the target 1370 * 1371 * @param target LinkProperties to compare. 1372 * @return {@code true} if both are identical, {@code false} otherwise. 1373 * @hide 1374 */ isIdenticalDhcpServerAddress(@onNull LinkProperties target)1375 public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) { 1376 return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress); 1377 } 1378 1379 /** 1380 * Compares this {@code LinkProperties} interface addresses against the target 1381 * 1382 * @param target LinkProperties to compare. 1383 * @return {@code true} if both are identical, {@code false} otherwise. 1384 * @hide 1385 */ 1386 @UnsupportedAppUsage isIdenticalAddresses(@onNull LinkProperties target)1387 public boolean isIdenticalAddresses(@NonNull LinkProperties target) { 1388 return LinkPropertiesUtils.isIdenticalAddresses(target, this); 1389 } 1390 1391 /** 1392 * Compares this {@code LinkProperties} DNS addresses against the target 1393 * 1394 * @param target LinkProperties to compare. 1395 * @return {@code true} if both are identical, {@code false} otherwise. 1396 * @hide 1397 */ 1398 @UnsupportedAppUsage isIdenticalDnses(@onNull LinkProperties target)1399 public boolean isIdenticalDnses(@NonNull LinkProperties target) { 1400 return LinkPropertiesUtils.isIdenticalDnses(target, this); 1401 } 1402 1403 /** 1404 * Compares this {@code LinkProperties} private DNS settings against the 1405 * target. 1406 * 1407 * @param target LinkProperties to compare. 1408 * @return {@code true} if both are identical, {@code false} otherwise. 1409 * @hide 1410 */ isIdenticalPrivateDns(@onNull LinkProperties target)1411 public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) { 1412 return (isPrivateDnsActive() == target.isPrivateDnsActive() 1413 && TextUtils.equals(getPrivateDnsServerName(), 1414 target.getPrivateDnsServerName())); 1415 } 1416 1417 /** 1418 * Compares this {@code LinkProperties} validated private DNS addresses against 1419 * the target 1420 * 1421 * @param target LinkProperties to compare. 1422 * @return {@code true} if both are identical, {@code false} otherwise. 1423 * @hide 1424 */ isIdenticalValidatedPrivateDnses(@onNull LinkProperties target)1425 public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) { 1426 Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers(); 1427 return (mValidatedPrivateDnses.size() == targetDnses.size()) 1428 ? mValidatedPrivateDnses.containsAll(targetDnses) : false; 1429 } 1430 1431 /** 1432 * Compares this {@code LinkProperties} PCSCF addresses against the target 1433 * 1434 * @param target LinkProperties to compare. 1435 * @return {@code true} if both are identical, {@code false} otherwise. 1436 * @hide 1437 */ isIdenticalPcscfs(@onNull LinkProperties target)1438 public boolean isIdenticalPcscfs(@NonNull LinkProperties target) { 1439 Collection<InetAddress> targetPcscfs = target.getPcscfServers(); 1440 return (mPcscfs.size() == targetPcscfs.size()) ? 1441 mPcscfs.containsAll(targetPcscfs) : false; 1442 } 1443 1444 /** 1445 * Compares this {@code LinkProperties} Routes against the target 1446 * 1447 * @param target LinkProperties to compare. 1448 * @return {@code true} if both are identical, {@code false} otherwise. 1449 * @hide 1450 */ 1451 @UnsupportedAppUsage isIdenticalRoutes(@onNull LinkProperties target)1452 public boolean isIdenticalRoutes(@NonNull LinkProperties target) { 1453 return LinkPropertiesUtils.isIdenticalRoutes(target, this); 1454 } 1455 1456 /** 1457 * Compares this {@code LinkProperties} HttpProxy against the target 1458 * 1459 * @param target LinkProperties to compare. 1460 * @return {@code true} if both are identical, {@code false} otherwise. 1461 * @hide 1462 */ 1463 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) isIdenticalHttpProxy(@onNull LinkProperties target)1464 public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) { 1465 return LinkPropertiesUtils.isIdenticalHttpProxy(target, this); 1466 } 1467 1468 /** 1469 * Compares this {@code LinkProperties} stacked links against the target 1470 * 1471 * @param target LinkProperties to compare. 1472 * @return {@code true} if both are identical, {@code false} otherwise. 1473 * @hide 1474 */ 1475 @UnsupportedAppUsage isIdenticalStackedLinks(@onNull LinkProperties target)1476 public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) { 1477 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { 1478 return false; 1479 } 1480 for (LinkProperties stacked : mStackedLinks.values()) { 1481 // Hashtable values can never be null. 1482 String iface = stacked.getInterfaceName(); 1483 if (!stacked.equals(target.mStackedLinks.get(iface))) { 1484 return false; 1485 } 1486 } 1487 return true; 1488 } 1489 1490 /** 1491 * Compares this {@code LinkProperties} MTU against the target 1492 * 1493 * @param target LinkProperties to compare. 1494 * @return {@code true} if both are identical, {@code false} otherwise. 1495 * @hide 1496 */ isIdenticalMtu(@onNull LinkProperties target)1497 public boolean isIdenticalMtu(@NonNull LinkProperties target) { 1498 return getMtu() == target.getMtu(); 1499 } 1500 1501 /** 1502 * Compares this {@code LinkProperties} Tcp buffer sizes against the target. 1503 * 1504 * @param target LinkProperties to compare. 1505 * @return {@code true} if both are identical, {@code false} otherwise. 1506 * @hide 1507 */ isIdenticalTcpBufferSizes(@onNull LinkProperties target)1508 public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) { 1509 return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes); 1510 } 1511 1512 /** 1513 * Compares this {@code LinkProperties} NAT64 prefix against the target. 1514 * 1515 * @param target LinkProperties to compare. 1516 * @return {@code true} if both are identical, {@code false} otherwise. 1517 * @hide 1518 */ isIdenticalNat64Prefix(@onNull LinkProperties target)1519 public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) { 1520 return Objects.equals(mNat64Prefix, target.mNat64Prefix); 1521 } 1522 1523 /** 1524 * Compares this {@code LinkProperties} WakeOnLan supported against the target. 1525 * 1526 * @param target LinkProperties to compare. 1527 * @return {@code true} if both are identical, {@code false} otherwise. 1528 * @hide 1529 */ isIdenticalWakeOnLan(LinkProperties target)1530 public boolean isIdenticalWakeOnLan(LinkProperties target) { 1531 return isWakeOnLanSupported() == target.isWakeOnLanSupported(); 1532 } 1533 1534 /** 1535 * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target. 1536 * 1537 * @param target LinkProperties to compare. 1538 * @return {@code true} if both are identical, {@code false} otherwise. 1539 * @hide 1540 */ isIdenticalCaptivePortalApiUrl(LinkProperties target)1541 public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) { 1542 return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl); 1543 } 1544 1545 /** 1546 * Compares this {@code LinkProperties}'s CaptivePortalData against the target. 1547 * 1548 * @param target LinkProperties to compare. 1549 * @return {@code true} if both are identical, {@code false} otherwise. 1550 * @hide 1551 */ isIdenticalCaptivePortalData(LinkProperties target)1552 public boolean isIdenticalCaptivePortalData(LinkProperties target) { 1553 return Objects.equals(mCaptivePortalData, target.mCaptivePortalData); 1554 } 1555 1556 /** 1557 * Set whether the network interface supports WakeOnLAN 1558 * 1559 * @param supported WakeOnLAN supported value 1560 * 1561 * @hide 1562 */ setWakeOnLanSupported(boolean supported)1563 public void setWakeOnLanSupported(boolean supported) { 1564 mWakeOnLanSupported = supported; 1565 } 1566 1567 /** 1568 * Returns whether the network interface supports WakeOnLAN 1569 * 1570 * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise. 1571 */ isWakeOnLanSupported()1572 public boolean isWakeOnLanSupported() { 1573 return mWakeOnLanSupported; 1574 } 1575 1576 /** 1577 * Set the URL of the captive portal API endpoint to get more information about the network. 1578 * @hide 1579 */ 1580 @SystemApi 1581 @TestApi setCaptivePortalApiUrl(@ullable Uri url)1582 public void setCaptivePortalApiUrl(@Nullable Uri url) { 1583 mCaptivePortalApiUrl = url; 1584 } 1585 1586 /** 1587 * Get the URL of the captive portal API endpoint to get more information about the network. 1588 * 1589 * <p>This is null unless the application has 1590 * {@link android.Manifest.permission.NETWORK_SETTINGS} or 1591 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided 1592 * the URL. 1593 * @hide 1594 */ 1595 @SystemApi 1596 @TestApi 1597 @Nullable getCaptivePortalApiUrl()1598 public Uri getCaptivePortalApiUrl() { 1599 return mCaptivePortalApiUrl; 1600 } 1601 1602 /** 1603 * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis). 1604 * @hide 1605 */ 1606 @SystemApi 1607 @TestApi setCaptivePortalData(@ullable CaptivePortalData data)1608 public void setCaptivePortalData(@Nullable CaptivePortalData data) { 1609 mCaptivePortalData = data; 1610 } 1611 1612 /** 1613 * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis). 1614 * 1615 * <p>This is null unless the application has 1616 * {@link android.Manifest.permission.NETWORK_SETTINGS} or 1617 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions. 1618 * @hide 1619 */ 1620 @SystemApi 1621 @TestApi 1622 @Nullable getCaptivePortalData()1623 public CaptivePortalData getCaptivePortalData() { 1624 return mCaptivePortalData; 1625 } 1626 1627 /** 1628 * Compares this {@code LinkProperties} instance against the target 1629 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if 1630 * all their fields are equal in values. 1631 * 1632 * For collection fields, such as mDnses, containsAll() is used to check 1633 * if two collections contains the same elements, independent of order. 1634 * There are two thoughts regarding containsAll() 1635 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. 1636 * 2. Worst case performance is O(n^2). 1637 * 1638 * @param obj the object to be tested for equality. 1639 * @return {@code true} if both objects are equal, {@code false} otherwise. 1640 */ 1641 @Override equals(Object obj)1642 public boolean equals(Object obj) { 1643 if (this == obj) return true; 1644 1645 if (!(obj instanceof LinkProperties)) return false; 1646 1647 LinkProperties target = (LinkProperties) obj; 1648 /* 1649 * This method does not check that stacked interfaces are equal, because 1650 * stacked interfaces are not so much a property of the link as a 1651 * description of connections between links. 1652 */ 1653 return isIdenticalInterfaceName(target) 1654 && isIdenticalAddresses(target) 1655 && isIdenticalDhcpServerAddress(target) 1656 && isIdenticalDnses(target) 1657 && isIdenticalPrivateDns(target) 1658 && isIdenticalValidatedPrivateDnses(target) 1659 && isIdenticalPcscfs(target) 1660 && isIdenticalRoutes(target) 1661 && isIdenticalHttpProxy(target) 1662 && isIdenticalStackedLinks(target) 1663 && isIdenticalMtu(target) 1664 && isIdenticalTcpBufferSizes(target) 1665 && isIdenticalNat64Prefix(target) 1666 && isIdenticalWakeOnLan(target) 1667 && isIdenticalCaptivePortalApiUrl(target) 1668 && isIdenticalCaptivePortalData(target); 1669 } 1670 1671 /** 1672 * Compares the DNS addresses in this LinkProperties with another 1673 * LinkProperties, examining only DNS addresses on the base link. 1674 * 1675 * @param target a LinkProperties with the new list of dns addresses 1676 * @return the differences between the DNS addresses. 1677 * @hide 1678 */ compareDnses(@ullable LinkProperties target)1679 public @NonNull CompareResult<InetAddress> compareDnses(@Nullable LinkProperties target) { 1680 /* 1681 * Duplicate the InetAddresses into removed, we will be removing 1682 * dns address which are common between mDnses and target 1683 * leaving the addresses that are different. And dns address which 1684 * are in target but not in mDnses are placed in the 1685 * addedAddresses. 1686 */ 1687 return new CompareResult<>(mDnses, target != null ? target.getDnsServers() : null); 1688 } 1689 1690 /** 1691 * Compares the validated private DNS addresses in this LinkProperties with another 1692 * LinkProperties. 1693 * 1694 * @param target a LinkProperties with the new list of validated private dns addresses 1695 * @return the differences between the DNS addresses. 1696 * @hide 1697 */ compareValidatedPrivateDnses( @ullable LinkProperties target)1698 public @NonNull CompareResult<InetAddress> compareValidatedPrivateDnses( 1699 @Nullable LinkProperties target) { 1700 return new CompareResult<>(mValidatedPrivateDnses, 1701 target != null ? target.getValidatedPrivateDnsServers() : null); 1702 } 1703 1704 /** 1705 * Compares all routes in this LinkProperties with another LinkProperties, 1706 * examining both the the base link and all stacked links. 1707 * 1708 * @param target a LinkProperties with the new list of routes 1709 * @return the differences between the routes. 1710 * @hide 1711 */ compareAllRoutes(@ullable LinkProperties target)1712 public @NonNull CompareResult<RouteInfo> compareAllRoutes(@Nullable LinkProperties target) { 1713 /* 1714 * Duplicate the RouteInfos into removed, we will be removing 1715 * routes which are common between mRoutes and target 1716 * leaving the routes that are different. And route address which 1717 * are in target but not in mRoutes are placed in added. 1718 */ 1719 return new CompareResult<>(getAllRoutes(), target != null ? target.getAllRoutes() : null); 1720 } 1721 1722 /** 1723 * Compares all interface names in this LinkProperties with another 1724 * LinkProperties, examining both the the base link and all stacked links. 1725 * 1726 * @param target a LinkProperties with the new list of interface names 1727 * @return the differences between the interface names. 1728 * @hide 1729 */ compareAllInterfaceNames( @ullable LinkProperties target)1730 public @NonNull CompareResult<String> compareAllInterfaceNames( 1731 @Nullable LinkProperties target) { 1732 /* 1733 * Duplicate the interface names into removed, we will be removing 1734 * interface names which are common between this and target 1735 * leaving the interface names that are different. And interface names which 1736 * are in target but not in this are placed in added. 1737 */ 1738 return new CompareResult<>(getAllInterfaceNames(), 1739 target != null ? target.getAllInterfaceNames() : null); 1740 } 1741 1742 1743 /** 1744 * Generate hashcode based on significant fields 1745 * 1746 * Equal objects must produce the same hash code, while unequal objects 1747 * may have the same hash codes. 1748 */ 1749 @Override hashCode()1750 public int hashCode() { 1751 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() 1752 + mLinkAddresses.size() * 31 1753 + mDnses.size() * 37 1754 + mValidatedPrivateDnses.size() * 61 1755 + ((null == mDomains) ? 0 : mDomains.hashCode()) 1756 + mRoutes.size() * 41 1757 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) 1758 + mStackedLinks.hashCode() * 47) 1759 + mMtu * 51 1760 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()) 1761 + (mUsePrivateDns ? 57 : 0) 1762 + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode()) 1763 + mPcscfs.size() * 67 1764 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode()) 1765 + Objects.hash(mNat64Prefix) 1766 + (mWakeOnLanSupported ? 71 : 0) 1767 + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData); 1768 } 1769 1770 /** 1771 * Implement the Parcelable interface. 1772 */ writeToParcel(Parcel dest, int flags)1773 public void writeToParcel(Parcel dest, int flags) { 1774 dest.writeString(getInterfaceName()); 1775 dest.writeInt(mLinkAddresses.size()); 1776 for (LinkAddress linkAddress : mLinkAddresses) { 1777 dest.writeParcelable(linkAddress, flags); 1778 } 1779 1780 writeAddresses(dest, mDnses); 1781 writeAddresses(dest, mValidatedPrivateDnses); 1782 dest.writeBoolean(mUsePrivateDns); 1783 dest.writeString(mPrivateDnsServerName); 1784 writeAddresses(dest, mPcscfs); 1785 dest.writeString(mDomains); 1786 writeAddress(dest, mDhcpServerAddress); 1787 dest.writeInt(mMtu); 1788 dest.writeString(mTcpBufferSizes); 1789 dest.writeInt(mRoutes.size()); 1790 for (RouteInfo route : mRoutes) { 1791 dest.writeParcelable(route, flags); 1792 } 1793 1794 if (mHttpProxy != null) { 1795 dest.writeByte((byte)1); 1796 dest.writeParcelable(mHttpProxy, flags); 1797 } else { 1798 dest.writeByte((byte)0); 1799 } 1800 dest.writeParcelable(mNat64Prefix, 0); 1801 1802 ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values()); 1803 dest.writeList(stackedLinks); 1804 1805 dest.writeBoolean(mWakeOnLanSupported); 1806 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0); 1807 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0); 1808 } 1809 writeAddresses(@onNull Parcel dest, @NonNull List<InetAddress> list)1810 private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) { 1811 dest.writeInt(list.size()); 1812 for (InetAddress d : list) { 1813 writeAddress(dest, d); 1814 } 1815 } 1816 writeAddress(@onNull Parcel dest, @Nullable InetAddress addr)1817 private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) { 1818 byte[] addressBytes = (addr == null ? null : addr.getAddress()); 1819 dest.writeByteArray(addressBytes); 1820 if (addr instanceof Inet6Address) { 1821 final Inet6Address v6Addr = (Inet6Address) addr; 1822 final boolean hasScopeId = v6Addr.getScopeId() != 0; 1823 dest.writeBoolean(hasScopeId); 1824 if (hasScopeId) dest.writeInt(v6Addr.getScopeId()); 1825 } 1826 } 1827 1828 @Nullable readAddress(@onNull Parcel p)1829 private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException { 1830 final byte[] addr = p.createByteArray(); 1831 if (addr == null) return null; 1832 1833 if (addr.length == INET6_ADDR_LENGTH) { 1834 final boolean hasScopeId = p.readBoolean(); 1835 final int scopeId = hasScopeId ? p.readInt() : 0; 1836 return Inet6Address.getByAddress(null /* host */, addr, scopeId); 1837 } 1838 1839 return InetAddress.getByAddress(addr); 1840 } 1841 1842 /** 1843 * Implement the Parcelable interface. 1844 */ 1845 public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR = 1846 new Creator<LinkProperties>() { 1847 public LinkProperties createFromParcel(Parcel in) { 1848 LinkProperties netProp = new LinkProperties(); 1849 1850 String iface = in.readString(); 1851 if (iface != null) { 1852 netProp.setInterfaceName(iface); 1853 } 1854 int addressCount = in.readInt(); 1855 for (int i = 0; i < addressCount; i++) { 1856 netProp.addLinkAddress(in.readParcelable(null)); 1857 } 1858 addressCount = in.readInt(); 1859 for (int i = 0; i < addressCount; i++) { 1860 try { 1861 netProp.addDnsServer(readAddress(in)); 1862 } catch (UnknownHostException e) { } 1863 } 1864 addressCount = in.readInt(); 1865 for (int i = 0; i < addressCount; i++) { 1866 try { 1867 netProp.addValidatedPrivateDnsServer(readAddress(in)); 1868 } catch (UnknownHostException e) { } 1869 } 1870 netProp.setUsePrivateDns(in.readBoolean()); 1871 netProp.setPrivateDnsServerName(in.readString()); 1872 addressCount = in.readInt(); 1873 for (int i = 0; i < addressCount; i++) { 1874 try { 1875 netProp.addPcscfServer(readAddress(in)); 1876 } catch (UnknownHostException e) { } 1877 } 1878 netProp.setDomains(in.readString()); 1879 try { 1880 netProp.setDhcpServerAddress((Inet4Address) InetAddress 1881 .getByAddress(in.createByteArray())); 1882 } catch (UnknownHostException e) { } 1883 netProp.setMtu(in.readInt()); 1884 netProp.setTcpBufferSizes(in.readString()); 1885 addressCount = in.readInt(); 1886 for (int i = 0; i < addressCount; i++) { 1887 netProp.addRoute(in.readParcelable(null)); 1888 } 1889 if (in.readByte() == 1) { 1890 netProp.setHttpProxy(in.readParcelable(null)); 1891 } 1892 netProp.setNat64Prefix(in.readParcelable(null)); 1893 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>(); 1894 in.readList(stackedLinks, LinkProperties.class.getClassLoader()); 1895 for (LinkProperties stackedLink: stackedLinks) { 1896 netProp.addStackedLink(stackedLink); 1897 } 1898 netProp.setWakeOnLanSupported(in.readBoolean()); 1899 1900 netProp.setCaptivePortalApiUrl(in.readParcelable(null)); 1901 netProp.setCaptivePortalData(in.readParcelable(null)); 1902 return netProp; 1903 } 1904 1905 public LinkProperties[] newArray(int size) { 1906 return new LinkProperties[size]; 1907 } 1908 }; 1909 1910 /** 1911 * Check the valid MTU range based on IPv4 or IPv6. 1912 * @hide 1913 */ isValidMtu(int mtu, boolean ipv6)1914 public static boolean isValidMtu(int mtu, boolean ipv6) { 1915 if (ipv6) { 1916 return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU; 1917 } else { 1918 return mtu >= MIN_MTU && mtu <= MAX_MTU; 1919 } 1920 } 1921 } 1922