blob: 76ca0613e59f58e03d9a3ecd3d5a67f69c9954be [file] [log] [blame]
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001/*
Wink Saville17465432010-09-21 09:15:35 -07002 * Copyright (C) 2010 The Android Open Source Project
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net;
18
Jeff Sharkey0aef9342014-08-11 15:22:51 -070019import android.annotation.NonNull;
Jeff Sharkeyf2ceed82014-08-14 12:55:00 -070020import android.annotation.Nullable;
paulhu058120d2018-12-12 17:52:57 +080021import android.annotation.SystemApi;
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020022import android.app.compat.CompatChanges;
23import android.compat.annotation.ChangeId;
24import android.compat.annotation.EnabledAfter;
Artur Satayev9c2add62019-12-10 17:47:52 +000025import android.compat.annotation.UnsupportedAppUsage;
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +000026import android.os.Build;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070027import android.os.Parcel;
Rubin Xuffd77d82017-09-05 18:40:49 +010028import android.os.Parcelable;
John Wang3e567d52011-04-04 12:35:42 -070029import android.text.TextUtils;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070030
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020031import com.android.internal.annotations.VisibleForTesting;
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +090032import com.android.modules.utils.build.SdkLevel;
33import com.android.net.module.util.CollectionUtils;
Chalard Jean79162542020-08-19 16:07:22 +090034import com.android.net.module.util.LinkPropertiesUtils;
35
Lorenzo Colittic0803122013-03-07 10:59:25 -080036import java.net.Inet4Address;
Lorenzo Colitti09de4182013-08-08 11:00:12 +090037import java.net.Inet6Address;
Rubin Xuffd77d82017-09-05 18:40:49 +010038import java.net.InetAddress;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070039import java.net.UnknownHostException;
40import java.util.ArrayList;
41import java.util.Collection;
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -070042import java.util.Collections;
Lorenzo Colittic0803122013-03-07 10:59:25 -080043import java.util.Hashtable;
Robert Greenwalt69aceaf2014-06-06 10:30:11 -070044import java.util.List;
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +090045import java.util.Objects;
Chalard Jeand51966a2018-06-07 13:27:00 +090046import java.util.StringJoiner;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070047
48/**
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -070049 * Describes the properties of a network link.
Robert Greenwalt5c733972011-02-09 13:56:06 -080050 *
51 * A link represents a connection to a network.
52 * It may have multiple addresses and multiple gateways,
Robert Greenwalteaa84d52014-05-18 22:01:38 -070053 * multiple dns servers but only one http proxy and one
54 * network interface.
Robert Greenwalt5c733972011-02-09 13:56:06 -080055 *
Robert Greenwalteaa84d52014-05-18 22:01:38 -070056 * Note that this is just a holder of data. Modifying it
57 * does not affect live networks.
Robert Greenwalt5c733972011-02-09 13:56:06 -080058 *
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070059 */
Robert Greenwaltc4920a52014-06-12 16:24:38 -070060public final class LinkProperties implements Parcelable {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020061 /**
62 * The {@link #getRoutes()} now can contain excluded as well as included routes. Use
63 * {@link RouteInfo#getType()} to determine route type.
64 *
65 * @hide
66 */
67 @ChangeId
Taras Antoshchukaf3c3602022-04-28 15:47:29 +020068 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020069 @VisibleForTesting
70 public static final long EXCLUDED_ROUTES = 186082280;
71
Lorenzo Colittic0803122013-03-07 10:59:25 -080072 // The interface described by the network link.
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +000073 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Robert Greenwalt462e5702012-10-31 14:32:53 -070074 private String mIfaceName;
paulhucbbc3db2019-03-08 16:35:20 +080075 private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
76 private final ArrayList<InetAddress> mDnses = new ArrayList<>();
Hongshike2d7cf52018-06-28 20:42:19 +090077 // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
paulhucbbc3db2019-03-08 16:35:20 +080078 private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
79 private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
dalyk7643abc2018-01-17 14:20:55 -050080 private boolean mUsePrivateDns;
81 private String mPrivateDnsServerName;
Robert Greenwaltcd277852012-11-09 10:52:27 -080082 private String mDomains;
Chalard Jeand51966a2018-06-07 13:27:00 +090083 private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
ruibin zhangca75bc82019-05-23 19:35:30 +080084 private Inet4Address mDhcpServerAddress;
Jason Monk4d5e20f2014-04-25 15:00:09 -040085 private ProxyInfo mHttpProxy;
sy.yun4aa73922013-09-02 05:24:09 +090086 private int mMtu;
Robert Greenwaltdebf0e02014-08-06 12:00:25 -070087 // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
88 private String mTcpBufferSizes;
Lorenzo Colitti981b34f2019-01-08 09:58:59 +090089 private IpPrefix mNat64Prefix;
Valentin Iftime9fa35092019-09-24 13:32:13 +020090 private boolean mWakeOnLanSupported;
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +090091 private Uri mCaptivePortalApiUrl;
92 private CaptivePortalData mCaptivePortalData;
93
94 /**
95 * Indicates whether parceling should preserve fields that are set based on permissions of
96 * the process receiving the {@link LinkProperties}.
97 */
98 private final transient boolean mParcelSensitiveFields;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070099
w19976e714f1d2014-08-05 15:18:11 -0700100 private static final int MIN_MTU = 68;
Benedict Wongf3215112020-11-19 00:17:29 -0800101
Remi NGUYEN VAN00c5e702020-11-30 16:35:43 +0900102 private static final int MIN_MTU_V6 = 1280;
Benedict Wongf3215112020-11-19 00:17:29 -0800103
w19976e714f1d2014-08-05 15:18:11 -0700104 private static final int MAX_MTU = 10000;
105
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +0900106 private static final int INET6_ADDR_LENGTH = 16;
107
Lorenzo Colittic0803122013-03-07 10:59:25 -0800108 // Stores the properties of links that are "stacked" above this link.
109 // Indexed by interface name to allow modification and to prevent duplicates being added.
Chalard Jeand51966a2018-06-07 13:27:00 +0900110 private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
Lorenzo Colittic0803122013-03-07 10:59:25 -0800111
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700112 /**
113 * @hide
114 */
Artur Satayev56cb6bb2019-11-04 17:50:59 +0000115 @UnsupportedAppUsage(implicitMember =
116 "values()[Landroid/net/LinkProperties$ProvisioningChange;")
Erik Kline04612b02015-05-21 16:15:02 +0900117 public enum ProvisioningChange {
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100118 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900119 STILL_NOT_PROVISIONED,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100120 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900121 LOST_PROVISIONING,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100122 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900123 GAINED_PROVISIONING,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100124 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900125 STILL_PROVISIONED,
126 }
127
128 /**
129 * Compare the provisioning states of two LinkProperties instances.
130 *
131 * @hide
132 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +0000133 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Erik Kline04612b02015-05-21 16:15:02 +0900134 public static ProvisioningChange compareProvisioning(
135 LinkProperties before, LinkProperties after) {
136 if (before.isProvisioned() && after.isProvisioned()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900137 // On dual-stack networks, DHCPv4 renewals can occasionally fail.
Erik Kline04612b02015-05-21 16:15:02 +0900138 // When this happens, IPv6-reachable services continue to function
139 // normally but IPv4-only services (naturally) fail.
140 //
141 // When an application using an IPv4-only service reports a bad
142 // network condition to the framework, attempts to re-validate
143 // the network succeed (since we support IPv6-only networks) and
144 // nothing is changed.
145 //
146 // For users, this is confusing and unexpected behaviour, and is
147 // not necessarily easy to diagnose. Therefore, we treat changing
Chalard Jeand51966a2018-06-07 13:27:00 +0900148 // from a dual-stack network to an IPv6-only network equivalent to
Erik Kline04612b02015-05-21 16:15:02 +0900149 // a total loss of provisioning.
150 //
151 // For one such example of this, see b/18867306.
152 //
Erik Klineaa8f8f32015-08-14 12:16:55 +0900153 // Additionally, losing IPv6 provisioning can result in TCP
154 // connections getting stuck until timeouts fire and other
155 // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
Chalard Jeand51966a2018-06-07 13:27:00 +0900156 // previously dual-stack network is deemed a lost of provisioning.
paulhucbbc3db2019-03-08 16:35:20 +0800157 if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned())
158 || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) {
Erik Kline04612b02015-05-21 16:15:02 +0900159 return ProvisioningChange.LOST_PROVISIONING;
160 }
161 return ProvisioningChange.STILL_PROVISIONED;
162 } else if (before.isProvisioned() && !after.isProvisioned()) {
163 return ProvisioningChange.LOST_PROVISIONING;
164 } else if (!before.isProvisioned() && after.isProvisioned()) {
165 return ProvisioningChange.GAINED_PROVISIONING;
166 } else { // !before.isProvisioned() && !after.isProvisioned()
167 return ProvisioningChange.STILL_NOT_PROVISIONED;
168 }
169 }
170
171 /**
paulhucbbc3db2019-03-08 16:35:20 +0800172 * Constructs a new {@code LinkProperties} with default values.
Erik Kline04612b02015-05-21 16:15:02 +0900173 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700174 public LinkProperties() {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900175 mParcelSensitiveFields = false;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700176 }
177
Sreeram Ramachandran887d7b12014-06-03 18:41:43 -0700178 /**
179 * @hide
180 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900181 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800182 public LinkProperties(@Nullable LinkProperties source) {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900183 this(source, false /* parcelSensitiveFields */);
184 }
185
Remi NGUYEN VAN8dd694d2020-03-16 14:48:37 +0900186 /**
187 * Create a copy of a {@link LinkProperties} that may preserve fields that were set
188 * based on the permissions of the process that originally received it.
189 *
190 * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
191 * they should not be shared outside of the process that receives them without appropriate
192 * checks.
193 * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling
194 * @hide
195 */
196 @SystemApi
Remi NGUYEN VAN8dd694d2020-03-16 14:48:37 +0900197 public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900198 mParcelSensitiveFields = parcelSensitiveFields;
199 if (source == null) return;
200 mIfaceName = source.mIfaceName;
201 mLinkAddresses.addAll(source.mLinkAddresses);
202 mDnses.addAll(source.mDnses);
203 mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
204 mUsePrivateDns = source.mUsePrivateDns;
205 mPrivateDnsServerName = source.mPrivateDnsServerName;
206 mPcscfs.addAll(source.mPcscfs);
207 mDomains = source.mDomains;
208 mRoutes.addAll(source.mRoutes);
209 mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
210 for (LinkProperties l: source.mStackedLinks.values()) {
211 addStackedLink(l);
Irfan Sherifffd151ec2010-08-30 20:37:17 -0700212 }
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900213 setMtu(source.mMtu);
214 setDhcpServerAddress(source.getDhcpServerAddress());
215 mTcpBufferSizes = source.mTcpBufferSizes;
216 mNat64Prefix = source.mNat64Prefix;
217 mWakeOnLanSupported = source.mWakeOnLanSupported;
218 mCaptivePortalApiUrl = source.mCaptivePortalApiUrl;
219 mCaptivePortalData = source.mCaptivePortalData;
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700220 }
221
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700222 /**
223 * Sets the interface name for this link. All {@link RouteInfo} already set for this
224 * will have their interface changed to match this new value.
225 *
226 * @param iface The name of the network interface used for this link.
227 */
paulhucbbc3db2019-03-08 16:35:20 +0800228 public void setInterfaceName(@Nullable String iface) {
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700229 mIfaceName = iface;
Chalard Jeand51966a2018-06-07 13:27:00 +0900230 ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800231 for (RouteInfo route : mRoutes) {
232 newRoutes.add(routeWithInterface(route));
233 }
234 mRoutes = newRoutes;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700235 }
236
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700237 /**
238 * Gets the interface name for this link. May be {@code null} if not set.
239 *
240 * @return The interface name set for this link or {@code null}.
241 */
Jeff Sharkeyf2ceed82014-08-14 12:55:00 -0700242 public @Nullable String getInterfaceName() {
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700243 return mIfaceName;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700244 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700245
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700246 /**
247 * @hide
248 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800249 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800250 public @NonNull List<String> getAllInterfaceNames() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900251 List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
252 if (mIfaceName != null) interfaceNames.add(mIfaceName);
Lorenzo Colitti63839822013-03-20 19:22:58 +0900253 for (LinkProperties stacked: mStackedLinks.values()) {
254 interfaceNames.addAll(stacked.getAllInterfaceNames());
255 }
256 return interfaceNames;
257 }
258
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900259 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700260 * Returns all the addresses on this link. We often think of a link having a single address,
261 * however, particularly with Ipv6 several addresses are typical. Note that the
262 * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
263 * prefix lengths for each address. This is a simplified utility alternative to
264 * {@link LinkProperties#getLinkAddresses}.
265 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900266 * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700267 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900268 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800269 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800270 public @NonNull List<InetAddress> getAddresses() {
271 final List<InetAddress> addresses = new ArrayList<>();
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700272 for (LinkAddress linkAddress : mLinkAddresses) {
273 addresses.add(linkAddress.getAddress());
274 }
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700275 return Collections.unmodifiableList(addresses);
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700276 }
277
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900278 /**
279 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700280 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900281 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100282 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +0800283 public @NonNull List<InetAddress> getAllAddresses() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900284 List<InetAddress> addresses = new ArrayList<>();
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900285 for (LinkAddress linkAddress : mLinkAddresses) {
286 addresses.add(linkAddress.getAddress());
287 }
288 for (LinkProperties stacked: mStackedLinks.values()) {
289 addresses.addAll(stacked.getAllAddresses());
290 }
291 return addresses;
292 }
293
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900294 private int findLinkAddressIndex(LinkAddress address) {
295 for (int i = 0; i < mLinkAddresses.size(); i++) {
296 if (mLinkAddresses.get(i).isSameAddressAs(address)) {
297 return i;
298 }
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900299 }
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900300 return -1;
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900301 }
302
303 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700304 * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
305 * same address/prefix does not already exist. If it does exist it is replaced.
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900306 * @param address The {@code LinkAddress} to add.
307 * @return true if {@code address} was added or updated, false otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700308 * @hide
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900309 */
Remi NGUYEN VANc7fe99f2019-01-29 12:08:43 +0900310 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800311 public boolean addLinkAddress(@NonNull LinkAddress address) {
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900312 if (address == null) {
313 return false;
314 }
315 int i = findLinkAddressIndex(address);
316 if (i < 0) {
317 // Address was not present. Add it.
318 mLinkAddresses.add(address);
319 return true;
320 } else if (mLinkAddresses.get(i).equals(address)) {
321 // Address was present and has same properties. Do nothing.
322 return false;
323 } else {
324 // Address was present and has different properties. Update it.
325 mLinkAddresses.set(i, address);
326 return true;
327 }
328 }
329
330 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700331 * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches
332 * and {@link LinkAddress} with the same address and prefix.
333 *
334 * @param toRemove A {@link LinkAddress} specifying the address to remove.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900335 * @return true if the address was removed, false if it did not exist.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700336 * @hide
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900337 */
Remi NGUYEN VANc7fe99f2019-01-29 12:08:43 +0900338 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800339 public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900340 int i = findLinkAddressIndex(toRemove);
341 if (i >= 0) {
342 mLinkAddresses.remove(i);
343 return true;
344 }
345 return false;
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700346 }
347
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900348 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700349 * Returns all the {@link LinkAddress} on this link. Typically a link will have
350 * one IPv4 address and one or more IPv6 addresses.
351 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700352 * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900353 */
paulhucbbc3db2019-03-08 16:35:20 +0800354 public @NonNull List<LinkAddress> getLinkAddresses() {
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700355 return Collections.unmodifiableList(mLinkAddresses);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700356 }
357
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900358 /**
359 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700360 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900361 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800362 @SystemApi
363 public @NonNull List<LinkAddress> getAllLinkAddresses() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900364 List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900365 for (LinkProperties stacked: mStackedLinks.values()) {
366 addresses.addAll(stacked.getAllLinkAddresses());
367 }
368 return addresses;
369 }
370
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900371 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700372 * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
373 * the given {@link Collection} of {@link LinkAddress}.
374 *
375 * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
376 * object.
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900377 */
paulhucbbc3db2019-03-08 16:35:20 +0800378 public void setLinkAddresses(@NonNull Collection<LinkAddress> addresses) {
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900379 mLinkAddresses.clear();
380 for (LinkAddress address: addresses) {
381 addLinkAddress(address);
382 }
383 }
384
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700385 /**
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900386 * Adds the given {@link InetAddress} to the list of DNS servers, if not present.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700387 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700388 * @param dnsServer The {@link InetAddress} to add to the list of DNS servers.
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900389 * @return true if the DNS server was added, false if it was already present.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700390 * @hide
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700391 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900392 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800393 public boolean addDnsServer(@NonNull InetAddress dnsServer) {
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900394 if (dnsServer != null && !mDnses.contains(dnsServer)) {
395 mDnses.add(dnsServer);
396 return true;
397 }
398 return false;
399 }
400
401 /**
Erik Kline04612b02015-05-21 16:15:02 +0900402 * Removes the given {@link InetAddress} from the list of DNS servers.
403 *
404 * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers.
405 * @return true if the DNS server was removed, false if it did not exist.
406 * @hide
407 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900408 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800409 public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
paulhu1a407652019-03-22 16:35:06 +0800410 return mDnses.remove(dnsServer);
Erik Kline04612b02015-05-21 16:15:02 +0900411 }
412
413 /**
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900414 * Replaces the DNS servers in this {@code LinkProperties} with
415 * the given {@link Collection} of {@link InetAddress} objects.
416 *
Chalard Jean299d8562018-04-11 16:36:41 +0900417 * @param dnsServers The {@link Collection} of DNS servers to set in this object.
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900418 */
paulhucbbc3db2019-03-08 16:35:20 +0800419 public void setDnsServers(@NonNull Collection<InetAddress> dnsServers) {
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900420 mDnses.clear();
421 for (InetAddress dnsServer: dnsServers) {
422 addDnsServer(dnsServer);
423 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700424 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700425
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700426 /**
Sreeram Ramachandran887d7b12014-06-03 18:41:43 -0700427 * Returns all the {@link InetAddress} for DNS servers on this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700428 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900429 * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700430 * this link.
431 */
paulhucbbc3db2019-03-08 16:35:20 +0800432 public @NonNull List<InetAddress> getDnsServers() {
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700433 return Collections.unmodifiableList(mDnses);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700434 }
435
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700436 /**
dalyk7643abc2018-01-17 14:20:55 -0500437 * Set whether private DNS is currently in use on this network.
438 *
439 * @param usePrivateDns The private DNS state.
440 * @hide
441 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900442 @SystemApi
dalyk7643abc2018-01-17 14:20:55 -0500443 public void setUsePrivateDns(boolean usePrivateDns) {
444 mUsePrivateDns = usePrivateDns;
445 }
446
447 /**
448 * Returns whether private DNS is currently in use on this network. When
449 * private DNS is in use, applications must not send unencrypted DNS
450 * queries as doing so could reveal private user information. Furthermore,
451 * if private DNS is in use and {@link #getPrivateDnsServerName} is not
452 * {@code null}, DNS queries must be sent to the specified DNS server.
453 *
454 * @return {@code true} if private DNS is in use, {@code false} otherwise.
455 */
456 public boolean isPrivateDnsActive() {
457 return mUsePrivateDns;
458 }
459
460 /**
461 * Set the name of the private DNS server to which private DNS queries
462 * should be sent when in strict mode. This value should be {@code null}
463 * when private DNS is off or in opportunistic mode.
464 *
465 * @param privateDnsServerName The private DNS server name.
466 * @hide
467 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900468 @SystemApi
dalyk7643abc2018-01-17 14:20:55 -0500469 public void setPrivateDnsServerName(@Nullable String privateDnsServerName) {
470 mPrivateDnsServerName = privateDnsServerName;
471 }
472
473 /**
ruibin zhangca75bc82019-05-23 19:35:30 +0800474 * Set DHCP server address.
475 *
476 * @param serverAddress the server address to set.
477 */
478 public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) {
479 mDhcpServerAddress = serverAddress;
480 }
481
482 /**
483 * Get DHCP server address
484 *
485 * @return The current DHCP server address.
486 */
487 public @Nullable Inet4Address getDhcpServerAddress() {
488 return mDhcpServerAddress;
489 }
490
491 /**
dalyk7643abc2018-01-17 14:20:55 -0500492 * Returns the private DNS server name that is in use. If not {@code null},
493 * private DNS is in strict mode. In this mode, applications should ensure
494 * that all DNS queries are encrypted and sent to this hostname and that
495 * queries are only sent if the hostname's certificate is valid. If
496 * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private
497 * DNS is in opportunistic mode, and applications should ensure that DNS
498 * queries are encrypted and sent to a DNS server returned by
499 * {@link #getDnsServers}. System DNS will handle each of these cases
500 * correctly, but applications implementing their own DNS lookups must make
501 * sure to follow these requirements.
502 *
503 * @return The private DNS server name.
504 */
505 public @Nullable String getPrivateDnsServerName() {
506 return mPrivateDnsServerName;
507 }
508
509 /**
Chalard Jean299d8562018-04-11 16:36:41 +0900510 * Adds the given {@link InetAddress} to the list of validated private DNS servers,
511 * if not present. This is distinct from the server name in that these are actually
512 * resolved addresses.
513 *
514 * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers.
515 * @return true if the DNS server was added, false if it was already present.
516 * @hide
517 */
paulhucbbc3db2019-03-08 16:35:20 +0800518 public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
Chalard Jean299d8562018-04-11 16:36:41 +0900519 if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) {
520 mValidatedPrivateDnses.add(dnsServer);
521 return true;
522 }
523 return false;
524 }
525
526 /**
527 * Removes the given {@link InetAddress} from the list of validated private DNS servers.
528 *
529 * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS
530 * servers.
531 * @return true if the DNS server was removed, false if it did not exist.
532 * @hide
533 */
paulhucbbc3db2019-03-08 16:35:20 +0800534 public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
535 return mValidatedPrivateDnses.remove(dnsServer);
Chalard Jean299d8562018-04-11 16:36:41 +0900536 }
537
538 /**
539 * Replaces the validated private DNS servers in this {@code LinkProperties} with
540 * the given {@link Collection} of {@link InetAddress} objects.
541 *
542 * @param dnsServers The {@link Collection} of validated private DNS servers to set in this
543 * object.
544 * @hide
545 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900546 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800547 public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) {
Chalard Jean299d8562018-04-11 16:36:41 +0900548 mValidatedPrivateDnses.clear();
549 for (InetAddress dnsServer: dnsServers) {
550 addValidatedPrivateDnsServer(dnsServer);
551 }
552 }
553
554 /**
555 * Returns all the {@link InetAddress} for validated private DNS servers on this link.
556 * These are resolved from the private DNS server name.
557 *
paulhucbbc3db2019-03-08 16:35:20 +0800558 * @return An unmodifiable {@link List} of {@link InetAddress} for validated private
Chalard Jean299d8562018-04-11 16:36:41 +0900559 * DNS servers on this link.
560 * @hide
561 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900562 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800563 public @NonNull List<InetAddress> getValidatedPrivateDnsServers() {
Chalard Jean299d8562018-04-11 16:36:41 +0900564 return Collections.unmodifiableList(mValidatedPrivateDnses);
565 }
566
567 /**
Hongshike2d7cf52018-06-28 20:42:19 +0900568 * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present.
569 *
570 * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers.
571 * @return true if the PCSCF server was added, false otherwise.
572 * @hide
573 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800574 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800575 public boolean addPcscfServer(@NonNull InetAddress pcscfServer) {
Hongshike2d7cf52018-06-28 20:42:19 +0900576 if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
577 mPcscfs.add(pcscfServer);
578 return true;
579 }
580 return false;
581 }
582
583 /**
584 * Removes the given {@link InetAddress} from the list of PCSCF servers.
585 *
paulhucbbc3db2019-03-08 16:35:20 +0800586 * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers.
Hongshike2d7cf52018-06-28 20:42:19 +0900587 * @return true if the PCSCF server was removed, false otherwise.
588 * @hide
589 */
paulhucbbc3db2019-03-08 16:35:20 +0800590 public boolean removePcscfServer(@NonNull InetAddress pcscfServer) {
591 return mPcscfs.remove(pcscfServer);
Hongshike2d7cf52018-06-28 20:42:19 +0900592 }
593
594 /**
595 * Replaces the PCSCF servers in this {@code LinkProperties} with
596 * the given {@link Collection} of {@link InetAddress} objects.
597 *
paulhucbbc3db2019-03-08 16:35:20 +0800598 * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object.
Hongshike2d7cf52018-06-28 20:42:19 +0900599 * @hide
600 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900601 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800602 public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) {
Hongshike2d7cf52018-06-28 20:42:19 +0900603 mPcscfs.clear();
604 for (InetAddress pcscfServer: pcscfServers) {
605 addPcscfServer(pcscfServer);
606 }
607 }
608
609 /**
610 * Returns all the {@link InetAddress} for PCSCF servers on this link.
611 *
612 * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on
613 * this link.
614 * @hide
615 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900616 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800617 public @NonNull List<InetAddress> getPcscfServers() {
Hongshike2d7cf52018-06-28 20:42:19 +0900618 return Collections.unmodifiableList(mPcscfs);
619 }
620
621 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700622 * Sets the DNS domain search path used on this link.
623 *
624 * @param domains A {@link String} listing in priority order the comma separated
625 * domains to search when resolving host names on this link.
626 */
paulhucbbc3db2019-03-08 16:35:20 +0800627 public void setDomains(@Nullable String domains) {
Robert Greenwaltcd277852012-11-09 10:52:27 -0800628 mDomains = domains;
629 }
630
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700631 /**
paulhucbbc3db2019-03-08 16:35:20 +0800632 * Get the DNS domains search path set for this link. May be {@code null} if not set.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700633 *
paulhucbbc3db2019-03-08 16:35:20 +0800634 * @return A {@link String} containing the comma separated domains to search when resolving host
635 * names on this link or {@code null}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700636 */
paulhucbbc3db2019-03-08 16:35:20 +0800637 public @Nullable String getDomains() {
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700638 return mDomains;
639 }
640
641 /**
642 * Sets the Maximum Transmission Unit size to use on this link. This should not be used
643 * unless the system default (1500) is incorrect. Values less than 68 or greater than
644 * 10000 will be ignored.
645 *
646 * @param mtu The MTU to use for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700647 */
sy.yun4aa73922013-09-02 05:24:09 +0900648 public void setMtu(int mtu) {
649 mMtu = mtu;
650 }
651
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700652 /**
653 * Gets any non-default MTU size set for this link. Note that if the default is being used
654 * this will return 0.
655 *
656 * @return The mtu value set for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700657 */
sy.yun4aa73922013-09-02 05:24:09 +0900658 public int getMtu() {
659 return mMtu;
660 }
661
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700662 /**
663 * Sets the tcp buffers sizes to be used when this link is the system default.
664 * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max".
665 *
666 * @param tcpBufferSizes The tcp buffers sizes to use.
667 *
668 * @hide
669 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900670 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800671 public void setTcpBufferSizes(@Nullable String tcpBufferSizes) {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700672 mTcpBufferSizes = tcpBufferSizes;
673 }
674
675 /**
paulhucbbc3db2019-03-08 16:35:20 +0800676 * Gets the tcp buffer sizes. May be {@code null} if not set.
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700677 *
paulhucbbc3db2019-03-08 16:35:20 +0800678 * @return the tcp buffer sizes to use when this link is the system default or {@code null}.
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700679 *
680 * @hide
681 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900682 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800683 public @Nullable String getTcpBufferSizes() {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700684 return mTcpBufferSizes;
685 }
686
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800687 private RouteInfo routeWithInterface(RouteInfo route) {
688 return new RouteInfo(
689 route.getDestination(),
690 route.getGateway(),
Lorenzo Colitti21290342014-09-19 01:49:05 +0900691 mIfaceName,
Tyler Weare4314862019-12-05 14:55:30 -0800692 route.getType(),
693 route.getMtu());
694 }
695
junyulaia1493a52020-03-23 20:49:43 +0800696 private int findRouteIndexByRouteKey(RouteInfo route) {
Tyler Weare4314862019-12-05 14:55:30 -0800697 for (int i = 0; i < mRoutes.size(); i++) {
junyulaia1493a52020-03-23 20:49:43 +0800698 if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) {
Tyler Weare4314862019-12-05 14:55:30 -0800699 return i;
700 }
701 }
702 return -1;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700703 }
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800704
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700705 /**
Chiachang Wang52a55922021-04-15 16:04:00 +0800706 * Adds a {@link RouteInfo} to this {@code LinkProperties}. If there is a {@link RouteInfo}
707 * with the same destination, gateway and interface with different properties
junyulaia1493a52020-03-23 20:49:43 +0800708 * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an
709 * interface name set and that differs from the interface set for this
710 * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.
711 * The proper course is to add either un-named or properly named {@link RouteInfo}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700712 *
713 * @param route A {@link RouteInfo} to add to this object.
Tyler Weare4314862019-12-05 14:55:30 -0800714 * @return {@code true} was added or updated, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700715 */
paulhucbbc3db2019-03-08 16:35:20 +0800716 public boolean addRoute(@NonNull RouteInfo route) {
717 String routeIface = route.getInterface();
718 if (routeIface != null && !routeIface.equals(mIfaceName)) {
719 throw new IllegalArgumentException(
720 "Route added with non-matching interface: " + routeIface
721 + " vs. " + mIfaceName);
722 }
723 route = routeWithInterface(route);
Tyler Weare4314862019-12-05 14:55:30 -0800724
junyulaia1493a52020-03-23 20:49:43 +0800725 int i = findRouteIndexByRouteKey(route);
Tyler Weare4314862019-12-05 14:55:30 -0800726 if (i == -1) {
727 // Route was not present. Add it.
paulhucbbc3db2019-03-08 16:35:20 +0800728 mRoutes.add(route);
729 return true;
Tyler Weare4314862019-12-05 14:55:30 -0800730 } else if (mRoutes.get(i).equals(route)) {
731 // Route was present and has same properties. Do nothing.
732 return false;
733 } else {
734 // Route was present and has different properties. Update it.
735 mRoutes.set(i, route);
736 return true;
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800737 }
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +0900738 }
739
740 /**
741 * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
742 * specify an interface and the interface must match the interface of this
743 * {@code LinkProperties}, or it will not be removed.
744 *
Tyler Weare4314862019-12-05 14:55:30 -0800745 * @param route A {@link RouteInfo} specifying the route to remove.
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +0900746 * @return {@code true} if the route was removed, {@code false} if it was not present.
747 *
748 * @hide
749 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900750 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800751 public boolean removeRoute(@NonNull RouteInfo route) {
752 return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route);
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800753 }
754
Lorenzo Colittic0803122013-03-07 10:59:25 -0800755 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700756 * Returns all the {@link RouteInfo} set on this link.
757 *
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200758 * Only unicast routes are returned for apps targeting Android S or below.
759 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700760 * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
Lorenzo Colittic0803122013-03-07 10:59:25 -0800761 */
paulhucbbc3db2019-03-08 16:35:20 +0800762 public @NonNull List<RouteInfo> getRoutes() {
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900763 // Before T, there's no throw routes because VpnService is not updatable, so no need to
764 // filter them out.
765 if (CompatChanges.isChangeEnabled(EXCLUDED_ROUTES) || !SdkLevel.isAtLeastT()) {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200766 return Collections.unmodifiableList(mRoutes);
767 } else {
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900768 // Apps that added a throw route themselves (not obtaining LinkProperties from the
769 // system) will not see it in getRoutes on T+ if they do not have the compat change
770 // enabled (target SDK < T); but this is expected to be rare and typically only affect
771 // tests creating LinkProperties themselves (like CTS v12, which is only running on S).
772 return Collections.unmodifiableList(getNonThrowRoutes());
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200773 }
774 }
775
776 /**
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900777 * Returns all the {@link RouteInfo} that are not of type {@link RouteInfo#RTN_THROW} set on
778 * this link.
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200779 */
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900780 private @NonNull List<RouteInfo> getNonThrowRoutes() {
781 return CollectionUtils.filter(mRoutes, route -> route.getType() != RouteInfo.RTN_THROW);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700782 }
783
Lorenzo Colittic0803122013-03-07 10:59:25 -0800784 /**
Rubin Xuffd77d82017-09-05 18:40:49 +0100785 * Make sure this LinkProperties instance contains routes that cover the local subnet
786 * of its link addresses. Add any route that is missing.
787 * @hide
788 */
789 public void ensureDirectlyConnectedRoutes() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900790 for (LinkAddress addr : mLinkAddresses) {
Rubin Xuffd77d82017-09-05 18:40:49 +0100791 addRoute(new RouteInfo(addr, null, mIfaceName));
792 }
793 }
794
795 /**
Lorenzo Colittic0803122013-03-07 10:59:25 -0800796 * Returns all the routes on this link and all the links stacked above it.
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200797 *
798 * Only unicast routes are returned for apps targeting Android S or below.
799 *
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700800 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800801 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800802 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800803 public @NonNull List<RouteInfo> getAllRoutes() {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200804 final List<RouteInfo> routes = new ArrayList<>(getRoutes());
Lorenzo Colittic0803122013-03-07 10:59:25 -0800805 for (LinkProperties stacked: mStackedLinks.values()) {
806 routes.addAll(stacked.getAllRoutes());
807 }
Robert Greenwaltf3385082013-03-15 11:28:50 -0700808 return routes;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800809 }
810
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700811 /**
812 * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
813 * Note that Http Proxies are only a hint - the system recommends their use, but it does
814 * not enforce it and applications may ignore them.
815 *
Erik Klinea923dba2015-06-26 19:21:34 +0900816 * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700817 */
paulhucbbc3db2019-03-08 16:35:20 +0800818 public void setHttpProxy(@Nullable ProxyInfo proxy) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700819 mHttpProxy = proxy;
820 }
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700821
822 /**
823 * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
824 *
paulhucbbc3db2019-03-08 16:35:20 +0800825 * @return The {@link ProxyInfo} set on this link or {@code null}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700826 */
paulhucbbc3db2019-03-08 16:35:20 +0800827 public @Nullable ProxyInfo getHttpProxy() {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700828 return mHttpProxy;
829 }
830
Lorenzo Colittic0803122013-03-07 10:59:25 -0800831 /**
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900832 * Returns the NAT64 prefix in use on this link, if any.
833 *
paulhucbbc3db2019-03-08 16:35:20 +0800834 * @return the NAT64 prefix or {@code null}.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900835 */
836 public @Nullable IpPrefix getNat64Prefix() {
837 return mNat64Prefix;
838 }
839
840 /**
841 * Sets the NAT64 prefix in use on this link.
842 *
843 * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the
paulhucbbc3db2019-03-08 16:35:20 +0800844 * 128-bit IPv6 address) are supported or {@code null} for no prefix.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900845 *
846 * @param prefix the NAT64 prefix.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900847 */
paulhucbbc3db2019-03-08 16:35:20 +0800848 public void setNat64Prefix(@Nullable IpPrefix prefix) {
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900849 if (prefix != null && prefix.getPrefixLength() != 96) {
850 throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
851 }
852 mNat64Prefix = prefix; // IpPrefix objects are immutable.
853 }
854
855 /**
Lorenzo Colittic0803122013-03-07 10:59:25 -0800856 * Adds a stacked link.
857 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900858 * If there is already a stacked link with the same interface name as link,
Lorenzo Colittic0803122013-03-07 10:59:25 -0800859 * that link is replaced with link. Otherwise, link is added to the list
paulhucbbc3db2019-03-08 16:35:20 +0800860 * of stacked links.
Lorenzo Colittic0803122013-03-07 10:59:25 -0800861 *
862 * @param link The link to add.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900863 * @return true if the link was stacked, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700864 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800865 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100866 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +0800867 public boolean addStackedLink(@NonNull LinkProperties link) {
868 if (link.getInterfaceName() != null) {
Lorenzo Colittic0803122013-03-07 10:59:25 -0800869 mStackedLinks.put(link.getInterfaceName(), link);
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900870 return true;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800871 }
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900872 return false;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800873 }
874
875 /**
876 * Removes a stacked link.
877 *
Lorenzo Colitti38258432014-10-20 11:08:03 +0900878 * If there is a stacked link with the given interface name, it is
Lorenzo Colittic0803122013-03-07 10:59:25 -0800879 * removed. Otherwise, nothing changes.
880 *
Lorenzo Colitti38258432014-10-20 11:08:03 +0900881 * @param iface The interface name of the link to remove.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900882 * @return true if the link was removed, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700883 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800884 */
paulhucbbc3db2019-03-08 16:35:20 +0800885 public boolean removeStackedLink(@NonNull String iface) {
886 LinkProperties removed = mStackedLinks.remove(iface);
887 return removed != null;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800888 }
889
890 /**
891 * Returns all the links stacked on top of this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700892 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800893 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +0000894 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700895 public @NonNull List<LinkProperties> getStackedLinks() {
896 if (mStackedLinks.isEmpty()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900897 return Collections.emptyList();
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700898 }
paulhucbbc3db2019-03-08 16:35:20 +0800899 final List<LinkProperties> stacked = new ArrayList<>();
Lorenzo Colittic0803122013-03-07 10:59:25 -0800900 for (LinkProperties link : mStackedLinks.values()) {
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700901 stacked.add(new LinkProperties(link));
Lorenzo Colittic0803122013-03-07 10:59:25 -0800902 }
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700903 return Collections.unmodifiableList(stacked);
Lorenzo Colittic0803122013-03-07 10:59:25 -0800904 }
905
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700906 /**
907 * Clears this object to its initial state.
908 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700909 public void clear() {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900910 if (mParcelSensitiveFields) {
911 throw new UnsupportedOperationException(
912 "Cannot clear LinkProperties when parcelSensitiveFields is set");
913 }
914
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700915 mIfaceName = null;
Wink Saville051a6642011-07-13 13:44:13 -0700916 mLinkAddresses.clear();
917 mDnses.clear();
dalyk7643abc2018-01-17 14:20:55 -0500918 mUsePrivateDns = false;
919 mPrivateDnsServerName = null;
Hongshike2d7cf52018-06-28 20:42:19 +0900920 mPcscfs.clear();
Robert Greenwaltcd277852012-11-09 10:52:27 -0800921 mDomains = null;
Wink Saville051a6642011-07-13 13:44:13 -0700922 mRoutes.clear();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700923 mHttpProxy = null;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800924 mStackedLinks.clear();
sy.yun4aa73922013-09-02 05:24:09 +0900925 mMtu = 0;
ruibin zhangca75bc82019-05-23 19:35:30 +0800926 mDhcpServerAddress = null;
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700927 mTcpBufferSizes = null;
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900928 mNat64Prefix = null;
Valentin Iftime9fa35092019-09-24 13:32:13 +0200929 mWakeOnLanSupported = false;
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900930 mCaptivePortalApiUrl = null;
931 mCaptivePortalData = null;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700932 }
933
934 /**
935 * Implement the Parcelable interface
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700936 */
937 public int describeContents() {
938 return 0;
939 }
940
Wink Saville7d857902010-08-27 11:15:18 -0700941 @Override
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700942 public String toString() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900943 // Space as a separator, so no need for spaces at start/end of the individual fragments.
944 final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700945
Chalard Jeand51966a2018-06-07 13:27:00 +0900946 if (mIfaceName != null) {
947 resultJoiner.add("InterfaceName:");
948 resultJoiner.add(mIfaceName);
949 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700950
Chalard Jeand51966a2018-06-07 13:27:00 +0900951 resultJoiner.add("LinkAddresses: [");
952 if (!mLinkAddresses.isEmpty()) {
953 resultJoiner.add(TextUtils.join(",", mLinkAddresses));
954 }
955 resultJoiner.add("]");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700956
Chalard Jeand51966a2018-06-07 13:27:00 +0900957 resultJoiner.add("DnsAddresses: [");
958 if (!mDnses.isEmpty()) {
959 resultJoiner.add(TextUtils.join(",", mDnses));
960 }
961 resultJoiner.add("]");
dalyk7643abc2018-01-17 14:20:55 -0500962
Chalard Jeand51966a2018-06-07 13:27:00 +0900963 if (mUsePrivateDns) {
964 resultJoiner.add("UsePrivateDns: true");
965 }
966
Chalard Jeand3930f12018-06-07 13:28:09 +0900967 if (mPrivateDnsServerName != null) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900968 resultJoiner.add("PrivateDnsServerName:");
969 resultJoiner.add(mPrivateDnsServerName);
dalyk7643abc2018-01-17 14:20:55 -0500970 }
971
Hongshike2d7cf52018-06-28 20:42:19 +0900972 if (!mPcscfs.isEmpty()) {
973 resultJoiner.add("PcscfAddresses: [");
974 resultJoiner.add(TextUtils.join(",", mPcscfs));
975 resultJoiner.add("]");
976 }
977
Chalard Jean299d8562018-04-11 16:36:41 +0900978 if (!mValidatedPrivateDnses.isEmpty()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900979 final StringJoiner validatedPrivateDnsesJoiner =
980 new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
981 for (final InetAddress addr : mValidatedPrivateDnses) {
982 validatedPrivateDnsesJoiner.add(addr.getHostAddress());
Chalard Jean299d8562018-04-11 16:36:41 +0900983 }
Chalard Jeand51966a2018-06-07 13:27:00 +0900984 resultJoiner.add(validatedPrivateDnsesJoiner.toString());
Chalard Jean299d8562018-04-11 16:36:41 +0900985 }
986
Chalard Jeand51966a2018-06-07 13:27:00 +0900987 resultJoiner.add("Domains:");
988 resultJoiner.add(mDomains);
Robert Greenwaltcd277852012-11-09 10:52:27 -0800989
Chalard Jeand51966a2018-06-07 13:27:00 +0900990 resultJoiner.add("MTU:");
991 resultJoiner.add(Integer.toString(mMtu));
sy.yun4aa73922013-09-02 05:24:09 +0900992
Valentin Iftime9fa35092019-09-24 13:32:13 +0200993 if (mWakeOnLanSupported) {
994 resultJoiner.add("WakeOnLanSupported: true");
995 }
996
ruibin zhangca75bc82019-05-23 19:35:30 +0800997 if (mDhcpServerAddress != null) {
998 resultJoiner.add("ServerAddress:");
999 resultJoiner.add(mDhcpServerAddress.toString());
1000 }
1001
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001002 if (mCaptivePortalApiUrl != null) {
1003 resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl);
1004 }
1005
1006 if (mCaptivePortalData != null) {
1007 resultJoiner.add("CaptivePortalData: " + mCaptivePortalData);
1008 }
1009
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001010 if (mTcpBufferSizes != null) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001011 resultJoiner.add("TcpBufferSizes:");
1012 resultJoiner.add(mTcpBufferSizes);
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001013 }
1014
Chalard Jeand51966a2018-06-07 13:27:00 +09001015 resultJoiner.add("Routes: [");
1016 if (!mRoutes.isEmpty()) {
1017 resultJoiner.add(TextUtils.join(",", mRoutes));
1018 }
1019 resultJoiner.add("]");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001020
Chalard Jeand51966a2018-06-07 13:27:00 +09001021 if (mHttpProxy != null) {
1022 resultJoiner.add("HttpProxy:");
1023 resultJoiner.add(mHttpProxy.toString());
1024 }
1025
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001026 if (mNat64Prefix != null) {
1027 resultJoiner.add("Nat64Prefix:");
1028 resultJoiner.add(mNat64Prefix.toString());
1029 }
1030
Chalard Jeand51966a2018-06-07 13:27:00 +09001031 final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
1032 if (!stackedLinksValues.isEmpty()) {
1033 final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
1034 for (final LinkProperties lp : stackedLinksValues) {
1035 stackedLinksJoiner.add("[ " + lp + " ]");
Lorenzo Colittic0803122013-03-07 10:59:25 -08001036 }
Chalard Jeand51966a2018-06-07 13:27:00 +09001037 resultJoiner.add(stackedLinksJoiner.toString());
Lorenzo Colittic0803122013-03-07 10:59:25 -08001038 }
Chalard Jeand51966a2018-06-07 13:27:00 +09001039
1040 return resultJoiner.toString();
Lorenzo Colittic0803122013-03-07 10:59:25 -08001041 }
1042
1043 /**
1044 * Returns true if this link has an IPv4 address.
1045 *
1046 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -07001047 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -08001048 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001049 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001050 public boolean hasIpv4Address() {
Lorenzo Colittic0803122013-03-07 10:59:25 -08001051 for (LinkAddress address : mLinkAddresses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001052 if (address.getAddress() instanceof Inet4Address) {
1053 return true;
1054 }
Lorenzo Colittic0803122013-03-07 10:59:25 -08001055 }
1056 return false;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001057 }
1058
Wink Saville051a6642011-07-13 13:44:13 -07001059 /**
paulhucbbc3db2019-03-08 16:35:20 +08001060 * For backward compatibility.
1061 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1062 * just yet.
1063 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1064 * @hide
1065 */
1066 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1067 public boolean hasIPv4Address() {
1068 return hasIpv4Address();
1069 }
1070
1071 /**
Lorenzo Colitti05a505c2015-07-27 16:35:33 +09001072 * Returns true if this link or any of its stacked interfaces has an IPv4 address.
1073 *
1074 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1075 */
paulhucbbc3db2019-03-08 16:35:20 +08001076 private boolean hasIpv4AddressOnInterface(String iface) {
Lorenzo Colitti28bb16c2015-07-30 23:41:43 +09001077 // mIfaceName can be null.
paulhucbbc3db2019-03-08 16:35:20 +08001078 return (Objects.equals(iface, mIfaceName) && hasIpv4Address())
1079 || (iface != null && mStackedLinks.containsKey(iface)
1080 && mStackedLinks.get(iface).hasIpv4Address());
Lorenzo Colitti05a505c2015-07-27 16:35:33 +09001081 }
1082
1083 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001084 * Returns true if this link has a global preferred IPv6 address.
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001085 *
Lorenzo Colittifc854692014-06-23 22:33:43 +09001086 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -07001087 * @hide
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001088 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001089 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001090 public boolean hasGlobalIpv6Address() {
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001091 for (LinkAddress address : mLinkAddresses) {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001092 if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001093 return true;
1094 }
1095 }
1096 return false;
1097 }
1098
1099 /**
Rubin Xuab8cf302020-03-30 14:37:05 +01001100 * Returns true if this link has an IPv4 unreachable default route.
1101 *
1102 * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise.
1103 * @hide
1104 */
1105 public boolean hasIpv4UnreachableDefaultRoute() {
1106 for (RouteInfo r : mRoutes) {
1107 if (r.isIPv4UnreachableDefault()) {
1108 return true;
1109 }
1110 }
1111 return false;
1112 }
1113
1114 /**
paulhucbbc3db2019-03-08 16:35:20 +08001115 * For backward compatibility.
1116 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1117 * just yet.
1118 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
1119 * @hide
1120 */
1121 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1122 public boolean hasGlobalIPv6Address() {
1123 return hasGlobalIpv6Address();
1124 }
1125
1126 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001127 * Returns true if this link has an IPv4 default route.
1128 *
1129 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1130 * @hide
1131 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001132 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001133 public boolean hasIpv4DefaultRoute() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001134 for (RouteInfo r : mRoutes) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001135 if (r.isIPv4Default()) {
1136 return true;
1137 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001138 }
1139 return false;
1140 }
1141
1142 /**
Rubin Xuab8cf302020-03-30 14:37:05 +01001143 * Returns true if this link has an IPv6 unreachable default route.
1144 *
1145 * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise.
1146 * @hide
1147 */
1148 public boolean hasIpv6UnreachableDefaultRoute() {
1149 for (RouteInfo r : mRoutes) {
1150 if (r.isIPv6UnreachableDefault()) {
1151 return true;
1152 }
1153 }
1154 return false;
1155 }
1156
1157 /**
paulhucbbc3db2019-03-08 16:35:20 +08001158 * For backward compatibility.
1159 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1160 * just yet.
1161 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1162 * @hide
1163 */
1164 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1165 public boolean hasIPv4DefaultRoute() {
1166 return hasIpv4DefaultRoute();
1167 }
1168
1169 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001170 * Returns true if this link has an IPv6 default route.
1171 *
1172 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1173 * @hide
1174 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001175 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001176 public boolean hasIpv6DefaultRoute() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001177 for (RouteInfo r : mRoutes) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001178 if (r.isIPv6Default()) {
1179 return true;
1180 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001181 }
1182 return false;
1183 }
1184
1185 /**
paulhucbbc3db2019-03-08 16:35:20 +08001186 * For backward compatibility.
1187 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1188 * just yet.
1189 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1190 * @hide
1191 */
1192 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1193 public boolean hasIPv6DefaultRoute() {
1194 return hasIpv6DefaultRoute();
1195 }
1196
1197 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001198 * Returns true if this link has an IPv4 DNS server.
1199 *
1200 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1201 * @hide
1202 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001203 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001204 public boolean hasIpv4DnsServer() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001205 for (InetAddress ia : mDnses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001206 if (ia instanceof Inet4Address) {
1207 return true;
1208 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001209 }
1210 return false;
1211 }
1212
1213 /**
paulhucbbc3db2019-03-08 16:35:20 +08001214 * For backward compatibility.
1215 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1216 * just yet.
1217 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1218 * @hide
1219 */
1220 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1221 public boolean hasIPv4DnsServer() {
1222 return hasIpv4DnsServer();
1223 }
1224
1225 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001226 * Returns true if this link has an IPv6 DNS server.
1227 *
1228 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1229 * @hide
1230 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001231 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001232 public boolean hasIpv6DnsServer() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001233 for (InetAddress ia : mDnses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001234 if (ia instanceof Inet6Address) {
1235 return true;
1236 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001237 }
1238 return false;
1239 }
1240
1241 /**
paulhucbbc3db2019-03-08 16:35:20 +08001242 * For backward compatibility.
1243 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1244 * just yet.
1245 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1246 * @hide
1247 */
1248 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1249 public boolean hasIPv6DnsServer() {
1250 return hasIpv6DnsServer();
1251 }
1252
1253 /**
Hongshike2d7cf52018-06-28 20:42:19 +09001254 * Returns true if this link has an IPv4 PCSCF server.
1255 *
1256 * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
1257 * @hide
1258 */
paulhucbbc3db2019-03-08 16:35:20 +08001259 public boolean hasIpv4PcscfServer() {
Hongshike2d7cf52018-06-28 20:42:19 +09001260 for (InetAddress ia : mPcscfs) {
1261 if (ia instanceof Inet4Address) {
1262 return true;
1263 }
1264 }
1265 return false;
1266 }
1267
1268 /**
1269 * Returns true if this link has an IPv6 PCSCF server.
1270 *
1271 * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
1272 * @hide
1273 */
paulhucbbc3db2019-03-08 16:35:20 +08001274 public boolean hasIpv6PcscfServer() {
Hongshike2d7cf52018-06-28 20:42:19 +09001275 for (InetAddress ia : mPcscfs) {
1276 if (ia instanceof Inet6Address) {
1277 return true;
1278 }
1279 }
1280 return false;
1281 }
1282
1283 /**
Erik Kline8b023072014-10-24 21:50:20 +09001284 * Returns true if this link is provisioned for global IPv4 connectivity.
1285 * This requires an IP address, default route, and DNS server.
1286 *
1287 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Kline04612b02015-05-21 16:15:02 +09001288 * @hide
Erik Kline8b023072014-10-24 21:50:20 +09001289 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001290 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001291 public boolean isIpv4Provisioned() {
1292 return (hasIpv4Address()
1293 && hasIpv4DefaultRoute()
1294 && hasIpv4DnsServer());
Erik Kline8b023072014-10-24 21:50:20 +09001295 }
1296
1297 /**
1298 * Returns true if this link is provisioned for global IPv6 connectivity.
1299 * This requires an IP address, default route, and DNS server.
1300 *
1301 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Kline04612b02015-05-21 16:15:02 +09001302 * @hide
Erik Kline8b023072014-10-24 21:50:20 +09001303 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001304 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001305 public boolean isIpv6Provisioned() {
1306 return (hasGlobalIpv6Address()
1307 && hasIpv6DefaultRoute()
1308 && hasIpv6DnsServer());
Erik Kline8b023072014-10-24 21:50:20 +09001309 }
1310
1311 /**
paulhucbbc3db2019-03-08 16:35:20 +08001312 * For backward compatibility.
1313 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1314 * just yet.
1315 * @return {@code true} if the link is provisioned, {@code false} otherwise.
1316 * @hide
1317 */
1318 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1319 public boolean isIPv6Provisioned() {
1320 return isIpv6Provisioned();
1321 }
1322
1323
1324 /**
Erik Kline8b023072014-10-24 21:50:20 +09001325 * Returns true if this link is provisioned for global connectivity,
1326 * for at least one Internet Protocol family.
Lorenzo Colittifc854692014-06-23 22:33:43 +09001327 *
1328 * @return {@code true} if the link is provisioned, {@code false} otherwise.
1329 * @hide
1330 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001331 @SystemApi
Lorenzo Colittifc854692014-06-23 22:33:43 +09001332 public boolean isProvisioned() {
paulhucbbc3db2019-03-08 16:35:20 +08001333 return (isIpv4Provisioned() || isIpv6Provisioned());
Lorenzo Colittifc854692014-06-23 22:33:43 +09001334 }
1335
1336 /**
Erik Klinea923dba2015-06-26 19:21:34 +09001337 * Evaluate whether the {@link InetAddress} is considered reachable.
1338 *
1339 * @return {@code true} if the given {@link InetAddress} is considered reachable,
1340 * {@code false} otherwise.
1341 * @hide
1342 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001343 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001344 public boolean isReachable(@NonNull InetAddress ip) {
Erik Klinea923dba2015-06-26 19:21:34 +09001345 final List<RouteInfo> allRoutes = getAllRoutes();
1346 // If we don't have a route to this IP address, it's not reachable.
1347 final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip);
1348 if (bestRoute == null) {
1349 return false;
1350 }
1351
1352 // TODO: better source address evaluation for destination addresses.
1353
1354 if (ip instanceof Inet4Address) {
1355 // For IPv4, it suffices for now to simply have any address.
paulhucbbc3db2019-03-08 16:35:20 +08001356 return hasIpv4AddressOnInterface(bestRoute.getInterface());
Erik Klinea923dba2015-06-26 19:21:34 +09001357 } else if (ip instanceof Inet6Address) {
1358 if (ip.isLinkLocalAddress()) {
1359 // For now, just make sure link-local destinations have
1360 // scopedIds set, since transmits will generally fail otherwise.
1361 // TODO: verify it matches the ifindex of one of the interfaces.
1362 return (((Inet6Address)ip).getScopeId() != 0);
1363 } else {
1364 // For non-link-local destinations check that either the best route
1365 // is directly connected or that some global preferred address exists.
1366 // TODO: reconsider all cases (disconnected ULA networks, ...).
paulhucbbc3db2019-03-08 16:35:20 +08001367 return (!bestRoute.hasGateway() || hasGlobalIpv6Address());
Erik Klinea923dba2015-06-26 19:21:34 +09001368 }
1369 }
1370
1371 return false;
1372 }
1373
1374 /**
Prerana2b97bbe2022-04-28 04:02:05 +00001375 * Returns true if this link has a throw route.
1376 *
1377 * @return {@code true} if there is an exclude route, {@code false} otherwise.
1378 * @hide
1379 */
1380 public boolean hasExcludeRoute() {
1381 for (RouteInfo r : mRoutes) {
1382 if (r.getType() == RouteInfo.RTN_THROW) {
1383 return true;
1384 }
1385 }
1386 return false;
1387 }
1388
1389 /**
Wink Saville051a6642011-07-13 13:44:13 -07001390 * Compares this {@code LinkProperties} interface name against the target
1391 *
1392 * @param target LinkProperties to compare.
1393 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001394 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001395 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001396 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001397 public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001398 return LinkPropertiesUtils.isIdenticalInterfaceName(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001399 }
1400
1401 /**
ruibin zhangca75bc82019-05-23 19:35:30 +08001402 * Compares this {@code LinkProperties} DHCP server address against the target
1403 *
1404 * @param target LinkProperties to compare.
1405 * @return {@code true} if both are identical, {@code false} otherwise.
1406 * @hide
1407 */
1408 public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) {
1409 return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress);
1410 }
1411
1412 /**
Robert Greenwalt462e5702012-10-31 14:32:53 -07001413 * Compares this {@code LinkProperties} interface addresses against the target
Wink Saville051a6642011-07-13 13:44:13 -07001414 *
1415 * @param target LinkProperties to compare.
1416 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001417 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001418 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001419 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001420 public boolean isIdenticalAddresses(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001421 return LinkPropertiesUtils.isIdenticalAddresses(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001422 }
1423
1424 /**
1425 * Compares this {@code LinkProperties} DNS addresses against the target
1426 *
1427 * @param target LinkProperties to compare.
1428 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001429 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001430 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001431 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001432 public boolean isIdenticalDnses(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001433 return LinkPropertiesUtils.isIdenticalDnses(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001434 }
1435
1436 /**
dalyk7643abc2018-01-17 14:20:55 -05001437 * Compares this {@code LinkProperties} private DNS settings against the
1438 * target.
1439 *
1440 * @param target LinkProperties to compare.
1441 * @return {@code true} if both are identical, {@code false} otherwise.
1442 * @hide
1443 */
paulhucbbc3db2019-03-08 16:35:20 +08001444 public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) {
dalyk7643abc2018-01-17 14:20:55 -05001445 return (isPrivateDnsActive() == target.isPrivateDnsActive()
1446 && TextUtils.equals(getPrivateDnsServerName(),
1447 target.getPrivateDnsServerName()));
1448 }
1449
1450 /**
Chalard Jean299d8562018-04-11 16:36:41 +09001451 * Compares this {@code LinkProperties} validated private DNS addresses against
1452 * the target
1453 *
1454 * @param target LinkProperties to compare.
1455 * @return {@code true} if both are identical, {@code false} otherwise.
1456 * @hide
1457 */
paulhucbbc3db2019-03-08 16:35:20 +08001458 public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) {
Chalard Jean299d8562018-04-11 16:36:41 +09001459 Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers();
1460 return (mValidatedPrivateDnses.size() == targetDnses.size())
1461 ? mValidatedPrivateDnses.containsAll(targetDnses) : false;
1462 }
1463
1464 /**
Hongshike2d7cf52018-06-28 20:42:19 +09001465 * Compares this {@code LinkProperties} PCSCF addresses against the target
1466 *
1467 * @param target LinkProperties to compare.
1468 * @return {@code true} if both are identical, {@code false} otherwise.
1469 * @hide
1470 */
paulhucbbc3db2019-03-08 16:35:20 +08001471 public boolean isIdenticalPcscfs(@NonNull LinkProperties target) {
Hongshike2d7cf52018-06-28 20:42:19 +09001472 Collection<InetAddress> targetPcscfs = target.getPcscfServers();
1473 return (mPcscfs.size() == targetPcscfs.size()) ?
1474 mPcscfs.containsAll(targetPcscfs) : false;
1475 }
1476
1477 /**
Wink Saville051a6642011-07-13 13:44:13 -07001478 * Compares this {@code LinkProperties} Routes against the target
1479 *
1480 * @param target LinkProperties to compare.
1481 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001482 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001483 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001484 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001485 public boolean isIdenticalRoutes(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001486 return LinkPropertiesUtils.isIdenticalRoutes(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001487 }
1488
1489 /**
1490 * Compares this {@code LinkProperties} HttpProxy against the target
1491 *
1492 * @param target LinkProperties to compare.
1493 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001494 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001495 */
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +00001496 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
paulhucbbc3db2019-03-08 16:35:20 +08001497 public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001498 return LinkPropertiesUtils.isIdenticalHttpProxy(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001499 }
John Wang3e567d52011-04-04 12:35:42 -07001500
Lorenzo Colittic0803122013-03-07 10:59:25 -08001501 /**
1502 * Compares this {@code LinkProperties} stacked links against the target
1503 *
1504 * @param target LinkProperties to compare.
1505 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001506 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -08001507 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +00001508 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
paulhucbbc3db2019-03-08 16:35:20 +08001509 public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) {
Lorenzo Colitti89218e52013-04-01 10:47:43 +09001510 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
Lorenzo Colittic0803122013-03-07 10:59:25 -08001511 return false;
1512 }
1513 for (LinkProperties stacked : mStackedLinks.values()) {
1514 // Hashtable values can never be null.
1515 String iface = stacked.getInterfaceName();
1516 if (!stacked.equals(target.mStackedLinks.get(iface))) {
1517 return false;
1518 }
1519 }
1520 return true;
1521 }
1522
sy.yun4aa73922013-09-02 05:24:09 +09001523 /**
1524 * Compares this {@code LinkProperties} MTU against the target
1525 *
Ying Wangcb5620b2013-09-06 22:53:16 -07001526 * @param target LinkProperties to compare.
sy.yun4aa73922013-09-02 05:24:09 +09001527 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001528 * @hide
sy.yun4aa73922013-09-02 05:24:09 +09001529 */
paulhucbbc3db2019-03-08 16:35:20 +08001530 public boolean isIdenticalMtu(@NonNull LinkProperties target) {
sy.yun4aa73922013-09-02 05:24:09 +09001531 return getMtu() == target.getMtu();
1532 }
1533
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001534 /**
1535 * Compares this {@code LinkProperties} Tcp buffer sizes against the target.
1536 *
1537 * @param target LinkProperties to compare.
1538 * @return {@code true} if both are identical, {@code false} otherwise.
1539 * @hide
1540 */
paulhucbbc3db2019-03-08 16:35:20 +08001541 public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001542 return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
1543 }
1544
John Wang3e567d52011-04-04 12:35:42 -07001545 /**
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001546 * Compares this {@code LinkProperties} NAT64 prefix against the target.
1547 *
1548 * @param target LinkProperties to compare.
1549 * @return {@code true} if both are identical, {@code false} otherwise.
1550 * @hide
1551 */
paulhucbbc3db2019-03-08 16:35:20 +08001552 public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) {
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001553 return Objects.equals(mNat64Prefix, target.mNat64Prefix);
1554 }
1555
1556 /**
Valentin Iftime9fa35092019-09-24 13:32:13 +02001557 * Compares this {@code LinkProperties} WakeOnLan supported against the target.
1558 *
1559 * @param target LinkProperties to compare.
1560 * @return {@code true} if both are identical, {@code false} otherwise.
1561 * @hide
1562 */
1563 public boolean isIdenticalWakeOnLan(LinkProperties target) {
1564 return isWakeOnLanSupported() == target.isWakeOnLanSupported();
1565 }
1566
1567 /**
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001568 * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target.
1569 *
1570 * @param target LinkProperties to compare.
1571 * @return {@code true} if both are identical, {@code false} otherwise.
1572 * @hide
1573 */
1574 public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) {
1575 return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl);
1576 }
1577
1578 /**
1579 * Compares this {@code LinkProperties}'s CaptivePortalData against the target.
1580 *
1581 * @param target LinkProperties to compare.
1582 * @return {@code true} if both are identical, {@code false} otherwise.
1583 * @hide
1584 */
1585 public boolean isIdenticalCaptivePortalData(LinkProperties target) {
1586 return Objects.equals(mCaptivePortalData, target.mCaptivePortalData);
1587 }
1588
1589 /**
Valentin Iftime9fa35092019-09-24 13:32:13 +02001590 * Set whether the network interface supports WakeOnLAN
1591 *
1592 * @param supported WakeOnLAN supported value
1593 *
1594 * @hide
1595 */
1596 public void setWakeOnLanSupported(boolean supported) {
1597 mWakeOnLanSupported = supported;
1598 }
1599
1600 /**
1601 * Returns whether the network interface supports WakeOnLAN
1602 *
1603 * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
1604 */
1605 public boolean isWakeOnLanSupported() {
1606 return mWakeOnLanSupported;
1607 }
1608
1609 /**
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001610 * Set the URL of the captive portal API endpoint to get more information about the network.
1611 * @hide
1612 */
1613 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001614 public void setCaptivePortalApiUrl(@Nullable Uri url) {
1615 mCaptivePortalApiUrl = url;
1616 }
1617
1618 /**
1619 * Get the URL of the captive portal API endpoint to get more information about the network.
1620 *
1621 * <p>This is null unless the application has
1622 * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1623 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided
1624 * the URL.
1625 * @hide
1626 */
1627 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001628 @Nullable
1629 public Uri getCaptivePortalApiUrl() {
1630 return mCaptivePortalApiUrl;
1631 }
1632
1633 /**
1634 * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1635 * @hide
1636 */
1637 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001638 public void setCaptivePortalData(@Nullable CaptivePortalData data) {
1639 mCaptivePortalData = data;
1640 }
1641
1642 /**
1643 * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1644 *
1645 * <p>This is null unless the application has
1646 * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1647 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions.
1648 * @hide
1649 */
1650 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001651 @Nullable
1652 public CaptivePortalData getCaptivePortalData() {
1653 return mCaptivePortalData;
1654 }
1655
1656 /**
John Wang3e567d52011-04-04 12:35:42 -07001657 * Compares this {@code LinkProperties} instance against the target
1658 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
1659 * all their fields are equal in values.
1660 *
1661 * For collection fields, such as mDnses, containsAll() is used to check
1662 * if two collections contains the same elements, independent of order.
1663 * There are two thoughts regarding containsAll()
1664 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
1665 * 2. Worst case performance is O(n^2).
1666 *
1667 * @param obj the object to be tested for equality.
1668 * @return {@code true} if both objects are equal, {@code false} otherwise.
1669 */
Chalard Jeand51966a2018-06-07 13:27:00 +09001670 @Override
Roman Kalukiewicz384a8c62020-10-14 15:59:06 -07001671 public boolean equals(@Nullable Object obj) {
John Wang3e567d52011-04-04 12:35:42 -07001672 if (this == obj) return true;
1673
1674 if (!(obj instanceof LinkProperties)) return false;
1675
John Wang3e567d52011-04-04 12:35:42 -07001676 LinkProperties target = (LinkProperties) obj;
Chalard Jeand51966a2018-06-07 13:27:00 +09001677 /*
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001678 * This method does not check that stacked interfaces are equal, because
1679 * stacked interfaces are not so much a property of the link as a
1680 * description of connections between links.
1681 */
dalyk7643abc2018-01-17 14:20:55 -05001682 return isIdenticalInterfaceName(target)
1683 && isIdenticalAddresses(target)
ruibin zhangca75bc82019-05-23 19:35:30 +08001684 && isIdenticalDhcpServerAddress(target)
dalyk7643abc2018-01-17 14:20:55 -05001685 && isIdenticalDnses(target)
1686 && isIdenticalPrivateDns(target)
Chalard Jean299d8562018-04-11 16:36:41 +09001687 && isIdenticalValidatedPrivateDnses(target)
Hongshike2d7cf52018-06-28 20:42:19 +09001688 && isIdenticalPcscfs(target)
dalyk7643abc2018-01-17 14:20:55 -05001689 && isIdenticalRoutes(target)
1690 && isIdenticalHttpProxy(target)
1691 && isIdenticalStackedLinks(target)
1692 && isIdenticalMtu(target)
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001693 && isIdenticalTcpBufferSizes(target)
Valentin Iftime9fa35092019-09-24 13:32:13 +02001694 && isIdenticalNat64Prefix(target)
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001695 && isIdenticalWakeOnLan(target)
1696 && isIdenticalCaptivePortalApiUrl(target)
1697 && isIdenticalCaptivePortalData(target);
Wink Saville051a6642011-07-13 13:44:13 -07001698 }
John Wang3e567d52011-04-04 12:35:42 -07001699
Wink Saville051a6642011-07-13 13:44:13 -07001700 /**
Chalard Jeand51966a2018-06-07 13:27:00 +09001701 * Generate hashcode based on significant fields
1702 *
John Wang3e567d52011-04-04 12:35:42 -07001703 * Equal objects must produce the same hash code, while unequal objects
1704 * may have the same hash codes.
1705 */
Chalard Jeand51966a2018-06-07 13:27:00 +09001706 @Override
John Wang3e567d52011-04-04 12:35:42 -07001707 public int hashCode() {
1708 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
1709 + mLinkAddresses.size() * 31
1710 + mDnses.size() * 37
Chalard Jean299d8562018-04-11 16:36:41 +09001711 + mValidatedPrivateDnses.size() * 61
Robert Greenwaltcd277852012-11-09 10:52:27 -08001712 + ((null == mDomains) ? 0 : mDomains.hashCode())
Robert Greenwalt5a901292011-04-28 14:28:50 -07001713 + mRoutes.size() * 41
Lorenzo Colittic0803122013-03-07 10:59:25 -08001714 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
sy.yun4aa73922013-09-02 05:24:09 +09001715 + mStackedLinks.hashCode() * 47)
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001716 + mMtu * 51
dalyk7643abc2018-01-17 14:20:55 -05001717 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
1718 + (mUsePrivateDns ? 57 : 0)
ruibin zhangca75bc82019-05-23 19:35:30 +08001719 + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode())
Hongshike2d7cf52018-06-28 20:42:19 +09001720 + mPcscfs.size() * 67
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001721 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
Valentin Iftime9fa35092019-09-24 13:32:13 +02001722 + Objects.hash(mNat64Prefix)
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001723 + (mWakeOnLanSupported ? 71 : 0)
1724 + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData);
John Wang3e567d52011-04-04 12:35:42 -07001725 }
1726
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001727 /**
1728 * Implement the Parcelable interface.
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001729 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001730 public void writeToParcel(Parcel dest, int flags) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001731 dest.writeString(getInterfaceName());
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001732 dest.writeInt(mLinkAddresses.size());
Chalard Jean299d8562018-04-11 16:36:41 +09001733 for (LinkAddress linkAddress : mLinkAddresses) {
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001734 dest.writeParcelable(linkAddress, flags);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001735 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001736
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001737 writeAddresses(dest, mDnses);
1738 writeAddresses(dest, mValidatedPrivateDnses);
dalyk7643abc2018-01-17 14:20:55 -05001739 dest.writeBoolean(mUsePrivateDns);
1740 dest.writeString(mPrivateDnsServerName);
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001741 writeAddresses(dest, mPcscfs);
Robert Greenwaltcd277852012-11-09 10:52:27 -08001742 dest.writeString(mDomains);
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001743 writeAddress(dest, mDhcpServerAddress);
sy.yun4aa73922013-09-02 05:24:09 +09001744 dest.writeInt(mMtu);
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001745 dest.writeString(mTcpBufferSizes);
Robert Greenwalt5a901292011-04-28 14:28:50 -07001746 dest.writeInt(mRoutes.size());
Chalard Jean299d8562018-04-11 16:36:41 +09001747 for (RouteInfo route : mRoutes) {
Robert Greenwalt5a901292011-04-28 14:28:50 -07001748 dest.writeParcelable(route, flags);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001749 }
Robert Greenwalt5c733972011-02-09 13:56:06 -08001750
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001751 if (mHttpProxy != null) {
1752 dest.writeByte((byte)1);
1753 dest.writeParcelable(mHttpProxy, flags);
1754 } else {
1755 dest.writeByte((byte)0);
1756 }
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001757 dest.writeParcelable(mNat64Prefix, 0);
1758
Chalard Jeand51966a2018-06-07 13:27:00 +09001759 ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
Lorenzo Colittic0803122013-03-07 10:59:25 -08001760 dest.writeList(stackedLinks);
Valentin Iftime9fa35092019-09-24 13:32:13 +02001761
1762 dest.writeBoolean(mWakeOnLanSupported);
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001763 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0);
1764 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001765 }
1766
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001767 private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) {
1768 dest.writeInt(list.size());
1769 for (InetAddress d : list) {
1770 writeAddress(dest, d);
1771 }
1772 }
1773
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001774 private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) {
1775 byte[] addressBytes = (addr == null ? null : addr.getAddress());
1776 dest.writeByteArray(addressBytes);
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001777 if (addr instanceof Inet6Address) {
1778 final Inet6Address v6Addr = (Inet6Address) addr;
1779 final boolean hasScopeId = v6Addr.getScopeId() != 0;
1780 dest.writeBoolean(hasScopeId);
1781 if (hasScopeId) dest.writeInt(v6Addr.getScopeId());
1782 }
1783 }
1784
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001785 @Nullable
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001786 private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException {
1787 final byte[] addr = p.createByteArray();
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001788 if (addr == null) return null;
1789
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001790 if (addr.length == INET6_ADDR_LENGTH) {
1791 final boolean hasScopeId = p.readBoolean();
1792 final int scopeId = hasScopeId ? p.readInt() : 0;
1793 return Inet6Address.getByAddress(null /* host */, addr, scopeId);
1794 }
1795
1796 return InetAddress.getByAddress(addr);
1797 }
1798
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001799 /**
1800 * Implement the Parcelable interface.
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001801 */
Jeff Sharkeyf8525282019-02-28 12:06:45 -07001802 public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR =
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001803 new Creator<LinkProperties>() {
1804 public LinkProperties createFromParcel(Parcel in) {
1805 LinkProperties netProp = new LinkProperties();
Robert Greenwalt462e5702012-10-31 14:32:53 -07001806
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001807 String iface = in.readString();
1808 if (iface != null) {
Robert Greenwalt462e5702012-10-31 14:32:53 -07001809 netProp.setInterfaceName(iface);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001810 }
1811 int addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001812 for (int i = 0; i < addressCount; i++) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001813 netProp.addLinkAddress(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001814 }
1815 addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001816 for (int i = 0; i < addressCount; i++) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001817 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001818 netProp.addDnsServer(readAddress(in));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001819 } catch (UnknownHostException e) { }
1820 }
Chalard Jean299d8562018-04-11 16:36:41 +09001821 addressCount = in.readInt();
1822 for (int i = 0; i < addressCount; i++) {
1823 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001824 netProp.addValidatedPrivateDnsServer(readAddress(in));
Chalard Jean299d8562018-04-11 16:36:41 +09001825 } catch (UnknownHostException e) { }
1826 }
dalyk7643abc2018-01-17 14:20:55 -05001827 netProp.setUsePrivateDns(in.readBoolean());
1828 netProp.setPrivateDnsServerName(in.readString());
Hongshike2d7cf52018-06-28 20:42:19 +09001829 addressCount = in.readInt();
1830 for (int i = 0; i < addressCount; i++) {
1831 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001832 netProp.addPcscfServer(readAddress(in));
Hongshike2d7cf52018-06-28 20:42:19 +09001833 } catch (UnknownHostException e) { }
1834 }
Robert Greenwaltcd277852012-11-09 10:52:27 -08001835 netProp.setDomains(in.readString());
ruibin zhangca75bc82019-05-23 19:35:30 +08001836 try {
1837 netProp.setDhcpServerAddress((Inet4Address) InetAddress
1838 .getByAddress(in.createByteArray()));
1839 } catch (UnknownHostException e) { }
sy.yun4aa73922013-09-02 05:24:09 +09001840 netProp.setMtu(in.readInt());
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001841 netProp.setTcpBufferSizes(in.readString());
Robert Greenwalt5c733972011-02-09 13:56:06 -08001842 addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001843 for (int i = 0; i < addressCount; i++) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001844 netProp.addRoute(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001845 }
1846 if (in.readByte() == 1) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001847 netProp.setHttpProxy(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001848 }
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001849 netProp.setNat64Prefix(in.readParcelable(null));
Lorenzo Colittic0803122013-03-07 10:59:25 -08001850 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
1851 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
1852 for (LinkProperties stackedLink: stackedLinks) {
1853 netProp.addStackedLink(stackedLink);
1854 }
Valentin Iftime9fa35092019-09-24 13:32:13 +02001855 netProp.setWakeOnLanSupported(in.readBoolean());
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001856
1857 netProp.setCaptivePortalApiUrl(in.readParcelable(null));
1858 netProp.setCaptivePortalData(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001859 return netProp;
1860 }
1861
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001862 public LinkProperties[] newArray(int size) {
1863 return new LinkProperties[size];
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001864 }
1865 };
w19976e714f1d2014-08-05 15:18:11 -07001866
Chalard Jean299d8562018-04-11 16:36:41 +09001867 /**
1868 * Check the valid MTU range based on IPv4 or IPv6.
1869 * @hide
1870 */
1871 public static boolean isValidMtu(int mtu, boolean ipv6) {
1872 if (ipv6) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001873 return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU;
Chalard Jean299d8562018-04-11 16:36:41 +09001874 } else {
Chalard Jeand51966a2018-06-07 13:27:00 +09001875 return mtu >= MIN_MTU && mtu <= MAX_MTU;
w19976e714f1d2014-08-05 15:18:11 -07001876 }
Chalard Jean299d8562018-04-11 16:36:41 +09001877 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001878}