blob: 9fb9bc667d26369b4b4bc217f1d10c1d30b10e9e [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
Yuyang Huang90a2cbd2023-02-09 16:29:16 +090019import static android.net.connectivity.ConnectivityCompatChanges.EXCLUDED_ROUTES;
20
Jeff Sharkey0aef9342014-08-11 15:22:51 -070021import android.annotation.NonNull;
Jeff Sharkeyf2ceed82014-08-14 12:55:00 -070022import android.annotation.Nullable;
paulhu058120d2018-12-12 17:52:57 +080023import android.annotation.SystemApi;
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020024import android.app.compat.CompatChanges;
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
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +090031import com.android.modules.utils.build.SdkLevel;
32import com.android.net.module.util.CollectionUtils;
Chalard Jean79162542020-08-19 16:07:22 +090033import com.android.net.module.util.LinkPropertiesUtils;
34
Lorenzo Colittic0803122013-03-07 10:59:25 -080035import java.net.Inet4Address;
Lorenzo Colitti09de4182013-08-08 11:00:12 +090036import java.net.Inet6Address;
Rubin Xuffd77d82017-09-05 18:40:49 +010037import java.net.InetAddress;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070038import java.net.UnknownHostException;
39import java.util.ArrayList;
40import java.util.Collection;
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -070041import java.util.Collections;
Lorenzo Colittic0803122013-03-07 10:59:25 -080042import java.util.Hashtable;
Robert Greenwalt69aceaf2014-06-06 10:30:11 -070043import java.util.List;
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +090044import java.util.Objects;
Chalard Jeand51966a2018-06-07 13:27:00 +090045import java.util.StringJoiner;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070046
47/**
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -070048 * Describes the properties of a network link.
Robert Greenwalt5c733972011-02-09 13:56:06 -080049 *
50 * A link represents a connection to a network.
51 * It may have multiple addresses and multiple gateways,
Robert Greenwalteaa84d52014-05-18 22:01:38 -070052 * multiple dns servers but only one http proxy and one
53 * network interface.
Robert Greenwalt5c733972011-02-09 13:56:06 -080054 *
Robert Greenwalteaa84d52014-05-18 22:01:38 -070055 * Note that this is just a holder of data. Modifying it
56 * does not affect live networks.
Robert Greenwalt5c733972011-02-09 13:56:06 -080057 *
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070058 */
Robert Greenwaltc4920a52014-06-12 16:24:38 -070059public final class LinkProperties implements Parcelable {
Lorenzo Colittic0803122013-03-07 10:59:25 -080060 // The interface described by the network link.
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +000061 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Robert Greenwalt462e5702012-10-31 14:32:53 -070062 private String mIfaceName;
paulhucbbc3db2019-03-08 16:35:20 +080063 private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
64 private final ArrayList<InetAddress> mDnses = new ArrayList<>();
Hongshike2d7cf52018-06-28 20:42:19 +090065 // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
paulhucbbc3db2019-03-08 16:35:20 +080066 private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
67 private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
dalyk7643abc2018-01-17 14:20:55 -050068 private boolean mUsePrivateDns;
69 private String mPrivateDnsServerName;
Robert Greenwaltcd277852012-11-09 10:52:27 -080070 private String mDomains;
Chalard Jeand51966a2018-06-07 13:27:00 +090071 private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
ruibin zhangca75bc82019-05-23 19:35:30 +080072 private Inet4Address mDhcpServerAddress;
Jason Monk4d5e20f2014-04-25 15:00:09 -040073 private ProxyInfo mHttpProxy;
sy.yun4aa73922013-09-02 05:24:09 +090074 private int mMtu;
Robert Greenwaltdebf0e02014-08-06 12:00:25 -070075 // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
76 private String mTcpBufferSizes;
Lorenzo Colitti981b34f2019-01-08 09:58:59 +090077 private IpPrefix mNat64Prefix;
Valentin Iftime9fa35092019-09-24 13:32:13 +020078 private boolean mWakeOnLanSupported;
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +090079 private Uri mCaptivePortalApiUrl;
80 private CaptivePortalData mCaptivePortalData;
81
82 /**
83 * Indicates whether parceling should preserve fields that are set based on permissions of
84 * the process receiving the {@link LinkProperties}.
85 */
86 private final transient boolean mParcelSensitiveFields;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070087
w19976e714f1d2014-08-05 15:18:11 -070088 private static final int MIN_MTU = 68;
Benedict Wongf3215112020-11-19 00:17:29 -080089
Remi NGUYEN VAN00c5e702020-11-30 16:35:43 +090090 private static final int MIN_MTU_V6 = 1280;
Benedict Wongf3215112020-11-19 00:17:29 -080091
w19976e714f1d2014-08-05 15:18:11 -070092 private static final int MAX_MTU = 10000;
93
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +090094 private static final int INET6_ADDR_LENGTH = 16;
95
Lorenzo Colittic0803122013-03-07 10:59:25 -080096 // Stores the properties of links that are "stacked" above this link.
97 // Indexed by interface name to allow modification and to prevent duplicates being added.
Chalard Jeand51966a2018-06-07 13:27:00 +090098 private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
Lorenzo Colittic0803122013-03-07 10:59:25 -080099
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700100 /**
101 * @hide
102 */
Artur Satayev56cb6bb2019-11-04 17:50:59 +0000103 @UnsupportedAppUsage(implicitMember =
104 "values()[Landroid/net/LinkProperties$ProvisioningChange;")
Erik Kline04612b02015-05-21 16:15:02 +0900105 public enum ProvisioningChange {
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100106 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900107 STILL_NOT_PROVISIONED,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100108 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900109 LOST_PROVISIONING,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100110 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900111 GAINED_PROVISIONING,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100112 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900113 STILL_PROVISIONED,
114 }
115
116 /**
117 * Compare the provisioning states of two LinkProperties instances.
118 *
119 * @hide
120 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +0000121 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Erik Kline04612b02015-05-21 16:15:02 +0900122 public static ProvisioningChange compareProvisioning(
123 LinkProperties before, LinkProperties after) {
124 if (before.isProvisioned() && after.isProvisioned()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900125 // On dual-stack networks, DHCPv4 renewals can occasionally fail.
Erik Kline04612b02015-05-21 16:15:02 +0900126 // When this happens, IPv6-reachable services continue to function
127 // normally but IPv4-only services (naturally) fail.
128 //
129 // When an application using an IPv4-only service reports a bad
130 // network condition to the framework, attempts to re-validate
131 // the network succeed (since we support IPv6-only networks) and
132 // nothing is changed.
133 //
134 // For users, this is confusing and unexpected behaviour, and is
135 // not necessarily easy to diagnose. Therefore, we treat changing
Chalard Jeand51966a2018-06-07 13:27:00 +0900136 // from a dual-stack network to an IPv6-only network equivalent to
Erik Kline04612b02015-05-21 16:15:02 +0900137 // a total loss of provisioning.
138 //
139 // For one such example of this, see b/18867306.
140 //
Erik Klineaa8f8f32015-08-14 12:16:55 +0900141 // Additionally, losing IPv6 provisioning can result in TCP
142 // connections getting stuck until timeouts fire and other
143 // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
Chalard Jeand51966a2018-06-07 13:27:00 +0900144 // previously dual-stack network is deemed a lost of provisioning.
paulhucbbc3db2019-03-08 16:35:20 +0800145 if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned())
146 || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) {
Erik Kline04612b02015-05-21 16:15:02 +0900147 return ProvisioningChange.LOST_PROVISIONING;
148 }
149 return ProvisioningChange.STILL_PROVISIONED;
150 } else if (before.isProvisioned() && !after.isProvisioned()) {
151 return ProvisioningChange.LOST_PROVISIONING;
152 } else if (!before.isProvisioned() && after.isProvisioned()) {
153 return ProvisioningChange.GAINED_PROVISIONING;
154 } else { // !before.isProvisioned() && !after.isProvisioned()
155 return ProvisioningChange.STILL_NOT_PROVISIONED;
156 }
157 }
158
159 /**
paulhucbbc3db2019-03-08 16:35:20 +0800160 * Constructs a new {@code LinkProperties} with default values.
Erik Kline04612b02015-05-21 16:15:02 +0900161 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700162 public LinkProperties() {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900163 mParcelSensitiveFields = false;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700164 }
165
Sreeram Ramachandran887d7b12014-06-03 18:41:43 -0700166 /**
167 * @hide
168 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900169 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800170 public LinkProperties(@Nullable LinkProperties source) {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900171 this(source, false /* parcelSensitiveFields */);
172 }
173
Remi NGUYEN VAN8dd694d2020-03-16 14:48:37 +0900174 /**
175 * Create a copy of a {@link LinkProperties} that may preserve fields that were set
176 * based on the permissions of the process that originally received it.
177 *
178 * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
179 * they should not be shared outside of the process that receives them without appropriate
180 * checks.
181 * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling
182 * @hide
183 */
184 @SystemApi
Remi NGUYEN VAN8dd694d2020-03-16 14:48:37 +0900185 public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900186 mParcelSensitiveFields = parcelSensitiveFields;
187 if (source == null) return;
188 mIfaceName = source.mIfaceName;
189 mLinkAddresses.addAll(source.mLinkAddresses);
190 mDnses.addAll(source.mDnses);
191 mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
192 mUsePrivateDns = source.mUsePrivateDns;
193 mPrivateDnsServerName = source.mPrivateDnsServerName;
194 mPcscfs.addAll(source.mPcscfs);
195 mDomains = source.mDomains;
196 mRoutes.addAll(source.mRoutes);
197 mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
198 for (LinkProperties l: source.mStackedLinks.values()) {
199 addStackedLink(l);
Irfan Sherifffd151ec2010-08-30 20:37:17 -0700200 }
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900201 setMtu(source.mMtu);
202 setDhcpServerAddress(source.getDhcpServerAddress());
203 mTcpBufferSizes = source.mTcpBufferSizes;
204 mNat64Prefix = source.mNat64Prefix;
205 mWakeOnLanSupported = source.mWakeOnLanSupported;
206 mCaptivePortalApiUrl = source.mCaptivePortalApiUrl;
207 mCaptivePortalData = source.mCaptivePortalData;
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700208 }
209
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700210 /**
211 * Sets the interface name for this link. All {@link RouteInfo} already set for this
212 * will have their interface changed to match this new value.
213 *
214 * @param iface The name of the network interface used for this link.
215 */
paulhucbbc3db2019-03-08 16:35:20 +0800216 public void setInterfaceName(@Nullable String iface) {
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700217 mIfaceName = iface;
Chalard Jeand51966a2018-06-07 13:27:00 +0900218 ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800219 for (RouteInfo route : mRoutes) {
220 newRoutes.add(routeWithInterface(route));
221 }
222 mRoutes = newRoutes;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700223 }
224
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700225 /**
226 * Gets the interface name for this link. May be {@code null} if not set.
227 *
228 * @return The interface name set for this link or {@code null}.
229 */
Jeff Sharkeyf2ceed82014-08-14 12:55:00 -0700230 public @Nullable String getInterfaceName() {
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700231 return mIfaceName;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700232 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700233
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700234 /**
235 * @hide
236 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800237 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800238 public @NonNull List<String> getAllInterfaceNames() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900239 List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
240 if (mIfaceName != null) interfaceNames.add(mIfaceName);
Lorenzo Colitti63839822013-03-20 19:22:58 +0900241 for (LinkProperties stacked: mStackedLinks.values()) {
242 interfaceNames.addAll(stacked.getAllInterfaceNames());
243 }
244 return interfaceNames;
245 }
246
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900247 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700248 * Returns all the addresses on this link. We often think of a link having a single address,
249 * however, particularly with Ipv6 several addresses are typical. Note that the
250 * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
251 * prefix lengths for each address. This is a simplified utility alternative to
252 * {@link LinkProperties#getLinkAddresses}.
253 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900254 * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700255 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900256 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800257 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800258 public @NonNull List<InetAddress> getAddresses() {
259 final List<InetAddress> addresses = new ArrayList<>();
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700260 for (LinkAddress linkAddress : mLinkAddresses) {
261 addresses.add(linkAddress.getAddress());
262 }
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700263 return Collections.unmodifiableList(addresses);
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700264 }
265
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900266 /**
267 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700268 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900269 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100270 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +0800271 public @NonNull List<InetAddress> getAllAddresses() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900272 List<InetAddress> addresses = new ArrayList<>();
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900273 for (LinkAddress linkAddress : mLinkAddresses) {
274 addresses.add(linkAddress.getAddress());
275 }
276 for (LinkProperties stacked: mStackedLinks.values()) {
277 addresses.addAll(stacked.getAllAddresses());
278 }
279 return addresses;
280 }
281
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900282 private int findLinkAddressIndex(LinkAddress address) {
283 for (int i = 0; i < mLinkAddresses.size(); i++) {
284 if (mLinkAddresses.get(i).isSameAddressAs(address)) {
285 return i;
286 }
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900287 }
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900288 return -1;
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900289 }
290
291 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700292 * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
293 * same address/prefix does not already exist. If it does exist it is replaced.
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900294 * @param address The {@code LinkAddress} to add.
295 * @return true if {@code address} was added or updated, false otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700296 * @hide
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900297 */
Remi NGUYEN VANc7fe99f2019-01-29 12:08:43 +0900298 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800299 public boolean addLinkAddress(@NonNull LinkAddress address) {
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900300 if (address == null) {
301 return false;
302 }
303 int i = findLinkAddressIndex(address);
304 if (i < 0) {
305 // Address was not present. Add it.
306 mLinkAddresses.add(address);
307 return true;
308 } else if (mLinkAddresses.get(i).equals(address)) {
309 // Address was present and has same properties. Do nothing.
310 return false;
311 } else {
312 // Address was present and has different properties. Update it.
313 mLinkAddresses.set(i, address);
314 return true;
315 }
316 }
317
318 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700319 * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches
320 * and {@link LinkAddress} with the same address and prefix.
321 *
322 * @param toRemove A {@link LinkAddress} specifying the address to remove.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900323 * @return true if the address was removed, false if it did not exist.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700324 * @hide
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900325 */
Remi NGUYEN VANc7fe99f2019-01-29 12:08:43 +0900326 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800327 public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900328 int i = findLinkAddressIndex(toRemove);
329 if (i >= 0) {
330 mLinkAddresses.remove(i);
331 return true;
332 }
333 return false;
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700334 }
335
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900336 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700337 * Returns all the {@link LinkAddress} on this link. Typically a link will have
338 * one IPv4 address and one or more IPv6 addresses.
339 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700340 * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900341 */
paulhucbbc3db2019-03-08 16:35:20 +0800342 public @NonNull List<LinkAddress> getLinkAddresses() {
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700343 return Collections.unmodifiableList(mLinkAddresses);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700344 }
345
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900346 /**
347 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700348 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900349 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800350 @SystemApi
351 public @NonNull List<LinkAddress> getAllLinkAddresses() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900352 List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900353 for (LinkProperties stacked: mStackedLinks.values()) {
354 addresses.addAll(stacked.getAllLinkAddresses());
355 }
356 return addresses;
357 }
358
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900359 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700360 * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
361 * the given {@link Collection} of {@link LinkAddress}.
362 *
363 * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
364 * object.
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900365 */
paulhucbbc3db2019-03-08 16:35:20 +0800366 public void setLinkAddresses(@NonNull Collection<LinkAddress> addresses) {
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900367 mLinkAddresses.clear();
368 for (LinkAddress address: addresses) {
369 addLinkAddress(address);
370 }
371 }
372
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700373 /**
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900374 * Adds the given {@link InetAddress} to the list of DNS servers, if not present.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700375 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700376 * @param dnsServer The {@link InetAddress} to add to the list of DNS servers.
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900377 * @return true if the DNS server was added, false if it was already present.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700378 * @hide
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700379 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900380 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800381 public boolean addDnsServer(@NonNull InetAddress dnsServer) {
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900382 if (dnsServer != null && !mDnses.contains(dnsServer)) {
383 mDnses.add(dnsServer);
384 return true;
385 }
386 return false;
387 }
388
389 /**
Erik Kline04612b02015-05-21 16:15:02 +0900390 * Removes the given {@link InetAddress} from the list of DNS servers.
391 *
392 * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers.
393 * @return true if the DNS server was removed, false if it did not exist.
394 * @hide
395 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900396 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800397 public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
paulhu1a407652019-03-22 16:35:06 +0800398 return mDnses.remove(dnsServer);
Erik Kline04612b02015-05-21 16:15:02 +0900399 }
400
401 /**
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900402 * Replaces the DNS servers in this {@code LinkProperties} with
403 * the given {@link Collection} of {@link InetAddress} objects.
404 *
Chalard Jean299d8562018-04-11 16:36:41 +0900405 * @param dnsServers The {@link Collection} of DNS servers to set in this object.
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900406 */
paulhucbbc3db2019-03-08 16:35:20 +0800407 public void setDnsServers(@NonNull Collection<InetAddress> dnsServers) {
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900408 mDnses.clear();
409 for (InetAddress dnsServer: dnsServers) {
410 addDnsServer(dnsServer);
411 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700412 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700413
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700414 /**
Sreeram Ramachandran887d7b12014-06-03 18:41:43 -0700415 * Returns all the {@link InetAddress} for DNS servers on this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700416 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900417 * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700418 * this link.
419 */
paulhucbbc3db2019-03-08 16:35:20 +0800420 public @NonNull List<InetAddress> getDnsServers() {
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700421 return Collections.unmodifiableList(mDnses);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700422 }
423
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700424 /**
dalyk7643abc2018-01-17 14:20:55 -0500425 * Set whether private DNS is currently in use on this network.
426 *
427 * @param usePrivateDns The private DNS state.
428 * @hide
429 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900430 @SystemApi
dalyk7643abc2018-01-17 14:20:55 -0500431 public void setUsePrivateDns(boolean usePrivateDns) {
432 mUsePrivateDns = usePrivateDns;
433 }
434
435 /**
436 * Returns whether private DNS is currently in use on this network. When
437 * private DNS is in use, applications must not send unencrypted DNS
438 * queries as doing so could reveal private user information. Furthermore,
439 * if private DNS is in use and {@link #getPrivateDnsServerName} is not
440 * {@code null}, DNS queries must be sent to the specified DNS server.
441 *
442 * @return {@code true} if private DNS is in use, {@code false} otherwise.
443 */
444 public boolean isPrivateDnsActive() {
445 return mUsePrivateDns;
446 }
447
448 /**
449 * Set the name of the private DNS server to which private DNS queries
450 * should be sent when in strict mode. This value should be {@code null}
451 * when private DNS is off or in opportunistic mode.
452 *
453 * @param privateDnsServerName The private DNS server name.
454 * @hide
455 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900456 @SystemApi
dalyk7643abc2018-01-17 14:20:55 -0500457 public void setPrivateDnsServerName(@Nullable String privateDnsServerName) {
458 mPrivateDnsServerName = privateDnsServerName;
459 }
460
461 /**
ruibin zhangca75bc82019-05-23 19:35:30 +0800462 * Set DHCP server address.
463 *
464 * @param serverAddress the server address to set.
465 */
466 public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) {
467 mDhcpServerAddress = serverAddress;
468 }
469
470 /**
471 * Get DHCP server address
472 *
473 * @return The current DHCP server address.
474 */
475 public @Nullable Inet4Address getDhcpServerAddress() {
476 return mDhcpServerAddress;
477 }
478
479 /**
dalyk7643abc2018-01-17 14:20:55 -0500480 * Returns the private DNS server name that is in use. If not {@code null},
481 * private DNS is in strict mode. In this mode, applications should ensure
482 * that all DNS queries are encrypted and sent to this hostname and that
483 * queries are only sent if the hostname's certificate is valid. If
484 * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private
485 * DNS is in opportunistic mode, and applications should ensure that DNS
486 * queries are encrypted and sent to a DNS server returned by
487 * {@link #getDnsServers}. System DNS will handle each of these cases
488 * correctly, but applications implementing their own DNS lookups must make
489 * sure to follow these requirements.
490 *
491 * @return The private DNS server name.
492 */
493 public @Nullable String getPrivateDnsServerName() {
494 return mPrivateDnsServerName;
495 }
496
497 /**
Chalard Jean299d8562018-04-11 16:36:41 +0900498 * Adds the given {@link InetAddress} to the list of validated private DNS servers,
499 * if not present. This is distinct from the server name in that these are actually
500 * resolved addresses.
501 *
502 * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers.
503 * @return true if the DNS server was added, false if it was already present.
504 * @hide
505 */
paulhucbbc3db2019-03-08 16:35:20 +0800506 public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
Chalard Jean299d8562018-04-11 16:36:41 +0900507 if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) {
508 mValidatedPrivateDnses.add(dnsServer);
509 return true;
510 }
511 return false;
512 }
513
514 /**
515 * Removes the given {@link InetAddress} from the list of validated private DNS servers.
516 *
517 * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS
518 * servers.
519 * @return true if the DNS server was removed, false if it did not exist.
520 * @hide
521 */
paulhucbbc3db2019-03-08 16:35:20 +0800522 public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
523 return mValidatedPrivateDnses.remove(dnsServer);
Chalard Jean299d8562018-04-11 16:36:41 +0900524 }
525
526 /**
527 * Replaces the validated private DNS servers in this {@code LinkProperties} with
528 * the given {@link Collection} of {@link InetAddress} objects.
529 *
530 * @param dnsServers The {@link Collection} of validated private DNS servers to set in this
531 * object.
532 * @hide
533 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900534 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800535 public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) {
Chalard Jean299d8562018-04-11 16:36:41 +0900536 mValidatedPrivateDnses.clear();
537 for (InetAddress dnsServer: dnsServers) {
538 addValidatedPrivateDnsServer(dnsServer);
539 }
540 }
541
542 /**
543 * Returns all the {@link InetAddress} for validated private DNS servers on this link.
544 * These are resolved from the private DNS server name.
545 *
paulhucbbc3db2019-03-08 16:35:20 +0800546 * @return An unmodifiable {@link List} of {@link InetAddress} for validated private
Chalard Jean299d8562018-04-11 16:36:41 +0900547 * DNS servers on this link.
548 * @hide
549 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900550 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800551 public @NonNull List<InetAddress> getValidatedPrivateDnsServers() {
Chalard Jean299d8562018-04-11 16:36:41 +0900552 return Collections.unmodifiableList(mValidatedPrivateDnses);
553 }
554
555 /**
Hongshike2d7cf52018-06-28 20:42:19 +0900556 * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present.
557 *
558 * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers.
559 * @return true if the PCSCF server was added, false otherwise.
560 * @hide
561 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800562 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800563 public boolean addPcscfServer(@NonNull InetAddress pcscfServer) {
Hongshike2d7cf52018-06-28 20:42:19 +0900564 if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
565 mPcscfs.add(pcscfServer);
566 return true;
567 }
568 return false;
569 }
570
571 /**
572 * Removes the given {@link InetAddress} from the list of PCSCF servers.
573 *
paulhucbbc3db2019-03-08 16:35:20 +0800574 * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers.
Hongshike2d7cf52018-06-28 20:42:19 +0900575 * @return true if the PCSCF server was removed, false otherwise.
576 * @hide
577 */
paulhucbbc3db2019-03-08 16:35:20 +0800578 public boolean removePcscfServer(@NonNull InetAddress pcscfServer) {
579 return mPcscfs.remove(pcscfServer);
Hongshike2d7cf52018-06-28 20:42:19 +0900580 }
581
582 /**
583 * Replaces the PCSCF servers in this {@code LinkProperties} with
584 * the given {@link Collection} of {@link InetAddress} objects.
585 *
paulhucbbc3db2019-03-08 16:35:20 +0800586 * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object.
Hongshike2d7cf52018-06-28 20:42:19 +0900587 * @hide
588 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900589 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800590 public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) {
Hongshike2d7cf52018-06-28 20:42:19 +0900591 mPcscfs.clear();
592 for (InetAddress pcscfServer: pcscfServers) {
593 addPcscfServer(pcscfServer);
594 }
595 }
596
597 /**
598 * Returns all the {@link InetAddress} for PCSCF servers on this link.
599 *
600 * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on
601 * this link.
602 * @hide
603 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900604 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800605 public @NonNull List<InetAddress> getPcscfServers() {
Hongshike2d7cf52018-06-28 20:42:19 +0900606 return Collections.unmodifiableList(mPcscfs);
607 }
608
609 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700610 * Sets the DNS domain search path used on this link.
611 *
612 * @param domains A {@link String} listing in priority order the comma separated
613 * domains to search when resolving host names on this link.
614 */
paulhucbbc3db2019-03-08 16:35:20 +0800615 public void setDomains(@Nullable String domains) {
Robert Greenwaltcd277852012-11-09 10:52:27 -0800616 mDomains = domains;
617 }
618
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700619 /**
paulhucbbc3db2019-03-08 16:35:20 +0800620 * Get the DNS domains search path set for this link. May be {@code null} if not set.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700621 *
paulhucbbc3db2019-03-08 16:35:20 +0800622 * @return A {@link String} containing the comma separated domains to search when resolving host
623 * names on this link or {@code null}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700624 */
paulhucbbc3db2019-03-08 16:35:20 +0800625 public @Nullable String getDomains() {
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700626 return mDomains;
627 }
628
629 /**
630 * Sets the Maximum Transmission Unit size to use on this link. This should not be used
631 * unless the system default (1500) is incorrect. Values less than 68 or greater than
632 * 10000 will be ignored.
633 *
634 * @param mtu The MTU to use for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700635 */
sy.yun4aa73922013-09-02 05:24:09 +0900636 public void setMtu(int mtu) {
637 mMtu = mtu;
638 }
639
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700640 /**
641 * Gets any non-default MTU size set for this link. Note that if the default is being used
642 * this will return 0.
643 *
644 * @return The mtu value set for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700645 */
sy.yun4aa73922013-09-02 05:24:09 +0900646 public int getMtu() {
647 return mMtu;
648 }
649
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700650 /**
651 * Sets the tcp buffers sizes to be used when this link is the system default.
652 * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max".
653 *
654 * @param tcpBufferSizes The tcp buffers sizes to use.
655 *
656 * @hide
657 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900658 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800659 public void setTcpBufferSizes(@Nullable String tcpBufferSizes) {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700660 mTcpBufferSizes = tcpBufferSizes;
661 }
662
663 /**
paulhucbbc3db2019-03-08 16:35:20 +0800664 * Gets the tcp buffer sizes. May be {@code null} if not set.
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700665 *
paulhucbbc3db2019-03-08 16:35:20 +0800666 * @return the tcp buffer sizes to use when this link is the system default or {@code null}.
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700667 *
668 * @hide
669 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900670 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800671 public @Nullable String getTcpBufferSizes() {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700672 return mTcpBufferSizes;
673 }
674
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800675 private RouteInfo routeWithInterface(RouteInfo route) {
676 return new RouteInfo(
677 route.getDestination(),
678 route.getGateway(),
Lorenzo Colitti21290342014-09-19 01:49:05 +0900679 mIfaceName,
Tyler Weare4314862019-12-05 14:55:30 -0800680 route.getType(),
681 route.getMtu());
682 }
683
junyulaia1493a52020-03-23 20:49:43 +0800684 private int findRouteIndexByRouteKey(RouteInfo route) {
Tyler Weare4314862019-12-05 14:55:30 -0800685 for (int i = 0; i < mRoutes.size(); i++) {
junyulaia1493a52020-03-23 20:49:43 +0800686 if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) {
Tyler Weare4314862019-12-05 14:55:30 -0800687 return i;
688 }
689 }
690 return -1;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700691 }
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800692
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700693 /**
Chiachang Wang52a55922021-04-15 16:04:00 +0800694 * Adds a {@link RouteInfo} to this {@code LinkProperties}. If there is a {@link RouteInfo}
695 * with the same destination, gateway and interface with different properties
junyulaia1493a52020-03-23 20:49:43 +0800696 * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an
697 * interface name set and that differs from the interface set for this
698 * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.
699 * The proper course is to add either un-named or properly named {@link RouteInfo}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700700 *
701 * @param route A {@link RouteInfo} to add to this object.
Tyler Weare4314862019-12-05 14:55:30 -0800702 * @return {@code true} was added or updated, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700703 */
paulhucbbc3db2019-03-08 16:35:20 +0800704 public boolean addRoute(@NonNull RouteInfo route) {
705 String routeIface = route.getInterface();
706 if (routeIface != null && !routeIface.equals(mIfaceName)) {
707 throw new IllegalArgumentException(
708 "Route added with non-matching interface: " + routeIface
709 + " vs. " + mIfaceName);
710 }
711 route = routeWithInterface(route);
Tyler Weare4314862019-12-05 14:55:30 -0800712
junyulaia1493a52020-03-23 20:49:43 +0800713 int i = findRouteIndexByRouteKey(route);
Tyler Weare4314862019-12-05 14:55:30 -0800714 if (i == -1) {
715 // Route was not present. Add it.
paulhucbbc3db2019-03-08 16:35:20 +0800716 mRoutes.add(route);
717 return true;
Tyler Weare4314862019-12-05 14:55:30 -0800718 } else if (mRoutes.get(i).equals(route)) {
719 // Route was present and has same properties. Do nothing.
720 return false;
721 } else {
722 // Route was present and has different properties. Update it.
723 mRoutes.set(i, route);
724 return true;
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800725 }
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +0900726 }
727
728 /**
729 * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
730 * specify an interface and the interface must match the interface of this
731 * {@code LinkProperties}, or it will not be removed.
732 *
Tyler Weare4314862019-12-05 14:55:30 -0800733 * @param route A {@link RouteInfo} specifying the route to remove.
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +0900734 * @return {@code true} if the route was removed, {@code false} if it was not present.
735 *
736 * @hide
737 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900738 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800739 public boolean removeRoute(@NonNull RouteInfo route) {
740 return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route);
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800741 }
742
Lorenzo Colittic0803122013-03-07 10:59:25 -0800743 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700744 * Returns all the {@link RouteInfo} set on this link.
745 *
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200746 * Only unicast routes are returned for apps targeting Android S or below.
747 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700748 * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
Lorenzo Colittic0803122013-03-07 10:59:25 -0800749 */
paulhucbbc3db2019-03-08 16:35:20 +0800750 public @NonNull List<RouteInfo> getRoutes() {
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900751 // Before T, there's no throw routes because VpnService is not updatable, so no need to
752 // filter them out.
753 if (CompatChanges.isChangeEnabled(EXCLUDED_ROUTES) || !SdkLevel.isAtLeastT()) {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200754 return Collections.unmodifiableList(mRoutes);
755 } else {
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900756 // Apps that added a throw route themselves (not obtaining LinkProperties from the
757 // system) will not see it in getRoutes on T+ if they do not have the compat change
758 // enabled (target SDK < T); but this is expected to be rare and typically only affect
759 // tests creating LinkProperties themselves (like CTS v12, which is only running on S).
Remi NGUYEN VAN48380e42022-07-15 16:42:49 +0900760 return Collections.unmodifiableList(getUnicastRoutes());
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200761 }
762 }
763
764 /**
Remi NGUYEN VAN48380e42022-07-15 16:42:49 +0900765 * Returns all the {@link RouteInfo} of type {@link RouteInfo#RTN_UNICAST} set on this link.
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200766 */
Remi NGUYEN VAN48380e42022-07-15 16:42:49 +0900767 private @NonNull List<RouteInfo> getUnicastRoutes() {
768 return CollectionUtils.filter(mRoutes, route -> route.getType() == RouteInfo.RTN_UNICAST);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700769 }
770
Lorenzo Colittic0803122013-03-07 10:59:25 -0800771 /**
Rubin Xuffd77d82017-09-05 18:40:49 +0100772 * Make sure this LinkProperties instance contains routes that cover the local subnet
773 * of its link addresses. Add any route that is missing.
774 * @hide
775 */
776 public void ensureDirectlyConnectedRoutes() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900777 for (LinkAddress addr : mLinkAddresses) {
Rubin Xuffd77d82017-09-05 18:40:49 +0100778 addRoute(new RouteInfo(addr, null, mIfaceName));
779 }
780 }
781
782 /**
Lorenzo Colittic0803122013-03-07 10:59:25 -0800783 * Returns all the routes on this link and all the links stacked above it.
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200784 *
785 * Only unicast routes are returned for apps targeting Android S or below.
786 *
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700787 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800788 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800789 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800790 public @NonNull List<RouteInfo> getAllRoutes() {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200791 final List<RouteInfo> routes = new ArrayList<>(getRoutes());
Lorenzo Colittic0803122013-03-07 10:59:25 -0800792 for (LinkProperties stacked: mStackedLinks.values()) {
793 routes.addAll(stacked.getAllRoutes());
794 }
Robert Greenwaltf3385082013-03-15 11:28:50 -0700795 return routes;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800796 }
797
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700798 /**
799 * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
800 * Note that Http Proxies are only a hint - the system recommends their use, but it does
801 * not enforce it and applications may ignore them.
802 *
Erik Klinea923dba2015-06-26 19:21:34 +0900803 * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700804 */
paulhucbbc3db2019-03-08 16:35:20 +0800805 public void setHttpProxy(@Nullable ProxyInfo proxy) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700806 mHttpProxy = proxy;
807 }
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700808
809 /**
810 * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
811 *
paulhucbbc3db2019-03-08 16:35:20 +0800812 * @return The {@link ProxyInfo} set on this link or {@code null}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700813 */
paulhucbbc3db2019-03-08 16:35:20 +0800814 public @Nullable ProxyInfo getHttpProxy() {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700815 return mHttpProxy;
816 }
817
Lorenzo Colittic0803122013-03-07 10:59:25 -0800818 /**
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900819 * Returns the NAT64 prefix in use on this link, if any.
820 *
paulhucbbc3db2019-03-08 16:35:20 +0800821 * @return the NAT64 prefix or {@code null}.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900822 */
823 public @Nullable IpPrefix getNat64Prefix() {
824 return mNat64Prefix;
825 }
826
827 /**
828 * Sets the NAT64 prefix in use on this link.
829 *
830 * 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 +0800831 * 128-bit IPv6 address) are supported or {@code null} for no prefix.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900832 *
833 * @param prefix the NAT64 prefix.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900834 */
paulhucbbc3db2019-03-08 16:35:20 +0800835 public void setNat64Prefix(@Nullable IpPrefix prefix) {
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900836 if (prefix != null && prefix.getPrefixLength() != 96) {
837 throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
838 }
839 mNat64Prefix = prefix; // IpPrefix objects are immutable.
840 }
841
842 /**
Lorenzo Colittic0803122013-03-07 10:59:25 -0800843 * Adds a stacked link.
844 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900845 * If there is already a stacked link with the same interface name as link,
Lorenzo Colittic0803122013-03-07 10:59:25 -0800846 * that link is replaced with link. Otherwise, link is added to the list
paulhucbbc3db2019-03-08 16:35:20 +0800847 * of stacked links.
Lorenzo Colittic0803122013-03-07 10:59:25 -0800848 *
849 * @param link The link to add.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900850 * @return true if the link was stacked, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700851 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800852 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100853 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +0800854 public boolean addStackedLink(@NonNull LinkProperties link) {
855 if (link.getInterfaceName() != null) {
Lorenzo Colittic0803122013-03-07 10:59:25 -0800856 mStackedLinks.put(link.getInterfaceName(), link);
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900857 return true;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800858 }
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900859 return false;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800860 }
861
862 /**
863 * Removes a stacked link.
864 *
Lorenzo Colitti38258432014-10-20 11:08:03 +0900865 * If there is a stacked link with the given interface name, it is
Lorenzo Colittic0803122013-03-07 10:59:25 -0800866 * removed. Otherwise, nothing changes.
867 *
Lorenzo Colitti38258432014-10-20 11:08:03 +0900868 * @param iface The interface name of the link to remove.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900869 * @return true if the link was removed, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700870 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800871 */
paulhucbbc3db2019-03-08 16:35:20 +0800872 public boolean removeStackedLink(@NonNull String iface) {
873 LinkProperties removed = mStackedLinks.remove(iface);
874 return removed != null;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800875 }
876
877 /**
878 * Returns all the links stacked on top of this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700879 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800880 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +0000881 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700882 public @NonNull List<LinkProperties> getStackedLinks() {
883 if (mStackedLinks.isEmpty()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900884 return Collections.emptyList();
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700885 }
paulhucbbc3db2019-03-08 16:35:20 +0800886 final List<LinkProperties> stacked = new ArrayList<>();
Lorenzo Colittic0803122013-03-07 10:59:25 -0800887 for (LinkProperties link : mStackedLinks.values()) {
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700888 stacked.add(new LinkProperties(link));
Lorenzo Colittic0803122013-03-07 10:59:25 -0800889 }
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700890 return Collections.unmodifiableList(stacked);
Lorenzo Colittic0803122013-03-07 10:59:25 -0800891 }
892
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700893 /**
894 * Clears this object to its initial state.
895 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700896 public void clear() {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900897 if (mParcelSensitiveFields) {
898 throw new UnsupportedOperationException(
899 "Cannot clear LinkProperties when parcelSensitiveFields is set");
900 }
901
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700902 mIfaceName = null;
Wink Saville051a6642011-07-13 13:44:13 -0700903 mLinkAddresses.clear();
904 mDnses.clear();
dalyk7643abc2018-01-17 14:20:55 -0500905 mUsePrivateDns = false;
906 mPrivateDnsServerName = null;
Hongshike2d7cf52018-06-28 20:42:19 +0900907 mPcscfs.clear();
Robert Greenwaltcd277852012-11-09 10:52:27 -0800908 mDomains = null;
Wink Saville051a6642011-07-13 13:44:13 -0700909 mRoutes.clear();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700910 mHttpProxy = null;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800911 mStackedLinks.clear();
sy.yun4aa73922013-09-02 05:24:09 +0900912 mMtu = 0;
ruibin zhangca75bc82019-05-23 19:35:30 +0800913 mDhcpServerAddress = null;
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700914 mTcpBufferSizes = null;
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900915 mNat64Prefix = null;
Valentin Iftime9fa35092019-09-24 13:32:13 +0200916 mWakeOnLanSupported = false;
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900917 mCaptivePortalApiUrl = null;
918 mCaptivePortalData = null;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700919 }
920
921 /**
922 * Implement the Parcelable interface
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700923 */
924 public int describeContents() {
925 return 0;
926 }
927
Wink Saville7d857902010-08-27 11:15:18 -0700928 @Override
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700929 public String toString() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900930 // Space as a separator, so no need for spaces at start/end of the individual fragments.
931 final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700932
Chalard Jeand51966a2018-06-07 13:27:00 +0900933 if (mIfaceName != null) {
934 resultJoiner.add("InterfaceName:");
935 resultJoiner.add(mIfaceName);
936 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700937
Chalard Jeand51966a2018-06-07 13:27:00 +0900938 resultJoiner.add("LinkAddresses: [");
939 if (!mLinkAddresses.isEmpty()) {
940 resultJoiner.add(TextUtils.join(",", mLinkAddresses));
941 }
942 resultJoiner.add("]");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700943
Chalard Jeand51966a2018-06-07 13:27:00 +0900944 resultJoiner.add("DnsAddresses: [");
945 if (!mDnses.isEmpty()) {
946 resultJoiner.add(TextUtils.join(",", mDnses));
947 }
948 resultJoiner.add("]");
dalyk7643abc2018-01-17 14:20:55 -0500949
Chalard Jeand51966a2018-06-07 13:27:00 +0900950 if (mUsePrivateDns) {
951 resultJoiner.add("UsePrivateDns: true");
952 }
953
Chalard Jeand3930f12018-06-07 13:28:09 +0900954 if (mPrivateDnsServerName != null) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900955 resultJoiner.add("PrivateDnsServerName:");
956 resultJoiner.add(mPrivateDnsServerName);
dalyk7643abc2018-01-17 14:20:55 -0500957 }
958
Hongshike2d7cf52018-06-28 20:42:19 +0900959 if (!mPcscfs.isEmpty()) {
960 resultJoiner.add("PcscfAddresses: [");
961 resultJoiner.add(TextUtils.join(",", mPcscfs));
962 resultJoiner.add("]");
963 }
964
Chalard Jean299d8562018-04-11 16:36:41 +0900965 if (!mValidatedPrivateDnses.isEmpty()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900966 final StringJoiner validatedPrivateDnsesJoiner =
967 new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
968 for (final InetAddress addr : mValidatedPrivateDnses) {
969 validatedPrivateDnsesJoiner.add(addr.getHostAddress());
Chalard Jean299d8562018-04-11 16:36:41 +0900970 }
Chalard Jeand51966a2018-06-07 13:27:00 +0900971 resultJoiner.add(validatedPrivateDnsesJoiner.toString());
Chalard Jean299d8562018-04-11 16:36:41 +0900972 }
973
Chalard Jeand51966a2018-06-07 13:27:00 +0900974 resultJoiner.add("Domains:");
975 resultJoiner.add(mDomains);
Robert Greenwaltcd277852012-11-09 10:52:27 -0800976
Chalard Jeand51966a2018-06-07 13:27:00 +0900977 resultJoiner.add("MTU:");
978 resultJoiner.add(Integer.toString(mMtu));
sy.yun4aa73922013-09-02 05:24:09 +0900979
Valentin Iftime9fa35092019-09-24 13:32:13 +0200980 if (mWakeOnLanSupported) {
981 resultJoiner.add("WakeOnLanSupported: true");
982 }
983
ruibin zhangca75bc82019-05-23 19:35:30 +0800984 if (mDhcpServerAddress != null) {
985 resultJoiner.add("ServerAddress:");
986 resultJoiner.add(mDhcpServerAddress.toString());
987 }
988
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900989 if (mCaptivePortalApiUrl != null) {
990 resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl);
991 }
992
993 if (mCaptivePortalData != null) {
994 resultJoiner.add("CaptivePortalData: " + mCaptivePortalData);
995 }
996
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700997 if (mTcpBufferSizes != null) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900998 resultJoiner.add("TcpBufferSizes:");
999 resultJoiner.add(mTcpBufferSizes);
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001000 }
1001
Chalard Jeand51966a2018-06-07 13:27:00 +09001002 resultJoiner.add("Routes: [");
1003 if (!mRoutes.isEmpty()) {
1004 resultJoiner.add(TextUtils.join(",", mRoutes));
1005 }
1006 resultJoiner.add("]");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001007
Chalard Jeand51966a2018-06-07 13:27:00 +09001008 if (mHttpProxy != null) {
1009 resultJoiner.add("HttpProxy:");
1010 resultJoiner.add(mHttpProxy.toString());
1011 }
1012
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001013 if (mNat64Prefix != null) {
1014 resultJoiner.add("Nat64Prefix:");
1015 resultJoiner.add(mNat64Prefix.toString());
1016 }
1017
Chalard Jeand51966a2018-06-07 13:27:00 +09001018 final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
1019 if (!stackedLinksValues.isEmpty()) {
1020 final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
1021 for (final LinkProperties lp : stackedLinksValues) {
1022 stackedLinksJoiner.add("[ " + lp + " ]");
Lorenzo Colittic0803122013-03-07 10:59:25 -08001023 }
Chalard Jeand51966a2018-06-07 13:27:00 +09001024 resultJoiner.add(stackedLinksJoiner.toString());
Lorenzo Colittic0803122013-03-07 10:59:25 -08001025 }
Chalard Jeand51966a2018-06-07 13:27:00 +09001026
1027 return resultJoiner.toString();
Lorenzo Colittic0803122013-03-07 10:59:25 -08001028 }
1029
1030 /**
1031 * Returns true if this link has an IPv4 address.
1032 *
1033 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -07001034 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -08001035 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001036 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001037 public boolean hasIpv4Address() {
Lorenzo Colittic0803122013-03-07 10:59:25 -08001038 for (LinkAddress address : mLinkAddresses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001039 if (address.getAddress() instanceof Inet4Address) {
1040 return true;
1041 }
Lorenzo Colittic0803122013-03-07 10:59:25 -08001042 }
1043 return false;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001044 }
1045
Wink Saville051a6642011-07-13 13:44:13 -07001046 /**
paulhucbbc3db2019-03-08 16:35:20 +08001047 * For backward compatibility.
1048 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1049 * just yet.
1050 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1051 * @hide
1052 */
1053 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1054 public boolean hasIPv4Address() {
1055 return hasIpv4Address();
1056 }
1057
1058 /**
Lorenzo Colitti05a505c2015-07-27 16:35:33 +09001059 * Returns true if this link or any of its stacked interfaces has an IPv4 address.
1060 *
1061 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1062 */
paulhucbbc3db2019-03-08 16:35:20 +08001063 private boolean hasIpv4AddressOnInterface(String iface) {
Lorenzo Colitti28bb16c2015-07-30 23:41:43 +09001064 // mIfaceName can be null.
paulhucbbc3db2019-03-08 16:35:20 +08001065 return (Objects.equals(iface, mIfaceName) && hasIpv4Address())
1066 || (iface != null && mStackedLinks.containsKey(iface)
1067 && mStackedLinks.get(iface).hasIpv4Address());
Lorenzo Colitti05a505c2015-07-27 16:35:33 +09001068 }
1069
1070 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001071 * Returns true if this link has a global preferred IPv6 address.
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001072 *
Lorenzo Colittifc854692014-06-23 22:33:43 +09001073 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -07001074 * @hide
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001075 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001076 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001077 public boolean hasGlobalIpv6Address() {
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001078 for (LinkAddress address : mLinkAddresses) {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001079 if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001080 return true;
1081 }
1082 }
1083 return false;
1084 }
1085
1086 /**
Rubin Xuab8cf302020-03-30 14:37:05 +01001087 * Returns true if this link has an IPv4 unreachable default route.
1088 *
1089 * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise.
1090 * @hide
1091 */
1092 public boolean hasIpv4UnreachableDefaultRoute() {
1093 for (RouteInfo r : mRoutes) {
1094 if (r.isIPv4UnreachableDefault()) {
1095 return true;
1096 }
1097 }
1098 return false;
1099 }
1100
1101 /**
paulhucbbc3db2019-03-08 16:35:20 +08001102 * For backward compatibility.
1103 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1104 * just yet.
1105 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
1106 * @hide
1107 */
1108 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1109 public boolean hasGlobalIPv6Address() {
1110 return hasGlobalIpv6Address();
1111 }
1112
1113 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001114 * Returns true if this link has an IPv4 default route.
1115 *
1116 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1117 * @hide
1118 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001119 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001120 public boolean hasIpv4DefaultRoute() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001121 for (RouteInfo r : mRoutes) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001122 if (r.isIPv4Default()) {
1123 return true;
1124 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001125 }
1126 return false;
1127 }
1128
1129 /**
Rubin Xuab8cf302020-03-30 14:37:05 +01001130 * Returns true if this link has an IPv6 unreachable default route.
1131 *
1132 * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise.
1133 * @hide
1134 */
1135 public boolean hasIpv6UnreachableDefaultRoute() {
1136 for (RouteInfo r : mRoutes) {
1137 if (r.isIPv6UnreachableDefault()) {
1138 return true;
1139 }
1140 }
1141 return false;
1142 }
1143
1144 /**
paulhucbbc3db2019-03-08 16:35:20 +08001145 * For backward compatibility.
1146 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1147 * just yet.
1148 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1149 * @hide
1150 */
1151 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1152 public boolean hasIPv4DefaultRoute() {
1153 return hasIpv4DefaultRoute();
1154 }
1155
1156 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001157 * Returns true if this link has an IPv6 default route.
1158 *
1159 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1160 * @hide
1161 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001162 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001163 public boolean hasIpv6DefaultRoute() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001164 for (RouteInfo r : mRoutes) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001165 if (r.isIPv6Default()) {
1166 return true;
1167 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001168 }
1169 return false;
1170 }
1171
1172 /**
paulhucbbc3db2019-03-08 16:35:20 +08001173 * For backward compatibility.
1174 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1175 * just yet.
1176 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1177 * @hide
1178 */
1179 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1180 public boolean hasIPv6DefaultRoute() {
1181 return hasIpv6DefaultRoute();
1182 }
1183
1184 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001185 * Returns true if this link has an IPv4 DNS server.
1186 *
1187 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1188 * @hide
1189 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001190 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001191 public boolean hasIpv4DnsServer() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001192 for (InetAddress ia : mDnses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001193 if (ia instanceof Inet4Address) {
1194 return true;
1195 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001196 }
1197 return false;
1198 }
1199
1200 /**
paulhucbbc3db2019-03-08 16:35:20 +08001201 * For backward compatibility.
1202 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1203 * just yet.
1204 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1205 * @hide
1206 */
1207 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1208 public boolean hasIPv4DnsServer() {
1209 return hasIpv4DnsServer();
1210 }
1211
1212 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001213 * Returns true if this link has an IPv6 DNS server.
1214 *
1215 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1216 * @hide
1217 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001218 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001219 public boolean hasIpv6DnsServer() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001220 for (InetAddress ia : mDnses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001221 if (ia instanceof Inet6Address) {
1222 return true;
1223 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001224 }
1225 return false;
1226 }
1227
1228 /**
paulhucbbc3db2019-03-08 16:35:20 +08001229 * For backward compatibility.
1230 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1231 * just yet.
1232 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1233 * @hide
1234 */
1235 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1236 public boolean hasIPv6DnsServer() {
1237 return hasIpv6DnsServer();
1238 }
1239
1240 /**
Hongshike2d7cf52018-06-28 20:42:19 +09001241 * Returns true if this link has an IPv4 PCSCF server.
1242 *
1243 * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
1244 * @hide
1245 */
paulhucbbc3db2019-03-08 16:35:20 +08001246 public boolean hasIpv4PcscfServer() {
Hongshike2d7cf52018-06-28 20:42:19 +09001247 for (InetAddress ia : mPcscfs) {
1248 if (ia instanceof Inet4Address) {
1249 return true;
1250 }
1251 }
1252 return false;
1253 }
1254
1255 /**
1256 * Returns true if this link has an IPv6 PCSCF server.
1257 *
1258 * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
1259 * @hide
1260 */
paulhucbbc3db2019-03-08 16:35:20 +08001261 public boolean hasIpv6PcscfServer() {
Hongshike2d7cf52018-06-28 20:42:19 +09001262 for (InetAddress ia : mPcscfs) {
1263 if (ia instanceof Inet6Address) {
1264 return true;
1265 }
1266 }
1267 return false;
1268 }
1269
1270 /**
Erik Kline8b023072014-10-24 21:50:20 +09001271 * Returns true if this link is provisioned for global IPv4 connectivity.
1272 * This requires an IP address, default route, and DNS server.
1273 *
1274 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Kline04612b02015-05-21 16:15:02 +09001275 * @hide
Erik Kline8b023072014-10-24 21:50:20 +09001276 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001277 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001278 public boolean isIpv4Provisioned() {
1279 return (hasIpv4Address()
1280 && hasIpv4DefaultRoute()
1281 && hasIpv4DnsServer());
Erik Kline8b023072014-10-24 21:50:20 +09001282 }
1283
1284 /**
1285 * Returns true if this link is provisioned for global IPv6 connectivity.
1286 * This requires an IP address, default route, and DNS server.
1287 *
1288 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Kline04612b02015-05-21 16:15:02 +09001289 * @hide
Erik Kline8b023072014-10-24 21:50:20 +09001290 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001291 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001292 public boolean isIpv6Provisioned() {
1293 return (hasGlobalIpv6Address()
1294 && hasIpv6DefaultRoute()
1295 && hasIpv6DnsServer());
Erik Kline8b023072014-10-24 21:50:20 +09001296 }
1297
1298 /**
paulhucbbc3db2019-03-08 16:35:20 +08001299 * For backward compatibility.
1300 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1301 * just yet.
1302 * @return {@code true} if the link is provisioned, {@code false} otherwise.
1303 * @hide
1304 */
1305 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1306 public boolean isIPv6Provisioned() {
1307 return isIpv6Provisioned();
1308 }
1309
1310
1311 /**
Erik Kline8b023072014-10-24 21:50:20 +09001312 * Returns true if this link is provisioned for global connectivity,
1313 * for at least one Internet Protocol family.
Lorenzo Colittifc854692014-06-23 22:33:43 +09001314 *
1315 * @return {@code true} if the link is provisioned, {@code false} otherwise.
1316 * @hide
1317 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001318 @SystemApi
Lorenzo Colittifc854692014-06-23 22:33:43 +09001319 public boolean isProvisioned() {
paulhucbbc3db2019-03-08 16:35:20 +08001320 return (isIpv4Provisioned() || isIpv6Provisioned());
Lorenzo Colittifc854692014-06-23 22:33:43 +09001321 }
1322
1323 /**
Erik Klinea923dba2015-06-26 19:21:34 +09001324 * Evaluate whether the {@link InetAddress} is considered reachable.
1325 *
1326 * @return {@code true} if the given {@link InetAddress} is considered reachable,
1327 * {@code false} otherwise.
1328 * @hide
1329 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001330 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001331 public boolean isReachable(@NonNull InetAddress ip) {
Erik Klinea923dba2015-06-26 19:21:34 +09001332 final List<RouteInfo> allRoutes = getAllRoutes();
1333 // If we don't have a route to this IP address, it's not reachable.
1334 final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip);
1335 if (bestRoute == null) {
1336 return false;
1337 }
1338
1339 // TODO: better source address evaluation for destination addresses.
1340
1341 if (ip instanceof Inet4Address) {
1342 // For IPv4, it suffices for now to simply have any address.
paulhucbbc3db2019-03-08 16:35:20 +08001343 return hasIpv4AddressOnInterface(bestRoute.getInterface());
Erik Klinea923dba2015-06-26 19:21:34 +09001344 } else if (ip instanceof Inet6Address) {
1345 if (ip.isLinkLocalAddress()) {
1346 // For now, just make sure link-local destinations have
1347 // scopedIds set, since transmits will generally fail otherwise.
1348 // TODO: verify it matches the ifindex of one of the interfaces.
1349 return (((Inet6Address)ip).getScopeId() != 0);
1350 } else {
1351 // For non-link-local destinations check that either the best route
1352 // is directly connected or that some global preferred address exists.
1353 // TODO: reconsider all cases (disconnected ULA networks, ...).
paulhucbbc3db2019-03-08 16:35:20 +08001354 return (!bestRoute.hasGateway() || hasGlobalIpv6Address());
Erik Klinea923dba2015-06-26 19:21:34 +09001355 }
1356 }
1357
1358 return false;
1359 }
1360
1361 /**
Prerana2b97bbe2022-04-28 04:02:05 +00001362 * Returns true if this link has a throw route.
1363 *
1364 * @return {@code true} if there is an exclude route, {@code false} otherwise.
1365 * @hide
1366 */
1367 public boolean hasExcludeRoute() {
1368 for (RouteInfo r : mRoutes) {
1369 if (r.getType() == RouteInfo.RTN_THROW) {
1370 return true;
1371 }
1372 }
1373 return false;
1374 }
1375
1376 /**
Wink Saville051a6642011-07-13 13:44:13 -07001377 * Compares this {@code LinkProperties} interface name against the target
1378 *
1379 * @param target LinkProperties to compare.
1380 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001381 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001382 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001383 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001384 public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001385 return LinkPropertiesUtils.isIdenticalInterfaceName(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001386 }
1387
1388 /**
ruibin zhangca75bc82019-05-23 19:35:30 +08001389 * Compares this {@code LinkProperties} DHCP server address against the target
1390 *
1391 * @param target LinkProperties to compare.
1392 * @return {@code true} if both are identical, {@code false} otherwise.
1393 * @hide
1394 */
1395 public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) {
1396 return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress);
1397 }
1398
1399 /**
Robert Greenwalt462e5702012-10-31 14:32:53 -07001400 * Compares this {@code LinkProperties} interface addresses against the target
Wink Saville051a6642011-07-13 13:44:13 -07001401 *
1402 * @param target LinkProperties to compare.
1403 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001404 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001405 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001406 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001407 public boolean isIdenticalAddresses(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001408 return LinkPropertiesUtils.isIdenticalAddresses(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001409 }
1410
1411 /**
1412 * Compares this {@code LinkProperties} DNS addresses against the target
1413 *
1414 * @param target LinkProperties to compare.
1415 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001416 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001417 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001418 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001419 public boolean isIdenticalDnses(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001420 return LinkPropertiesUtils.isIdenticalDnses(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001421 }
1422
1423 /**
dalyk7643abc2018-01-17 14:20:55 -05001424 * Compares this {@code LinkProperties} private DNS settings against the
1425 * target.
1426 *
1427 * @param target LinkProperties to compare.
1428 * @return {@code true} if both are identical, {@code false} otherwise.
1429 * @hide
1430 */
paulhucbbc3db2019-03-08 16:35:20 +08001431 public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) {
dalyk7643abc2018-01-17 14:20:55 -05001432 return (isPrivateDnsActive() == target.isPrivateDnsActive()
1433 && TextUtils.equals(getPrivateDnsServerName(),
1434 target.getPrivateDnsServerName()));
1435 }
1436
1437 /**
Chalard Jean299d8562018-04-11 16:36:41 +09001438 * Compares this {@code LinkProperties} validated private DNS addresses against
1439 * the target
1440 *
1441 * @param target LinkProperties to compare.
1442 * @return {@code true} if both are identical, {@code false} otherwise.
1443 * @hide
1444 */
paulhucbbc3db2019-03-08 16:35:20 +08001445 public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) {
Chalard Jean299d8562018-04-11 16:36:41 +09001446 Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers();
1447 return (mValidatedPrivateDnses.size() == targetDnses.size())
1448 ? mValidatedPrivateDnses.containsAll(targetDnses) : false;
1449 }
1450
1451 /**
Hongshike2d7cf52018-06-28 20:42:19 +09001452 * Compares this {@code LinkProperties} PCSCF addresses against 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 isIdenticalPcscfs(@NonNull LinkProperties target) {
Maciej Żenczykowskif7939fa2023-05-18 03:44:27 +00001459 // Per 3GPP TS 24.229, B.2.2.1 PDP context activation and P-CSCF discovery
1460 // list order is important, so on U+ compare one by one
1461 if (SdkLevel.isAtLeastU()) return target.getPcscfServers().equals(mPcscfs);
1462 // but for safety old behaviour on pre-U:
1463 Collection<InetAddress> targetPcscfs = target.getPcscfServers();
1464 return (mPcscfs.size() == targetPcscfs.size()) ?
1465 mPcscfs.containsAll(targetPcscfs) : false;
Hongshike2d7cf52018-06-28 20:42:19 +09001466 }
1467
1468 /**
Wink Saville051a6642011-07-13 13:44:13 -07001469 * Compares this {@code LinkProperties} Routes against the target
1470 *
1471 * @param target LinkProperties to compare.
1472 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001473 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001474 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001475 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001476 public boolean isIdenticalRoutes(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001477 return LinkPropertiesUtils.isIdenticalRoutes(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001478 }
1479
1480 /**
1481 * Compares this {@code LinkProperties} HttpProxy against the target
1482 *
1483 * @param target LinkProperties to compare.
1484 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001485 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001486 */
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +00001487 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
paulhucbbc3db2019-03-08 16:35:20 +08001488 public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001489 return LinkPropertiesUtils.isIdenticalHttpProxy(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001490 }
John Wang3e567d52011-04-04 12:35:42 -07001491
Lorenzo Colittic0803122013-03-07 10:59:25 -08001492 /**
1493 * Compares this {@code LinkProperties} stacked links against the target
1494 *
1495 * @param target LinkProperties to compare.
1496 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001497 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -08001498 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +00001499 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
paulhucbbc3db2019-03-08 16:35:20 +08001500 public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) {
Lorenzo Colitti89218e52013-04-01 10:47:43 +09001501 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
Lorenzo Colittic0803122013-03-07 10:59:25 -08001502 return false;
1503 }
1504 for (LinkProperties stacked : mStackedLinks.values()) {
1505 // Hashtable values can never be null.
1506 String iface = stacked.getInterfaceName();
1507 if (!stacked.equals(target.mStackedLinks.get(iface))) {
1508 return false;
1509 }
1510 }
1511 return true;
1512 }
1513
sy.yun4aa73922013-09-02 05:24:09 +09001514 /**
1515 * Compares this {@code LinkProperties} MTU against the target
1516 *
Ying Wangcb5620b2013-09-06 22:53:16 -07001517 * @param target LinkProperties to compare.
sy.yun4aa73922013-09-02 05:24:09 +09001518 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001519 * @hide
sy.yun4aa73922013-09-02 05:24:09 +09001520 */
paulhucbbc3db2019-03-08 16:35:20 +08001521 public boolean isIdenticalMtu(@NonNull LinkProperties target) {
sy.yun4aa73922013-09-02 05:24:09 +09001522 return getMtu() == target.getMtu();
1523 }
1524
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001525 /**
1526 * Compares this {@code LinkProperties} Tcp buffer sizes against the target.
1527 *
1528 * @param target LinkProperties to compare.
1529 * @return {@code true} if both are identical, {@code false} otherwise.
1530 * @hide
1531 */
paulhucbbc3db2019-03-08 16:35:20 +08001532 public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001533 return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
1534 }
1535
John Wang3e567d52011-04-04 12:35:42 -07001536 /**
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001537 * Compares this {@code LinkProperties} NAT64 prefix against the target.
1538 *
1539 * @param target LinkProperties to compare.
1540 * @return {@code true} if both are identical, {@code false} otherwise.
1541 * @hide
1542 */
paulhucbbc3db2019-03-08 16:35:20 +08001543 public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) {
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001544 return Objects.equals(mNat64Prefix, target.mNat64Prefix);
1545 }
1546
1547 /**
Valentin Iftime9fa35092019-09-24 13:32:13 +02001548 * Compares this {@code LinkProperties} WakeOnLan supported against the target.
1549 *
1550 * @param target LinkProperties to compare.
1551 * @return {@code true} if both are identical, {@code false} otherwise.
1552 * @hide
1553 */
1554 public boolean isIdenticalWakeOnLan(LinkProperties target) {
1555 return isWakeOnLanSupported() == target.isWakeOnLanSupported();
1556 }
1557
1558 /**
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001559 * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target.
1560 *
1561 * @param target LinkProperties to compare.
1562 * @return {@code true} if both are identical, {@code false} otherwise.
1563 * @hide
1564 */
1565 public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) {
1566 return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl);
1567 }
1568
1569 /**
1570 * Compares this {@code LinkProperties}'s CaptivePortalData against the target.
1571 *
1572 * @param target LinkProperties to compare.
1573 * @return {@code true} if both are identical, {@code false} otherwise.
1574 * @hide
1575 */
1576 public boolean isIdenticalCaptivePortalData(LinkProperties target) {
1577 return Objects.equals(mCaptivePortalData, target.mCaptivePortalData);
1578 }
1579
1580 /**
Valentin Iftime9fa35092019-09-24 13:32:13 +02001581 * Set whether the network interface supports WakeOnLAN
1582 *
1583 * @param supported WakeOnLAN supported value
1584 *
1585 * @hide
1586 */
1587 public void setWakeOnLanSupported(boolean supported) {
1588 mWakeOnLanSupported = supported;
1589 }
1590
1591 /**
1592 * Returns whether the network interface supports WakeOnLAN
1593 *
1594 * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
1595 */
1596 public boolean isWakeOnLanSupported() {
1597 return mWakeOnLanSupported;
1598 }
1599
1600 /**
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001601 * Set the URL of the captive portal API endpoint to get more information about the network.
1602 * @hide
1603 */
1604 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001605 public void setCaptivePortalApiUrl(@Nullable Uri url) {
1606 mCaptivePortalApiUrl = url;
1607 }
1608
1609 /**
1610 * Get the URL of the captive portal API endpoint to get more information about the network.
1611 *
1612 * <p>This is null unless the application has
1613 * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1614 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided
1615 * the URL.
1616 * @hide
1617 */
1618 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001619 @Nullable
1620 public Uri getCaptivePortalApiUrl() {
1621 return mCaptivePortalApiUrl;
1622 }
1623
1624 /**
1625 * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1626 * @hide
1627 */
1628 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001629 public void setCaptivePortalData(@Nullable CaptivePortalData data) {
1630 mCaptivePortalData = data;
1631 }
1632
1633 /**
1634 * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1635 *
1636 * <p>This is null unless the application has
1637 * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1638 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions.
1639 * @hide
1640 */
1641 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001642 @Nullable
1643 public CaptivePortalData getCaptivePortalData() {
1644 return mCaptivePortalData;
1645 }
1646
1647 /**
John Wang3e567d52011-04-04 12:35:42 -07001648 * Compares this {@code LinkProperties} instance against the target
1649 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
1650 * all their fields are equal in values.
1651 *
1652 * For collection fields, such as mDnses, containsAll() is used to check
1653 * if two collections contains the same elements, independent of order.
1654 * There are two thoughts regarding containsAll()
1655 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
1656 * 2. Worst case performance is O(n^2).
1657 *
1658 * @param obj the object to be tested for equality.
1659 * @return {@code true} if both objects are equal, {@code false} otherwise.
1660 */
Chalard Jeand51966a2018-06-07 13:27:00 +09001661 @Override
Roman Kalukiewicz384a8c62020-10-14 15:59:06 -07001662 public boolean equals(@Nullable Object obj) {
John Wang3e567d52011-04-04 12:35:42 -07001663 if (this == obj) return true;
1664
1665 if (!(obj instanceof LinkProperties)) return false;
1666
John Wang3e567d52011-04-04 12:35:42 -07001667 LinkProperties target = (LinkProperties) obj;
Chalard Jeand51966a2018-06-07 13:27:00 +09001668 /*
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001669 * This method does not check that stacked interfaces are equal, because
1670 * stacked interfaces are not so much a property of the link as a
1671 * description of connections between links.
1672 */
dalyk7643abc2018-01-17 14:20:55 -05001673 return isIdenticalInterfaceName(target)
1674 && isIdenticalAddresses(target)
ruibin zhangca75bc82019-05-23 19:35:30 +08001675 && isIdenticalDhcpServerAddress(target)
dalyk7643abc2018-01-17 14:20:55 -05001676 && isIdenticalDnses(target)
1677 && isIdenticalPrivateDns(target)
Chalard Jean299d8562018-04-11 16:36:41 +09001678 && isIdenticalValidatedPrivateDnses(target)
Hongshike2d7cf52018-06-28 20:42:19 +09001679 && isIdenticalPcscfs(target)
dalyk7643abc2018-01-17 14:20:55 -05001680 && isIdenticalRoutes(target)
1681 && isIdenticalHttpProxy(target)
1682 && isIdenticalStackedLinks(target)
1683 && isIdenticalMtu(target)
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001684 && isIdenticalTcpBufferSizes(target)
Valentin Iftime9fa35092019-09-24 13:32:13 +02001685 && isIdenticalNat64Prefix(target)
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001686 && isIdenticalWakeOnLan(target)
1687 && isIdenticalCaptivePortalApiUrl(target)
1688 && isIdenticalCaptivePortalData(target);
Wink Saville051a6642011-07-13 13:44:13 -07001689 }
John Wang3e567d52011-04-04 12:35:42 -07001690
Wink Saville051a6642011-07-13 13:44:13 -07001691 /**
Chalard Jeand51966a2018-06-07 13:27:00 +09001692 * Generate hashcode based on significant fields
1693 *
John Wang3e567d52011-04-04 12:35:42 -07001694 * Equal objects must produce the same hash code, while unequal objects
1695 * may have the same hash codes.
1696 */
Chalard Jeand51966a2018-06-07 13:27:00 +09001697 @Override
John Wang3e567d52011-04-04 12:35:42 -07001698 public int hashCode() {
1699 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
1700 + mLinkAddresses.size() * 31
1701 + mDnses.size() * 37
Chalard Jean299d8562018-04-11 16:36:41 +09001702 + mValidatedPrivateDnses.size() * 61
Robert Greenwaltcd277852012-11-09 10:52:27 -08001703 + ((null == mDomains) ? 0 : mDomains.hashCode())
Robert Greenwalt5a901292011-04-28 14:28:50 -07001704 + mRoutes.size() * 41
Lorenzo Colittic0803122013-03-07 10:59:25 -08001705 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
sy.yun4aa73922013-09-02 05:24:09 +09001706 + mStackedLinks.hashCode() * 47)
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001707 + mMtu * 51
dalyk7643abc2018-01-17 14:20:55 -05001708 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
1709 + (mUsePrivateDns ? 57 : 0)
ruibin zhangca75bc82019-05-23 19:35:30 +08001710 + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode())
Hongshike2d7cf52018-06-28 20:42:19 +09001711 + mPcscfs.size() * 67
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001712 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
Valentin Iftime9fa35092019-09-24 13:32:13 +02001713 + Objects.hash(mNat64Prefix)
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001714 + (mWakeOnLanSupported ? 71 : 0)
1715 + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData);
John Wang3e567d52011-04-04 12:35:42 -07001716 }
1717
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001718 /**
1719 * Implement the Parcelable interface.
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001720 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001721 public void writeToParcel(Parcel dest, int flags) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001722 dest.writeString(getInterfaceName());
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001723 dest.writeInt(mLinkAddresses.size());
Chalard Jean299d8562018-04-11 16:36:41 +09001724 for (LinkAddress linkAddress : mLinkAddresses) {
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001725 dest.writeParcelable(linkAddress, flags);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001726 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001727
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001728 writeAddresses(dest, mDnses);
1729 writeAddresses(dest, mValidatedPrivateDnses);
dalyk7643abc2018-01-17 14:20:55 -05001730 dest.writeBoolean(mUsePrivateDns);
1731 dest.writeString(mPrivateDnsServerName);
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001732 writeAddresses(dest, mPcscfs);
Robert Greenwaltcd277852012-11-09 10:52:27 -08001733 dest.writeString(mDomains);
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001734 writeAddress(dest, mDhcpServerAddress);
sy.yun4aa73922013-09-02 05:24:09 +09001735 dest.writeInt(mMtu);
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001736 dest.writeString(mTcpBufferSizes);
Robert Greenwalt5a901292011-04-28 14:28:50 -07001737 dest.writeInt(mRoutes.size());
Chalard Jean299d8562018-04-11 16:36:41 +09001738 for (RouteInfo route : mRoutes) {
Robert Greenwalt5a901292011-04-28 14:28:50 -07001739 dest.writeParcelable(route, flags);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001740 }
Robert Greenwalt5c733972011-02-09 13:56:06 -08001741
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001742 if (mHttpProxy != null) {
1743 dest.writeByte((byte)1);
1744 dest.writeParcelable(mHttpProxy, flags);
1745 } else {
1746 dest.writeByte((byte)0);
1747 }
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001748 dest.writeParcelable(mNat64Prefix, 0);
1749
Chalard Jeand51966a2018-06-07 13:27:00 +09001750 ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
Lorenzo Colittic0803122013-03-07 10:59:25 -08001751 dest.writeList(stackedLinks);
Valentin Iftime9fa35092019-09-24 13:32:13 +02001752
1753 dest.writeBoolean(mWakeOnLanSupported);
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001754 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0);
1755 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001756 }
1757
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001758 private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) {
1759 dest.writeInt(list.size());
1760 for (InetAddress d : list) {
1761 writeAddress(dest, d);
1762 }
1763 }
1764
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001765 private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) {
1766 byte[] addressBytes = (addr == null ? null : addr.getAddress());
1767 dest.writeByteArray(addressBytes);
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001768 if (addr instanceof Inet6Address) {
1769 final Inet6Address v6Addr = (Inet6Address) addr;
1770 final boolean hasScopeId = v6Addr.getScopeId() != 0;
1771 dest.writeBoolean(hasScopeId);
1772 if (hasScopeId) dest.writeInt(v6Addr.getScopeId());
1773 }
1774 }
1775
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001776 @Nullable
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001777 private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException {
1778 final byte[] addr = p.createByteArray();
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001779 if (addr == null) return null;
1780
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001781 if (addr.length == INET6_ADDR_LENGTH) {
1782 final boolean hasScopeId = p.readBoolean();
1783 final int scopeId = hasScopeId ? p.readInt() : 0;
1784 return Inet6Address.getByAddress(null /* host */, addr, scopeId);
1785 }
1786
1787 return InetAddress.getByAddress(addr);
1788 }
1789
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001790 /**
1791 * Implement the Parcelable interface.
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001792 */
Jeff Sharkeyf8525282019-02-28 12:06:45 -07001793 public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR =
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001794 new Creator<LinkProperties>() {
1795 public LinkProperties createFromParcel(Parcel in) {
1796 LinkProperties netProp = new LinkProperties();
Robert Greenwalt462e5702012-10-31 14:32:53 -07001797
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001798 String iface = in.readString();
1799 if (iface != null) {
Robert Greenwalt462e5702012-10-31 14:32:53 -07001800 netProp.setInterfaceName(iface);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001801 }
1802 int addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001803 for (int i = 0; i < addressCount; i++) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001804 netProp.addLinkAddress(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001805 }
1806 addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001807 for (int i = 0; i < addressCount; i++) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001808 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001809 netProp.addDnsServer(readAddress(in));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001810 } catch (UnknownHostException e) { }
1811 }
Chalard Jean299d8562018-04-11 16:36:41 +09001812 addressCount = in.readInt();
1813 for (int i = 0; i < addressCount; i++) {
1814 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001815 netProp.addValidatedPrivateDnsServer(readAddress(in));
Chalard Jean299d8562018-04-11 16:36:41 +09001816 } catch (UnknownHostException e) { }
1817 }
dalyk7643abc2018-01-17 14:20:55 -05001818 netProp.setUsePrivateDns(in.readBoolean());
1819 netProp.setPrivateDnsServerName(in.readString());
Hongshike2d7cf52018-06-28 20:42:19 +09001820 addressCount = in.readInt();
1821 for (int i = 0; i < addressCount; i++) {
1822 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001823 netProp.addPcscfServer(readAddress(in));
Hongshike2d7cf52018-06-28 20:42:19 +09001824 } catch (UnknownHostException e) { }
1825 }
Robert Greenwaltcd277852012-11-09 10:52:27 -08001826 netProp.setDomains(in.readString());
ruibin zhangca75bc82019-05-23 19:35:30 +08001827 try {
1828 netProp.setDhcpServerAddress((Inet4Address) InetAddress
1829 .getByAddress(in.createByteArray()));
1830 } catch (UnknownHostException e) { }
sy.yun4aa73922013-09-02 05:24:09 +09001831 netProp.setMtu(in.readInt());
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001832 netProp.setTcpBufferSizes(in.readString());
Robert Greenwalt5c733972011-02-09 13:56:06 -08001833 addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001834 for (int i = 0; i < addressCount; i++) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001835 netProp.addRoute(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001836 }
1837 if (in.readByte() == 1) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001838 netProp.setHttpProxy(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001839 }
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001840 netProp.setNat64Prefix(in.readParcelable(null));
Lorenzo Colittic0803122013-03-07 10:59:25 -08001841 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
1842 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
1843 for (LinkProperties stackedLink: stackedLinks) {
1844 netProp.addStackedLink(stackedLink);
1845 }
Valentin Iftime9fa35092019-09-24 13:32:13 +02001846 netProp.setWakeOnLanSupported(in.readBoolean());
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001847
1848 netProp.setCaptivePortalApiUrl(in.readParcelable(null));
1849 netProp.setCaptivePortalData(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001850 return netProp;
1851 }
1852
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001853 public LinkProperties[] newArray(int size) {
1854 return new LinkProperties[size];
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001855 }
1856 };
w19976e714f1d2014-08-05 15:18:11 -07001857
Chalard Jean299d8562018-04-11 16:36:41 +09001858 /**
1859 * Check the valid MTU range based on IPv4 or IPv6.
1860 * @hide
1861 */
1862 public static boolean isValidMtu(int mtu, boolean ipv6) {
1863 if (ipv6) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001864 return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU;
Chalard Jean299d8562018-04-11 16:36:41 +09001865 } else {
Chalard Jeand51966a2018-06-07 13:27:00 +09001866 return mtu >= MIN_MTU && mtu <= MAX_MTU;
w19976e714f1d2014-08-05 15:18:11 -07001867 }
Chalard Jean299d8562018-04-11 16:36:41 +09001868 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001869}