blob: b7ee84698c731fb6ab6e0c6e658924ee7e17861c [file] [log] [blame]
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001/*
Wink Saville17465432010-09-21 09:15:35 -07002 * Copyright (C) 2010 The Android Open Source Project
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net;
18
Jeff Sharkey0aef9342014-08-11 15:22:51 -070019import android.annotation.NonNull;
Jeff Sharkeyf2ceed82014-08-14 12:55:00 -070020import android.annotation.Nullable;
paulhu058120d2018-12-12 17:52:57 +080021import android.annotation.SystemApi;
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020022import android.app.compat.CompatChanges;
23import android.compat.annotation.ChangeId;
24import android.compat.annotation.EnabledAfter;
Artur Satayev9c2add62019-12-10 17:47:52 +000025import android.compat.annotation.UnsupportedAppUsage;
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +000026import android.os.Build;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070027import android.os.Parcel;
Rubin Xuffd77d82017-09-05 18:40:49 +010028import android.os.Parcelable;
John Wang3e567d52011-04-04 12:35:42 -070029import android.text.TextUtils;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070030
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020031import com.android.internal.annotations.VisibleForTesting;
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +090032import com.android.modules.utils.build.SdkLevel;
33import com.android.net.module.util.CollectionUtils;
Chalard Jean79162542020-08-19 16:07:22 +090034import com.android.net.module.util.LinkPropertiesUtils;
35
Lorenzo Colittic0803122013-03-07 10:59:25 -080036import java.net.Inet4Address;
Lorenzo Colitti09de4182013-08-08 11:00:12 +090037import java.net.Inet6Address;
Rubin Xuffd77d82017-09-05 18:40:49 +010038import java.net.InetAddress;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070039import java.net.UnknownHostException;
40import java.util.ArrayList;
41import java.util.Collection;
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -070042import java.util.Collections;
Lorenzo Colittic0803122013-03-07 10:59:25 -080043import java.util.Hashtable;
Robert Greenwalt69aceaf2014-06-06 10:30:11 -070044import java.util.List;
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +090045import java.util.Objects;
Chalard Jeand51966a2018-06-07 13:27:00 +090046import java.util.StringJoiner;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070047
48/**
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -070049 * Describes the properties of a network link.
Robert Greenwalt5c733972011-02-09 13:56:06 -080050 *
51 * A link represents a connection to a network.
52 * It may have multiple addresses and multiple gateways,
Robert Greenwalteaa84d52014-05-18 22:01:38 -070053 * multiple dns servers but only one http proxy and one
54 * network interface.
Robert Greenwalt5c733972011-02-09 13:56:06 -080055 *
Robert Greenwalteaa84d52014-05-18 22:01:38 -070056 * Note that this is just a holder of data. Modifying it
57 * does not affect live networks.
Robert Greenwalt5c733972011-02-09 13:56:06 -080058 *
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070059 */
Robert Greenwaltc4920a52014-06-12 16:24:38 -070060public final class LinkProperties implements Parcelable {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020061 /**
62 * The {@link #getRoutes()} now can contain excluded as well as included routes. Use
63 * {@link RouteInfo#getType()} to determine route type.
64 *
65 * @hide
66 */
67 @ChangeId
Taras Antoshchukaf3c3602022-04-28 15:47:29 +020068 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
Taras Antoshchuk30d41e52021-08-02 18:06:35 +020069 @VisibleForTesting
70 public static final long EXCLUDED_ROUTES = 186082280;
71
Lorenzo Colittic0803122013-03-07 10:59:25 -080072 // The interface described by the network link.
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +000073 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Robert Greenwalt462e5702012-10-31 14:32:53 -070074 private String mIfaceName;
paulhucbbc3db2019-03-08 16:35:20 +080075 private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
76 private final ArrayList<InetAddress> mDnses = new ArrayList<>();
Hongshike2d7cf52018-06-28 20:42:19 +090077 // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
paulhucbbc3db2019-03-08 16:35:20 +080078 private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
79 private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
dalyk7643abc2018-01-17 14:20:55 -050080 private boolean mUsePrivateDns;
81 private String mPrivateDnsServerName;
Robert Greenwaltcd277852012-11-09 10:52:27 -080082 private String mDomains;
Chalard Jeand51966a2018-06-07 13:27:00 +090083 private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
ruibin zhangca75bc82019-05-23 19:35:30 +080084 private Inet4Address mDhcpServerAddress;
Jason Monk4d5e20f2014-04-25 15:00:09 -040085 private ProxyInfo mHttpProxy;
sy.yun4aa73922013-09-02 05:24:09 +090086 private int mMtu;
Robert Greenwaltdebf0e02014-08-06 12:00:25 -070087 // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
88 private String mTcpBufferSizes;
Lorenzo Colitti981b34f2019-01-08 09:58:59 +090089 private IpPrefix mNat64Prefix;
Valentin Iftime9fa35092019-09-24 13:32:13 +020090 private boolean mWakeOnLanSupported;
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +090091 private Uri mCaptivePortalApiUrl;
92 private CaptivePortalData mCaptivePortalData;
93
94 /**
95 * Indicates whether parceling should preserve fields that are set based on permissions of
96 * the process receiving the {@link LinkProperties}.
97 */
98 private final transient boolean mParcelSensitiveFields;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070099
w19976e714f1d2014-08-05 15:18:11 -0700100 private static final int MIN_MTU = 68;
Benedict Wongf3215112020-11-19 00:17:29 -0800101
Remi NGUYEN VAN00c5e702020-11-30 16:35:43 +0900102 private static final int MIN_MTU_V6 = 1280;
Benedict Wongf3215112020-11-19 00:17:29 -0800103
w19976e714f1d2014-08-05 15:18:11 -0700104 private static final int MAX_MTU = 10000;
105
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +0900106 private static final int INET6_ADDR_LENGTH = 16;
107
Lorenzo Colittic0803122013-03-07 10:59:25 -0800108 // Stores the properties of links that are "stacked" above this link.
109 // Indexed by interface name to allow modification and to prevent duplicates being added.
Chalard Jeand51966a2018-06-07 13:27:00 +0900110 private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
Lorenzo Colittic0803122013-03-07 10:59:25 -0800111
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700112 /**
113 * @hide
114 */
Artur Satayev56cb6bb2019-11-04 17:50:59 +0000115 @UnsupportedAppUsage(implicitMember =
116 "values()[Landroid/net/LinkProperties$ProvisioningChange;")
Erik Kline04612b02015-05-21 16:15:02 +0900117 public enum ProvisioningChange {
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100118 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900119 STILL_NOT_PROVISIONED,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100120 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900121 LOST_PROVISIONING,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100122 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900123 GAINED_PROVISIONING,
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100124 @UnsupportedAppUsage
Erik Kline04612b02015-05-21 16:15:02 +0900125 STILL_PROVISIONED,
126 }
127
128 /**
129 * Compare the provisioning states of two LinkProperties instances.
130 *
131 * @hide
132 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +0000133 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Erik Kline04612b02015-05-21 16:15:02 +0900134 public static ProvisioningChange compareProvisioning(
135 LinkProperties before, LinkProperties after) {
136 if (before.isProvisioned() && after.isProvisioned()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900137 // On dual-stack networks, DHCPv4 renewals can occasionally fail.
Erik Kline04612b02015-05-21 16:15:02 +0900138 // When this happens, IPv6-reachable services continue to function
139 // normally but IPv4-only services (naturally) fail.
140 //
141 // When an application using an IPv4-only service reports a bad
142 // network condition to the framework, attempts to re-validate
143 // the network succeed (since we support IPv6-only networks) and
144 // nothing is changed.
145 //
146 // For users, this is confusing and unexpected behaviour, and is
147 // not necessarily easy to diagnose. Therefore, we treat changing
Chalard Jeand51966a2018-06-07 13:27:00 +0900148 // from a dual-stack network to an IPv6-only network equivalent to
Erik Kline04612b02015-05-21 16:15:02 +0900149 // a total loss of provisioning.
150 //
151 // For one such example of this, see b/18867306.
152 //
Erik Klineaa8f8f32015-08-14 12:16:55 +0900153 // Additionally, losing IPv6 provisioning can result in TCP
154 // connections getting stuck until timeouts fire and other
155 // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
Chalard Jeand51966a2018-06-07 13:27:00 +0900156 // previously dual-stack network is deemed a lost of provisioning.
paulhucbbc3db2019-03-08 16:35:20 +0800157 if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned())
158 || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) {
Erik Kline04612b02015-05-21 16:15:02 +0900159 return ProvisioningChange.LOST_PROVISIONING;
160 }
161 return ProvisioningChange.STILL_PROVISIONED;
162 } else if (before.isProvisioned() && !after.isProvisioned()) {
163 return ProvisioningChange.LOST_PROVISIONING;
164 } else if (!before.isProvisioned() && after.isProvisioned()) {
165 return ProvisioningChange.GAINED_PROVISIONING;
166 } else { // !before.isProvisioned() && !after.isProvisioned()
167 return ProvisioningChange.STILL_NOT_PROVISIONED;
168 }
169 }
170
171 /**
paulhucbbc3db2019-03-08 16:35:20 +0800172 * Constructs a new {@code LinkProperties} with default values.
Erik Kline04612b02015-05-21 16:15:02 +0900173 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700174 public LinkProperties() {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900175 mParcelSensitiveFields = false;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700176 }
177
Sreeram Ramachandran887d7b12014-06-03 18:41:43 -0700178 /**
179 * @hide
180 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900181 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800182 public LinkProperties(@Nullable LinkProperties source) {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900183 this(source, false /* parcelSensitiveFields */);
184 }
185
Remi NGUYEN VAN8dd694d2020-03-16 14:48:37 +0900186 /**
187 * Create a copy of a {@link LinkProperties} that may preserve fields that were set
188 * based on the permissions of the process that originally received it.
189 *
190 * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
191 * they should not be shared outside of the process that receives them without appropriate
192 * checks.
193 * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling
194 * @hide
195 */
196 @SystemApi
Remi NGUYEN VAN8dd694d2020-03-16 14:48:37 +0900197 public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900198 mParcelSensitiveFields = parcelSensitiveFields;
199 if (source == null) return;
200 mIfaceName = source.mIfaceName;
201 mLinkAddresses.addAll(source.mLinkAddresses);
202 mDnses.addAll(source.mDnses);
203 mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
204 mUsePrivateDns = source.mUsePrivateDns;
205 mPrivateDnsServerName = source.mPrivateDnsServerName;
206 mPcscfs.addAll(source.mPcscfs);
207 mDomains = source.mDomains;
208 mRoutes.addAll(source.mRoutes);
209 mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
210 for (LinkProperties l: source.mStackedLinks.values()) {
211 addStackedLink(l);
Irfan Sherifffd151ec2010-08-30 20:37:17 -0700212 }
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900213 setMtu(source.mMtu);
214 setDhcpServerAddress(source.getDhcpServerAddress());
215 mTcpBufferSizes = source.mTcpBufferSizes;
216 mNat64Prefix = source.mNat64Prefix;
217 mWakeOnLanSupported = source.mWakeOnLanSupported;
218 mCaptivePortalApiUrl = source.mCaptivePortalApiUrl;
219 mCaptivePortalData = source.mCaptivePortalData;
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700220 }
221
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700222 /**
223 * Sets the interface name for this link. All {@link RouteInfo} already set for this
224 * will have their interface changed to match this new value.
225 *
226 * @param iface The name of the network interface used for this link.
227 */
paulhucbbc3db2019-03-08 16:35:20 +0800228 public void setInterfaceName(@Nullable String iface) {
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700229 mIfaceName = iface;
Chalard Jeand51966a2018-06-07 13:27:00 +0900230 ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800231 for (RouteInfo route : mRoutes) {
232 newRoutes.add(routeWithInterface(route));
233 }
234 mRoutes = newRoutes;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700235 }
236
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700237 /**
238 * Gets the interface name for this link. May be {@code null} if not set.
239 *
240 * @return The interface name set for this link or {@code null}.
241 */
Jeff Sharkeyf2ceed82014-08-14 12:55:00 -0700242 public @Nullable String getInterfaceName() {
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700243 return mIfaceName;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700244 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700245
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700246 /**
247 * @hide
248 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800249 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800250 public @NonNull List<String> getAllInterfaceNames() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900251 List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
252 if (mIfaceName != null) interfaceNames.add(mIfaceName);
Lorenzo Colitti63839822013-03-20 19:22:58 +0900253 for (LinkProperties stacked: mStackedLinks.values()) {
254 interfaceNames.addAll(stacked.getAllInterfaceNames());
255 }
256 return interfaceNames;
257 }
258
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900259 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700260 * Returns all the addresses on this link. We often think of a link having a single address,
261 * however, particularly with Ipv6 several addresses are typical. Note that the
262 * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
263 * prefix lengths for each address. This is a simplified utility alternative to
264 * {@link LinkProperties#getLinkAddresses}.
265 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900266 * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700267 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900268 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800269 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800270 public @NonNull List<InetAddress> getAddresses() {
271 final List<InetAddress> addresses = new ArrayList<>();
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700272 for (LinkAddress linkAddress : mLinkAddresses) {
273 addresses.add(linkAddress.getAddress());
274 }
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700275 return Collections.unmodifiableList(addresses);
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700276 }
277
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900278 /**
279 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700280 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900281 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100282 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +0800283 public @NonNull List<InetAddress> getAllAddresses() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900284 List<InetAddress> addresses = new ArrayList<>();
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900285 for (LinkAddress linkAddress : mLinkAddresses) {
286 addresses.add(linkAddress.getAddress());
287 }
288 for (LinkProperties stacked: mStackedLinks.values()) {
289 addresses.addAll(stacked.getAllAddresses());
290 }
291 return addresses;
292 }
293
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900294 private int findLinkAddressIndex(LinkAddress address) {
295 for (int i = 0; i < mLinkAddresses.size(); i++) {
296 if (mLinkAddresses.get(i).isSameAddressAs(address)) {
297 return i;
298 }
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900299 }
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900300 return -1;
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900301 }
302
303 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700304 * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
305 * same address/prefix does not already exist. If it does exist it is replaced.
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900306 * @param address The {@code LinkAddress} to add.
307 * @return true if {@code address} was added or updated, false otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700308 * @hide
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900309 */
Remi NGUYEN VANc7fe99f2019-01-29 12:08:43 +0900310 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800311 public boolean addLinkAddress(@NonNull LinkAddress address) {
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900312 if (address == null) {
313 return false;
314 }
315 int i = findLinkAddressIndex(address);
316 if (i < 0) {
317 // Address was not present. Add it.
318 mLinkAddresses.add(address);
319 return true;
320 } else if (mLinkAddresses.get(i).equals(address)) {
321 // Address was present and has same properties. Do nothing.
322 return false;
323 } else {
324 // Address was present and has different properties. Update it.
325 mLinkAddresses.set(i, address);
326 return true;
327 }
328 }
329
330 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700331 * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches
332 * and {@link LinkAddress} with the same address and prefix.
333 *
334 * @param toRemove A {@link LinkAddress} specifying the address to remove.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900335 * @return true if the address was removed, false if it did not exist.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700336 * @hide
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900337 */
Remi NGUYEN VANc7fe99f2019-01-29 12:08:43 +0900338 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800339 public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
Lorenzo Colitti61b65822013-11-15 18:43:52 +0900340 int i = findLinkAddressIndex(toRemove);
341 if (i >= 0) {
342 mLinkAddresses.remove(i);
343 return true;
344 }
345 return false;
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700346 }
347
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900348 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700349 * Returns all the {@link LinkAddress} on this link. Typically a link will have
350 * one IPv4 address and one or more IPv6 addresses.
351 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700352 * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900353 */
paulhucbbc3db2019-03-08 16:35:20 +0800354 public @NonNull List<LinkAddress> getLinkAddresses() {
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700355 return Collections.unmodifiableList(mLinkAddresses);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700356 }
357
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900358 /**
359 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700360 * @hide
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900361 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800362 @SystemApi
363 public @NonNull List<LinkAddress> getAllLinkAddresses() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900364 List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
Lorenzo Colittie1b47422013-07-31 23:23:21 +0900365 for (LinkProperties stacked: mStackedLinks.values()) {
366 addresses.addAll(stacked.getAllLinkAddresses());
367 }
368 return addresses;
369 }
370
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900371 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700372 * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
373 * the given {@link Collection} of {@link LinkAddress}.
374 *
375 * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
376 * object.
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900377 */
paulhucbbc3db2019-03-08 16:35:20 +0800378 public void setLinkAddresses(@NonNull Collection<LinkAddress> addresses) {
Lorenzo Colitti174782b2013-08-23 20:54:49 +0900379 mLinkAddresses.clear();
380 for (LinkAddress address: addresses) {
381 addLinkAddress(address);
382 }
383 }
384
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700385 /**
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900386 * Adds the given {@link InetAddress} to the list of DNS servers, if not present.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700387 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700388 * @param dnsServer The {@link InetAddress} to add to the list of DNS servers.
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900389 * @return true if the DNS server was added, false if it was already present.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700390 * @hide
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700391 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900392 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800393 public boolean addDnsServer(@NonNull InetAddress dnsServer) {
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900394 if (dnsServer != null && !mDnses.contains(dnsServer)) {
395 mDnses.add(dnsServer);
396 return true;
397 }
398 return false;
399 }
400
401 /**
Erik Kline04612b02015-05-21 16:15:02 +0900402 * Removes the given {@link InetAddress} from the list of DNS servers.
403 *
404 * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers.
405 * @return true if the DNS server was removed, false if it did not exist.
406 * @hide
407 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900408 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800409 public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
paulhu1a407652019-03-22 16:35:06 +0800410 return mDnses.remove(dnsServer);
Erik Kline04612b02015-05-21 16:15:02 +0900411 }
412
413 /**
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900414 * Replaces the DNS servers in this {@code LinkProperties} with
415 * the given {@link Collection} of {@link InetAddress} objects.
416 *
Chalard Jean299d8562018-04-11 16:36:41 +0900417 * @param dnsServers The {@link Collection} of DNS servers to set in this object.
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900418 */
paulhucbbc3db2019-03-08 16:35:20 +0800419 public void setDnsServers(@NonNull Collection<InetAddress> dnsServers) {
Lorenzo Colitti131eb312014-06-24 00:34:39 +0900420 mDnses.clear();
421 for (InetAddress dnsServer: dnsServers) {
422 addDnsServer(dnsServer);
423 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700424 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700425
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700426 /**
Sreeram Ramachandran887d7b12014-06-03 18:41:43 -0700427 * Returns all the {@link InetAddress} for DNS servers on this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700428 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900429 * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700430 * this link.
431 */
paulhucbbc3db2019-03-08 16:35:20 +0800432 public @NonNull List<InetAddress> getDnsServers() {
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700433 return Collections.unmodifiableList(mDnses);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700434 }
435
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700436 /**
dalyk7643abc2018-01-17 14:20:55 -0500437 * Set whether private DNS is currently in use on this network.
438 *
439 * @param usePrivateDns The private DNS state.
440 * @hide
441 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900442 @SystemApi
dalyk7643abc2018-01-17 14:20:55 -0500443 public void setUsePrivateDns(boolean usePrivateDns) {
444 mUsePrivateDns = usePrivateDns;
445 }
446
447 /**
448 * Returns whether private DNS is currently in use on this network. When
449 * private DNS is in use, applications must not send unencrypted DNS
450 * queries as doing so could reveal private user information. Furthermore,
451 * if private DNS is in use and {@link #getPrivateDnsServerName} is not
452 * {@code null}, DNS queries must be sent to the specified DNS server.
453 *
454 * @return {@code true} if private DNS is in use, {@code false} otherwise.
455 */
456 public boolean isPrivateDnsActive() {
457 return mUsePrivateDns;
458 }
459
460 /**
461 * Set the name of the private DNS server to which private DNS queries
462 * should be sent when in strict mode. This value should be {@code null}
463 * when private DNS is off or in opportunistic mode.
464 *
465 * @param privateDnsServerName The private DNS server name.
466 * @hide
467 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900468 @SystemApi
dalyk7643abc2018-01-17 14:20:55 -0500469 public void setPrivateDnsServerName(@Nullable String privateDnsServerName) {
470 mPrivateDnsServerName = privateDnsServerName;
471 }
472
473 /**
ruibin zhangca75bc82019-05-23 19:35:30 +0800474 * Set DHCP server address.
475 *
476 * @param serverAddress the server address to set.
477 */
478 public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) {
479 mDhcpServerAddress = serverAddress;
480 }
481
482 /**
483 * Get DHCP server address
484 *
485 * @return The current DHCP server address.
486 */
487 public @Nullable Inet4Address getDhcpServerAddress() {
488 return mDhcpServerAddress;
489 }
490
491 /**
dalyk7643abc2018-01-17 14:20:55 -0500492 * Returns the private DNS server name that is in use. If not {@code null},
493 * private DNS is in strict mode. In this mode, applications should ensure
494 * that all DNS queries are encrypted and sent to this hostname and that
495 * queries are only sent if the hostname's certificate is valid. If
496 * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private
497 * DNS is in opportunistic mode, and applications should ensure that DNS
498 * queries are encrypted and sent to a DNS server returned by
499 * {@link #getDnsServers}. System DNS will handle each of these cases
500 * correctly, but applications implementing their own DNS lookups must make
501 * sure to follow these requirements.
502 *
503 * @return The private DNS server name.
504 */
505 public @Nullable String getPrivateDnsServerName() {
506 return mPrivateDnsServerName;
507 }
508
509 /**
Chalard Jean299d8562018-04-11 16:36:41 +0900510 * Adds the given {@link InetAddress} to the list of validated private DNS servers,
511 * if not present. This is distinct from the server name in that these are actually
512 * resolved addresses.
513 *
514 * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers.
515 * @return true if the DNS server was added, false if it was already present.
516 * @hide
517 */
paulhucbbc3db2019-03-08 16:35:20 +0800518 public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
Chalard Jean299d8562018-04-11 16:36:41 +0900519 if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) {
520 mValidatedPrivateDnses.add(dnsServer);
521 return true;
522 }
523 return false;
524 }
525
526 /**
527 * Removes the given {@link InetAddress} from the list of validated private DNS servers.
528 *
529 * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS
530 * servers.
531 * @return true if the DNS server was removed, false if it did not exist.
532 * @hide
533 */
paulhucbbc3db2019-03-08 16:35:20 +0800534 public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
535 return mValidatedPrivateDnses.remove(dnsServer);
Chalard Jean299d8562018-04-11 16:36:41 +0900536 }
537
538 /**
539 * Replaces the validated private DNS servers in this {@code LinkProperties} with
540 * the given {@link Collection} of {@link InetAddress} objects.
541 *
542 * @param dnsServers The {@link Collection} of validated private DNS servers to set in this
543 * object.
544 * @hide
545 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900546 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800547 public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) {
Chalard Jean299d8562018-04-11 16:36:41 +0900548 mValidatedPrivateDnses.clear();
549 for (InetAddress dnsServer: dnsServers) {
550 addValidatedPrivateDnsServer(dnsServer);
551 }
552 }
553
554 /**
555 * Returns all the {@link InetAddress} for validated private DNS servers on this link.
556 * These are resolved from the private DNS server name.
557 *
paulhucbbc3db2019-03-08 16:35:20 +0800558 * @return An unmodifiable {@link List} of {@link InetAddress} for validated private
Chalard Jean299d8562018-04-11 16:36:41 +0900559 * DNS servers on this link.
560 * @hide
561 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900562 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800563 public @NonNull List<InetAddress> getValidatedPrivateDnsServers() {
Chalard Jean299d8562018-04-11 16:36:41 +0900564 return Collections.unmodifiableList(mValidatedPrivateDnses);
565 }
566
567 /**
Hongshike2d7cf52018-06-28 20:42:19 +0900568 * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present.
569 *
570 * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers.
571 * @return true if the PCSCF server was added, false otherwise.
572 * @hide
573 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800574 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800575 public boolean addPcscfServer(@NonNull InetAddress pcscfServer) {
Hongshike2d7cf52018-06-28 20:42:19 +0900576 if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
577 mPcscfs.add(pcscfServer);
578 return true;
579 }
580 return false;
581 }
582
583 /**
584 * Removes the given {@link InetAddress} from the list of PCSCF servers.
585 *
paulhucbbc3db2019-03-08 16:35:20 +0800586 * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers.
Hongshike2d7cf52018-06-28 20:42:19 +0900587 * @return true if the PCSCF server was removed, false otherwise.
588 * @hide
589 */
paulhucbbc3db2019-03-08 16:35:20 +0800590 public boolean removePcscfServer(@NonNull InetAddress pcscfServer) {
591 return mPcscfs.remove(pcscfServer);
Hongshike2d7cf52018-06-28 20:42:19 +0900592 }
593
594 /**
595 * Replaces the PCSCF servers in this {@code LinkProperties} with
596 * the given {@link Collection} of {@link InetAddress} objects.
597 *
paulhucbbc3db2019-03-08 16:35:20 +0800598 * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object.
Hongshike2d7cf52018-06-28 20:42:19 +0900599 * @hide
600 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900601 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800602 public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) {
Hongshike2d7cf52018-06-28 20:42:19 +0900603 mPcscfs.clear();
604 for (InetAddress pcscfServer: pcscfServers) {
605 addPcscfServer(pcscfServer);
606 }
607 }
608
609 /**
610 * Returns all the {@link InetAddress} for PCSCF servers on this link.
611 *
612 * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on
613 * this link.
614 * @hide
615 */
Remi NGUYEN VANd9f75862019-01-23 21:35:52 +0900616 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800617 public @NonNull List<InetAddress> getPcscfServers() {
Hongshike2d7cf52018-06-28 20:42:19 +0900618 return Collections.unmodifiableList(mPcscfs);
619 }
620
621 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700622 * Sets the DNS domain search path used on this link.
623 *
624 * @param domains A {@link String} listing in priority order the comma separated
625 * domains to search when resolving host names on this link.
626 */
paulhucbbc3db2019-03-08 16:35:20 +0800627 public void setDomains(@Nullable String domains) {
Robert Greenwaltcd277852012-11-09 10:52:27 -0800628 mDomains = domains;
629 }
630
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700631 /**
paulhucbbc3db2019-03-08 16:35:20 +0800632 * Get the DNS domains search path set for this link. May be {@code null} if not set.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700633 *
paulhucbbc3db2019-03-08 16:35:20 +0800634 * @return A {@link String} containing the comma separated domains to search when resolving host
635 * names on this link or {@code null}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700636 */
paulhucbbc3db2019-03-08 16:35:20 +0800637 public @Nullable String getDomains() {
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700638 return mDomains;
639 }
640
641 /**
642 * Sets the Maximum Transmission Unit size to use on this link. This should not be used
643 * unless the system default (1500) is incorrect. Values less than 68 or greater than
644 * 10000 will be ignored.
645 *
646 * @param mtu The MTU to use for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700647 */
sy.yun4aa73922013-09-02 05:24:09 +0900648 public void setMtu(int mtu) {
649 mMtu = mtu;
650 }
651
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700652 /**
653 * Gets any non-default MTU size set for this link. Note that if the default is being used
654 * this will return 0.
655 *
656 * @return The mtu value set for this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700657 */
sy.yun4aa73922013-09-02 05:24:09 +0900658 public int getMtu() {
659 return mMtu;
660 }
661
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700662 /**
663 * Sets the tcp buffers sizes to be used when this link is the system default.
664 * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max".
665 *
666 * @param tcpBufferSizes The tcp buffers sizes to use.
667 *
668 * @hide
669 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900670 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800671 public void setTcpBufferSizes(@Nullable String tcpBufferSizes) {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700672 mTcpBufferSizes = tcpBufferSizes;
673 }
674
675 /**
paulhucbbc3db2019-03-08 16:35:20 +0800676 * Gets the tcp buffer sizes. May be {@code null} if not set.
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700677 *
paulhucbbc3db2019-03-08 16:35:20 +0800678 * @return the tcp buffer sizes to use when this link is the system default or {@code null}.
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700679 *
680 * @hide
681 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900682 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800683 public @Nullable String getTcpBufferSizes() {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700684 return mTcpBufferSizes;
685 }
686
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800687 private RouteInfo routeWithInterface(RouteInfo route) {
688 return new RouteInfo(
689 route.getDestination(),
690 route.getGateway(),
Lorenzo Colitti21290342014-09-19 01:49:05 +0900691 mIfaceName,
Tyler Weare4314862019-12-05 14:55:30 -0800692 route.getType(),
693 route.getMtu());
694 }
695
junyulaia1493a52020-03-23 20:49:43 +0800696 private int findRouteIndexByRouteKey(RouteInfo route) {
Tyler Weare4314862019-12-05 14:55:30 -0800697 for (int i = 0; i < mRoutes.size(); i++) {
junyulaia1493a52020-03-23 20:49:43 +0800698 if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) {
Tyler Weare4314862019-12-05 14:55:30 -0800699 return i;
700 }
701 }
702 return -1;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700703 }
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800704
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700705 /**
Chiachang Wang52a55922021-04-15 16:04:00 +0800706 * Adds a {@link RouteInfo} to this {@code LinkProperties}. If there is a {@link RouteInfo}
707 * with the same destination, gateway and interface with different properties
junyulaia1493a52020-03-23 20:49:43 +0800708 * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an
709 * interface name set and that differs from the interface set for this
710 * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.
711 * The proper course is to add either un-named or properly named {@link RouteInfo}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700712 *
713 * @param route A {@link RouteInfo} to add to this object.
Tyler Weare4314862019-12-05 14:55:30 -0800714 * @return {@code true} was added or updated, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700715 */
paulhucbbc3db2019-03-08 16:35:20 +0800716 public boolean addRoute(@NonNull RouteInfo route) {
717 String routeIface = route.getInterface();
718 if (routeIface != null && !routeIface.equals(mIfaceName)) {
719 throw new IllegalArgumentException(
720 "Route added with non-matching interface: " + routeIface
721 + " vs. " + mIfaceName);
722 }
723 route = routeWithInterface(route);
Tyler Weare4314862019-12-05 14:55:30 -0800724
junyulaia1493a52020-03-23 20:49:43 +0800725 int i = findRouteIndexByRouteKey(route);
Tyler Weare4314862019-12-05 14:55:30 -0800726 if (i == -1) {
727 // Route was not present. Add it.
paulhucbbc3db2019-03-08 16:35:20 +0800728 mRoutes.add(route);
729 return true;
Tyler Weare4314862019-12-05 14:55:30 -0800730 } else if (mRoutes.get(i).equals(route)) {
731 // Route was present and has same properties. Do nothing.
732 return false;
733 } else {
734 // Route was present and has different properties. Update it.
735 mRoutes.set(i, route);
736 return true;
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800737 }
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +0900738 }
739
740 /**
741 * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
742 * specify an interface and the interface must match the interface of this
743 * {@code LinkProperties}, or it will not be removed.
744 *
Tyler Weare4314862019-12-05 14:55:30 -0800745 * @param route A {@link RouteInfo} specifying the route to remove.
Lorenzo Colitti36ddd9d2014-06-12 23:10:17 +0900746 * @return {@code true} if the route was removed, {@code false} if it was not present.
747 *
748 * @hide
749 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +0900750 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800751 public boolean removeRoute(@NonNull RouteInfo route) {
752 return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route);
Lorenzo Colitti73b97852013-03-08 11:30:39 -0800753 }
754
Lorenzo Colittic0803122013-03-07 10:59:25 -0800755 /**
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700756 * Returns all the {@link RouteInfo} set on this link.
757 *
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200758 * Only unicast routes are returned for apps targeting Android S or below.
759 *
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700760 * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
Lorenzo Colittic0803122013-03-07 10:59:25 -0800761 */
paulhucbbc3db2019-03-08 16:35:20 +0800762 public @NonNull List<RouteInfo> getRoutes() {
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900763 // Before T, there's no throw routes because VpnService is not updatable, so no need to
764 // filter them out.
765 if (CompatChanges.isChangeEnabled(EXCLUDED_ROUTES) || !SdkLevel.isAtLeastT()) {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200766 return Collections.unmodifiableList(mRoutes);
767 } else {
Remi NGUYEN VAN66c27c12022-07-14 18:50:10 +0900768 // Apps that added a throw route themselves (not obtaining LinkProperties from the
769 // system) will not see it in getRoutes on T+ if they do not have the compat change
770 // enabled (target SDK < T); but this is expected to be rare and typically only affect
771 // tests creating LinkProperties themselves (like CTS v12, which is only running on S).
Remi NGUYEN VAN48380e42022-07-15 16:42:49 +0900772 return Collections.unmodifiableList(getUnicastRoutes());
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200773 }
774 }
775
776 /**
Remi NGUYEN VAN48380e42022-07-15 16:42:49 +0900777 * Returns all the {@link RouteInfo} of type {@link RouteInfo#RTN_UNICAST} set on this link.
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200778 */
Remi NGUYEN VAN48380e42022-07-15 16:42:49 +0900779 private @NonNull List<RouteInfo> getUnicastRoutes() {
780 return CollectionUtils.filter(mRoutes, route -> route.getType() == RouteInfo.RTN_UNICAST);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700781 }
782
Lorenzo Colittic0803122013-03-07 10:59:25 -0800783 /**
Rubin Xuffd77d82017-09-05 18:40:49 +0100784 * Make sure this LinkProperties instance contains routes that cover the local subnet
785 * of its link addresses. Add any route that is missing.
786 * @hide
787 */
788 public void ensureDirectlyConnectedRoutes() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900789 for (LinkAddress addr : mLinkAddresses) {
Rubin Xuffd77d82017-09-05 18:40:49 +0100790 addRoute(new RouteInfo(addr, null, mIfaceName));
791 }
792 }
793
794 /**
Lorenzo Colittic0803122013-03-07 10:59:25 -0800795 * Returns all the routes on this link and all the links stacked above it.
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200796 *
797 * Only unicast routes are returned for apps targeting Android S or below.
798 *
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700799 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800800 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +0800801 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +0800802 public @NonNull List<RouteInfo> getAllRoutes() {
Taras Antoshchuk30d41e52021-08-02 18:06:35 +0200803 final List<RouteInfo> routes = new ArrayList<>(getRoutes());
Lorenzo Colittic0803122013-03-07 10:59:25 -0800804 for (LinkProperties stacked: mStackedLinks.values()) {
805 routes.addAll(stacked.getAllRoutes());
806 }
Robert Greenwaltf3385082013-03-15 11:28:50 -0700807 return routes;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800808 }
809
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700810 /**
811 * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
812 * Note that Http Proxies are only a hint - the system recommends their use, but it does
813 * not enforce it and applications may ignore them.
814 *
Erik Klinea923dba2015-06-26 19:21:34 +0900815 * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700816 */
paulhucbbc3db2019-03-08 16:35:20 +0800817 public void setHttpProxy(@Nullable ProxyInfo proxy) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700818 mHttpProxy = proxy;
819 }
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700820
821 /**
822 * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
823 *
paulhucbbc3db2019-03-08 16:35:20 +0800824 * @return The {@link ProxyInfo} set on this link or {@code null}.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700825 */
paulhucbbc3db2019-03-08 16:35:20 +0800826 public @Nullable ProxyInfo getHttpProxy() {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700827 return mHttpProxy;
828 }
829
Lorenzo Colittic0803122013-03-07 10:59:25 -0800830 /**
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900831 * Returns the NAT64 prefix in use on this link, if any.
832 *
paulhucbbc3db2019-03-08 16:35:20 +0800833 * @return the NAT64 prefix or {@code null}.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900834 */
835 public @Nullable IpPrefix getNat64Prefix() {
836 return mNat64Prefix;
837 }
838
839 /**
840 * Sets the NAT64 prefix in use on this link.
841 *
842 * 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 +0800843 * 128-bit IPv6 address) are supported or {@code null} for no prefix.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900844 *
845 * @param prefix the NAT64 prefix.
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900846 */
paulhucbbc3db2019-03-08 16:35:20 +0800847 public void setNat64Prefix(@Nullable IpPrefix prefix) {
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900848 if (prefix != null && prefix.getPrefixLength() != 96) {
849 throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
850 }
851 mNat64Prefix = prefix; // IpPrefix objects are immutable.
852 }
853
854 /**
Lorenzo Colittic0803122013-03-07 10:59:25 -0800855 * Adds a stacked link.
856 *
Chalard Jeand51966a2018-06-07 13:27:00 +0900857 * If there is already a stacked link with the same interface name as link,
Lorenzo Colittic0803122013-03-07 10:59:25 -0800858 * that link is replaced with link. Otherwise, link is added to the list
paulhucbbc3db2019-03-08 16:35:20 +0800859 * of stacked links.
Lorenzo Colittic0803122013-03-07 10:59:25 -0800860 *
861 * @param link The link to add.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900862 * @return true if the link was stacked, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700863 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800864 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +0100865 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +0800866 public boolean addStackedLink(@NonNull LinkProperties link) {
867 if (link.getInterfaceName() != null) {
Lorenzo Colittic0803122013-03-07 10:59:25 -0800868 mStackedLinks.put(link.getInterfaceName(), link);
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900869 return true;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800870 }
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900871 return false;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800872 }
873
874 /**
875 * Removes a stacked link.
876 *
Lorenzo Colitti38258432014-10-20 11:08:03 +0900877 * If there is a stacked link with the given interface name, it is
Lorenzo Colittic0803122013-03-07 10:59:25 -0800878 * removed. Otherwise, nothing changes.
879 *
Lorenzo Colitti38258432014-10-20 11:08:03 +0900880 * @param iface The interface name of the link to remove.
Lorenzo Colitti09de4182013-08-08 11:00:12 +0900881 * @return true if the link was removed, false otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700882 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800883 */
paulhucbbc3db2019-03-08 16:35:20 +0800884 public boolean removeStackedLink(@NonNull String iface) {
885 LinkProperties removed = mStackedLinks.remove(iface);
886 return removed != null;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800887 }
888
889 /**
890 * Returns all the links stacked on top of this link.
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700891 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -0800892 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +0000893 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700894 public @NonNull List<LinkProperties> getStackedLinks() {
895 if (mStackedLinks.isEmpty()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900896 return Collections.emptyList();
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700897 }
paulhucbbc3db2019-03-08 16:35:20 +0800898 final List<LinkProperties> stacked = new ArrayList<>();
Lorenzo Colittic0803122013-03-07 10:59:25 -0800899 for (LinkProperties link : mStackedLinks.values()) {
Jeff Sharkey0aef9342014-08-11 15:22:51 -0700900 stacked.add(new LinkProperties(link));
Lorenzo Colittic0803122013-03-07 10:59:25 -0800901 }
Robert Greenwalt69aceaf2014-06-06 10:30:11 -0700902 return Collections.unmodifiableList(stacked);
Lorenzo Colittic0803122013-03-07 10:59:25 -0800903 }
904
Robert Greenwalteaa84d52014-05-18 22:01:38 -0700905 /**
906 * Clears this object to its initial state.
907 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700908 public void clear() {
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900909 if (mParcelSensitiveFields) {
910 throw new UnsupportedOperationException(
911 "Cannot clear LinkProperties when parcelSensitiveFields is set");
912 }
913
Irfan Sherifffb7c9642010-10-01 16:08:28 -0700914 mIfaceName = null;
Wink Saville051a6642011-07-13 13:44:13 -0700915 mLinkAddresses.clear();
916 mDnses.clear();
dalyk7643abc2018-01-17 14:20:55 -0500917 mUsePrivateDns = false;
918 mPrivateDnsServerName = null;
Hongshike2d7cf52018-06-28 20:42:19 +0900919 mPcscfs.clear();
Robert Greenwaltcd277852012-11-09 10:52:27 -0800920 mDomains = null;
Wink Saville051a6642011-07-13 13:44:13 -0700921 mRoutes.clear();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700922 mHttpProxy = null;
Lorenzo Colittic0803122013-03-07 10:59:25 -0800923 mStackedLinks.clear();
sy.yun4aa73922013-09-02 05:24:09 +0900924 mMtu = 0;
ruibin zhangca75bc82019-05-23 19:35:30 +0800925 mDhcpServerAddress = null;
Robert Greenwaltdebf0e02014-08-06 12:00:25 -0700926 mTcpBufferSizes = null;
Lorenzo Colitti981b34f2019-01-08 09:58:59 +0900927 mNat64Prefix = null;
Valentin Iftime9fa35092019-09-24 13:32:13 +0200928 mWakeOnLanSupported = false;
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +0900929 mCaptivePortalApiUrl = null;
930 mCaptivePortalData = null;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700931 }
932
933 /**
934 * Implement the Parcelable interface
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700935 */
936 public int describeContents() {
937 return 0;
938 }
939
Wink Saville7d857902010-08-27 11:15:18 -0700940 @Override
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -0700941 public String toString() {
Chalard Jeand51966a2018-06-07 13:27:00 +0900942 // Space as a separator, so no need for spaces at start/end of the individual fragments.
943 final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700944
Chalard Jeand51966a2018-06-07 13:27:00 +0900945 if (mIfaceName != null) {
946 resultJoiner.add("InterfaceName:");
947 resultJoiner.add(mIfaceName);
948 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700949
Chalard Jeand51966a2018-06-07 13:27:00 +0900950 resultJoiner.add("LinkAddresses: [");
951 if (!mLinkAddresses.isEmpty()) {
952 resultJoiner.add(TextUtils.join(",", mLinkAddresses));
953 }
954 resultJoiner.add("]");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700955
Chalard Jeand51966a2018-06-07 13:27:00 +0900956 resultJoiner.add("DnsAddresses: [");
957 if (!mDnses.isEmpty()) {
958 resultJoiner.add(TextUtils.join(",", mDnses));
959 }
960 resultJoiner.add("]");
dalyk7643abc2018-01-17 14:20:55 -0500961
Chalard Jeand51966a2018-06-07 13:27:00 +0900962 if (mUsePrivateDns) {
963 resultJoiner.add("UsePrivateDns: true");
964 }
965
Chalard Jeand3930f12018-06-07 13:28:09 +0900966 if (mPrivateDnsServerName != null) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900967 resultJoiner.add("PrivateDnsServerName:");
968 resultJoiner.add(mPrivateDnsServerName);
dalyk7643abc2018-01-17 14:20:55 -0500969 }
970
Hongshike2d7cf52018-06-28 20:42:19 +0900971 if (!mPcscfs.isEmpty()) {
972 resultJoiner.add("PcscfAddresses: [");
973 resultJoiner.add(TextUtils.join(",", mPcscfs));
974 resultJoiner.add("]");
975 }
976
Chalard Jean299d8562018-04-11 16:36:41 +0900977 if (!mValidatedPrivateDnses.isEmpty()) {
Chalard Jeand51966a2018-06-07 13:27:00 +0900978 final StringJoiner validatedPrivateDnsesJoiner =
979 new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
980 for (final InetAddress addr : mValidatedPrivateDnses) {
981 validatedPrivateDnsesJoiner.add(addr.getHostAddress());
Chalard Jean299d8562018-04-11 16:36:41 +0900982 }
Chalard Jeand51966a2018-06-07 13:27:00 +0900983 resultJoiner.add(validatedPrivateDnsesJoiner.toString());
Chalard Jean299d8562018-04-11 16:36:41 +0900984 }
985
Chalard Jeand51966a2018-06-07 13:27:00 +0900986 resultJoiner.add("Domains:");
987 resultJoiner.add(mDomains);
Robert Greenwaltcd277852012-11-09 10:52:27 -0800988
Chalard Jeand51966a2018-06-07 13:27:00 +0900989 resultJoiner.add("MTU:");
990 resultJoiner.add(Integer.toString(mMtu));
sy.yun4aa73922013-09-02 05:24:09 +0900991
Valentin Iftime9fa35092019-09-24 13:32:13 +0200992 if (mWakeOnLanSupported) {
993 resultJoiner.add("WakeOnLanSupported: true");
994 }
995
ruibin zhangca75bc82019-05-23 19:35:30 +0800996 if (mDhcpServerAddress != null) {
997 resultJoiner.add("ServerAddress:");
998 resultJoiner.add(mDhcpServerAddress.toString());
999 }
1000
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001001 if (mCaptivePortalApiUrl != null) {
1002 resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl);
1003 }
1004
1005 if (mCaptivePortalData != null) {
1006 resultJoiner.add("CaptivePortalData: " + mCaptivePortalData);
1007 }
1008
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001009 if (mTcpBufferSizes != null) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001010 resultJoiner.add("TcpBufferSizes:");
1011 resultJoiner.add(mTcpBufferSizes);
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001012 }
1013
Chalard Jeand51966a2018-06-07 13:27:00 +09001014 resultJoiner.add("Routes: [");
1015 if (!mRoutes.isEmpty()) {
1016 resultJoiner.add(TextUtils.join(",", mRoutes));
1017 }
1018 resultJoiner.add("]");
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001019
Chalard Jeand51966a2018-06-07 13:27:00 +09001020 if (mHttpProxy != null) {
1021 resultJoiner.add("HttpProxy:");
1022 resultJoiner.add(mHttpProxy.toString());
1023 }
1024
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001025 if (mNat64Prefix != null) {
1026 resultJoiner.add("Nat64Prefix:");
1027 resultJoiner.add(mNat64Prefix.toString());
1028 }
1029
Chalard Jeand51966a2018-06-07 13:27:00 +09001030 final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
1031 if (!stackedLinksValues.isEmpty()) {
1032 final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
1033 for (final LinkProperties lp : stackedLinksValues) {
1034 stackedLinksJoiner.add("[ " + lp + " ]");
Lorenzo Colittic0803122013-03-07 10:59:25 -08001035 }
Chalard Jeand51966a2018-06-07 13:27:00 +09001036 resultJoiner.add(stackedLinksJoiner.toString());
Lorenzo Colittic0803122013-03-07 10:59:25 -08001037 }
Chalard Jeand51966a2018-06-07 13:27:00 +09001038
1039 return resultJoiner.toString();
Lorenzo Colittic0803122013-03-07 10:59:25 -08001040 }
1041
1042 /**
1043 * Returns true if this link has an IPv4 address.
1044 *
1045 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -07001046 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -08001047 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001048 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001049 public boolean hasIpv4Address() {
Lorenzo Colittic0803122013-03-07 10:59:25 -08001050 for (LinkAddress address : mLinkAddresses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001051 if (address.getAddress() instanceof Inet4Address) {
1052 return true;
1053 }
Lorenzo Colittic0803122013-03-07 10:59:25 -08001054 }
1055 return false;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001056 }
1057
Wink Saville051a6642011-07-13 13:44:13 -07001058 /**
paulhucbbc3db2019-03-08 16:35:20 +08001059 * For backward compatibility.
1060 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1061 * just yet.
1062 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1063 * @hide
1064 */
1065 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1066 public boolean hasIPv4Address() {
1067 return hasIpv4Address();
1068 }
1069
1070 /**
Lorenzo Colitti05a505c2015-07-27 16:35:33 +09001071 * Returns true if this link or any of its stacked interfaces has an IPv4 address.
1072 *
1073 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1074 */
paulhucbbc3db2019-03-08 16:35:20 +08001075 private boolean hasIpv4AddressOnInterface(String iface) {
Lorenzo Colitti28bb16c2015-07-30 23:41:43 +09001076 // mIfaceName can be null.
paulhucbbc3db2019-03-08 16:35:20 +08001077 return (Objects.equals(iface, mIfaceName) && hasIpv4Address())
1078 || (iface != null && mStackedLinks.containsKey(iface)
1079 && mStackedLinks.get(iface).hasIpv4Address());
Lorenzo Colitti05a505c2015-07-27 16:35:33 +09001080 }
1081
1082 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001083 * Returns true if this link has a global preferred IPv6 address.
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001084 *
Lorenzo Colittifc854692014-06-23 22:33:43 +09001085 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
Robert Greenwalt69aceaf2014-06-06 10:30:11 -07001086 * @hide
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001087 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001088 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001089 public boolean hasGlobalIpv6Address() {
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001090 for (LinkAddress address : mLinkAddresses) {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001091 if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
Lorenzo Colitti09de4182013-08-08 11:00:12 +09001092 return true;
1093 }
1094 }
1095 return false;
1096 }
1097
1098 /**
Rubin Xuab8cf302020-03-30 14:37:05 +01001099 * Returns true if this link has an IPv4 unreachable default route.
1100 *
1101 * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise.
1102 * @hide
1103 */
1104 public boolean hasIpv4UnreachableDefaultRoute() {
1105 for (RouteInfo r : mRoutes) {
1106 if (r.isIPv4UnreachableDefault()) {
1107 return true;
1108 }
1109 }
1110 return false;
1111 }
1112
1113 /**
paulhucbbc3db2019-03-08 16:35:20 +08001114 * For backward compatibility.
1115 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1116 * just yet.
1117 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
1118 * @hide
1119 */
1120 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1121 public boolean hasGlobalIPv6Address() {
1122 return hasGlobalIpv6Address();
1123 }
1124
1125 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001126 * Returns true if this link has an IPv4 default route.
1127 *
1128 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1129 * @hide
1130 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001131 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001132 public boolean hasIpv4DefaultRoute() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001133 for (RouteInfo r : mRoutes) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001134 if (r.isIPv4Default()) {
1135 return true;
1136 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001137 }
1138 return false;
1139 }
1140
1141 /**
Rubin Xuab8cf302020-03-30 14:37:05 +01001142 * Returns true if this link has an IPv6 unreachable default route.
1143 *
1144 * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise.
1145 * @hide
1146 */
1147 public boolean hasIpv6UnreachableDefaultRoute() {
1148 for (RouteInfo r : mRoutes) {
1149 if (r.isIPv6UnreachableDefault()) {
1150 return true;
1151 }
1152 }
1153 return false;
1154 }
1155
1156 /**
paulhucbbc3db2019-03-08 16:35:20 +08001157 * For backward compatibility.
1158 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1159 * just yet.
1160 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1161 * @hide
1162 */
1163 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1164 public boolean hasIPv4DefaultRoute() {
1165 return hasIpv4DefaultRoute();
1166 }
1167
1168 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001169 * Returns true if this link has an IPv6 default route.
1170 *
1171 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1172 * @hide
1173 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001174 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001175 public boolean hasIpv6DefaultRoute() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001176 for (RouteInfo r : mRoutes) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001177 if (r.isIPv6Default()) {
1178 return true;
1179 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001180 }
1181 return false;
1182 }
1183
1184 /**
paulhucbbc3db2019-03-08 16:35:20 +08001185 * For backward compatibility.
1186 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1187 * just yet.
1188 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1189 * @hide
1190 */
1191 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1192 public boolean hasIPv6DefaultRoute() {
1193 return hasIpv6DefaultRoute();
1194 }
1195
1196 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001197 * Returns true if this link has an IPv4 DNS server.
1198 *
1199 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1200 * @hide
1201 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001202 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001203 public boolean hasIpv4DnsServer() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001204 for (InetAddress ia : mDnses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001205 if (ia instanceof Inet4Address) {
1206 return true;
1207 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001208 }
1209 return false;
1210 }
1211
1212 /**
paulhucbbc3db2019-03-08 16:35:20 +08001213 * For backward compatibility.
1214 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1215 * just yet.
1216 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1217 * @hide
1218 */
1219 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1220 public boolean hasIPv4DnsServer() {
1221 return hasIpv4DnsServer();
1222 }
1223
1224 /**
Lorenzo Colittifc854692014-06-23 22:33:43 +09001225 * Returns true if this link has an IPv6 DNS server.
1226 *
1227 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1228 * @hide
1229 */
Aaron Huang8d6ae5d2019-10-02 20:07:38 +08001230 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001231 public boolean hasIpv6DnsServer() {
Lorenzo Colittifc854692014-06-23 22:33:43 +09001232 for (InetAddress ia : mDnses) {
Hugo Benichi875e9a42017-10-10 16:29:06 +09001233 if (ia instanceof Inet6Address) {
1234 return true;
1235 }
Lorenzo Colittifc854692014-06-23 22:33:43 +09001236 }
1237 return false;
1238 }
1239
1240 /**
paulhucbbc3db2019-03-08 16:35:20 +08001241 * For backward compatibility.
1242 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1243 * just yet.
1244 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1245 * @hide
1246 */
1247 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1248 public boolean hasIPv6DnsServer() {
1249 return hasIpv6DnsServer();
1250 }
1251
1252 /**
Hongshike2d7cf52018-06-28 20:42:19 +09001253 * Returns true if this link has an IPv4 PCSCF server.
1254 *
1255 * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
1256 * @hide
1257 */
paulhucbbc3db2019-03-08 16:35:20 +08001258 public boolean hasIpv4PcscfServer() {
Hongshike2d7cf52018-06-28 20:42:19 +09001259 for (InetAddress ia : mPcscfs) {
1260 if (ia instanceof Inet4Address) {
1261 return true;
1262 }
1263 }
1264 return false;
1265 }
1266
1267 /**
1268 * Returns true if this link has an IPv6 PCSCF server.
1269 *
1270 * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
1271 * @hide
1272 */
paulhucbbc3db2019-03-08 16:35:20 +08001273 public boolean hasIpv6PcscfServer() {
Hongshike2d7cf52018-06-28 20:42:19 +09001274 for (InetAddress ia : mPcscfs) {
1275 if (ia instanceof Inet6Address) {
1276 return true;
1277 }
1278 }
1279 return false;
1280 }
1281
1282 /**
Erik Kline8b023072014-10-24 21:50:20 +09001283 * Returns true if this link is provisioned for global IPv4 connectivity.
1284 * This requires an IP address, default route, and DNS server.
1285 *
1286 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Kline04612b02015-05-21 16:15:02 +09001287 * @hide
Erik Kline8b023072014-10-24 21:50:20 +09001288 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001289 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001290 public boolean isIpv4Provisioned() {
1291 return (hasIpv4Address()
1292 && hasIpv4DefaultRoute()
1293 && hasIpv4DnsServer());
Erik Kline8b023072014-10-24 21:50:20 +09001294 }
1295
1296 /**
1297 * Returns true if this link is provisioned for global IPv6 connectivity.
1298 * This requires an IP address, default route, and DNS server.
1299 *
1300 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Kline04612b02015-05-21 16:15:02 +09001301 * @hide
Erik Kline8b023072014-10-24 21:50:20 +09001302 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001303 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001304 public boolean isIpv6Provisioned() {
1305 return (hasGlobalIpv6Address()
1306 && hasIpv6DefaultRoute()
1307 && hasIpv6DnsServer());
Erik Kline8b023072014-10-24 21:50:20 +09001308 }
1309
1310 /**
paulhucbbc3db2019-03-08 16:35:20 +08001311 * For backward compatibility.
1312 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1313 * just yet.
1314 * @return {@code true} if the link is provisioned, {@code false} otherwise.
1315 * @hide
1316 */
1317 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
1318 public boolean isIPv6Provisioned() {
1319 return isIpv6Provisioned();
1320 }
1321
1322
1323 /**
Erik Kline8b023072014-10-24 21:50:20 +09001324 * Returns true if this link is provisioned for global connectivity,
1325 * for at least one Internet Protocol family.
Lorenzo Colittifc854692014-06-23 22:33:43 +09001326 *
1327 * @return {@code true} if the link is provisioned, {@code false} otherwise.
1328 * @hide
1329 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001330 @SystemApi
Lorenzo Colittifc854692014-06-23 22:33:43 +09001331 public boolean isProvisioned() {
paulhucbbc3db2019-03-08 16:35:20 +08001332 return (isIpv4Provisioned() || isIpv6Provisioned());
Lorenzo Colittifc854692014-06-23 22:33:43 +09001333 }
1334
1335 /**
Erik Klinea923dba2015-06-26 19:21:34 +09001336 * Evaluate whether the {@link InetAddress} is considered reachable.
1337 *
1338 * @return {@code true} if the given {@link InetAddress} is considered reachable,
1339 * {@code false} otherwise.
1340 * @hide
1341 */
Remi NGUYEN VAN109f8d52019-01-20 12:38:10 +09001342 @SystemApi
paulhucbbc3db2019-03-08 16:35:20 +08001343 public boolean isReachable(@NonNull InetAddress ip) {
Erik Klinea923dba2015-06-26 19:21:34 +09001344 final List<RouteInfo> allRoutes = getAllRoutes();
1345 // If we don't have a route to this IP address, it's not reachable.
1346 final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip);
1347 if (bestRoute == null) {
1348 return false;
1349 }
1350
1351 // TODO: better source address evaluation for destination addresses.
1352
1353 if (ip instanceof Inet4Address) {
1354 // For IPv4, it suffices for now to simply have any address.
paulhucbbc3db2019-03-08 16:35:20 +08001355 return hasIpv4AddressOnInterface(bestRoute.getInterface());
Erik Klinea923dba2015-06-26 19:21:34 +09001356 } else if (ip instanceof Inet6Address) {
1357 if (ip.isLinkLocalAddress()) {
1358 // For now, just make sure link-local destinations have
1359 // scopedIds set, since transmits will generally fail otherwise.
1360 // TODO: verify it matches the ifindex of one of the interfaces.
1361 return (((Inet6Address)ip).getScopeId() != 0);
1362 } else {
1363 // For non-link-local destinations check that either the best route
1364 // is directly connected or that some global preferred address exists.
1365 // TODO: reconsider all cases (disconnected ULA networks, ...).
paulhucbbc3db2019-03-08 16:35:20 +08001366 return (!bestRoute.hasGateway() || hasGlobalIpv6Address());
Erik Klinea923dba2015-06-26 19:21:34 +09001367 }
1368 }
1369
1370 return false;
1371 }
1372
1373 /**
Prerana2b97bbe2022-04-28 04:02:05 +00001374 * Returns true if this link has a throw route.
1375 *
1376 * @return {@code true} if there is an exclude route, {@code false} otherwise.
1377 * @hide
1378 */
1379 public boolean hasExcludeRoute() {
1380 for (RouteInfo r : mRoutes) {
1381 if (r.getType() == RouteInfo.RTN_THROW) {
1382 return true;
1383 }
1384 }
1385 return false;
1386 }
1387
1388 /**
Wink Saville051a6642011-07-13 13:44:13 -07001389 * Compares this {@code LinkProperties} interface name against the target
1390 *
1391 * @param target LinkProperties to compare.
1392 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001393 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001394 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001395 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001396 public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001397 return LinkPropertiesUtils.isIdenticalInterfaceName(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001398 }
1399
1400 /**
ruibin zhangca75bc82019-05-23 19:35:30 +08001401 * Compares this {@code LinkProperties} DHCP server address against the target
1402 *
1403 * @param target LinkProperties to compare.
1404 * @return {@code true} if both are identical, {@code false} otherwise.
1405 * @hide
1406 */
1407 public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) {
1408 return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress);
1409 }
1410
1411 /**
Robert Greenwalt462e5702012-10-31 14:32:53 -07001412 * Compares this {@code LinkProperties} interface addresses against the target
Wink Saville051a6642011-07-13 13:44:13 -07001413 *
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 isIdenticalAddresses(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001420 return LinkPropertiesUtils.isIdenticalAddresses(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001421 }
1422
1423 /**
1424 * Compares this {@code LinkProperties} DNS addresses against the target
1425 *
1426 * @param target LinkProperties to compare.
1427 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001428 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001429 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001430 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001431 public boolean isIdenticalDnses(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001432 return LinkPropertiesUtils.isIdenticalDnses(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001433 }
1434
1435 /**
dalyk7643abc2018-01-17 14:20:55 -05001436 * Compares this {@code LinkProperties} private DNS settings against the
1437 * target.
1438 *
1439 * @param target LinkProperties to compare.
1440 * @return {@code true} if both are identical, {@code false} otherwise.
1441 * @hide
1442 */
paulhucbbc3db2019-03-08 16:35:20 +08001443 public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) {
dalyk7643abc2018-01-17 14:20:55 -05001444 return (isPrivateDnsActive() == target.isPrivateDnsActive()
1445 && TextUtils.equals(getPrivateDnsServerName(),
1446 target.getPrivateDnsServerName()));
1447 }
1448
1449 /**
Chalard Jean299d8562018-04-11 16:36:41 +09001450 * Compares this {@code LinkProperties} validated private DNS addresses against
1451 * the target
1452 *
1453 * @param target LinkProperties to compare.
1454 * @return {@code true} if both are identical, {@code false} otherwise.
1455 * @hide
1456 */
paulhucbbc3db2019-03-08 16:35:20 +08001457 public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) {
Chalard Jean299d8562018-04-11 16:36:41 +09001458 Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers();
1459 return (mValidatedPrivateDnses.size() == targetDnses.size())
1460 ? mValidatedPrivateDnses.containsAll(targetDnses) : false;
1461 }
1462
1463 /**
Hongshike2d7cf52018-06-28 20:42:19 +09001464 * Compares this {@code LinkProperties} PCSCF addresses against the target
1465 *
1466 * @param target LinkProperties to compare.
1467 * @return {@code true} if both are identical, {@code false} otherwise.
1468 * @hide
1469 */
paulhucbbc3db2019-03-08 16:35:20 +08001470 public boolean isIdenticalPcscfs(@NonNull LinkProperties target) {
Hongshike2d7cf52018-06-28 20:42:19 +09001471 Collection<InetAddress> targetPcscfs = target.getPcscfServers();
1472 return (mPcscfs.size() == targetPcscfs.size()) ?
1473 mPcscfs.containsAll(targetPcscfs) : false;
1474 }
1475
1476 /**
Wink Saville051a6642011-07-13 13:44:13 -07001477 * Compares this {@code LinkProperties} Routes against the target
1478 *
1479 * @param target LinkProperties to compare.
1480 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001481 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001482 */
Mathew Inwoodc5b9bec2018-08-08 14:52:47 +01001483 @UnsupportedAppUsage
paulhucbbc3db2019-03-08 16:35:20 +08001484 public boolean isIdenticalRoutes(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001485 return LinkPropertiesUtils.isIdenticalRoutes(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001486 }
1487
1488 /**
1489 * Compares this {@code LinkProperties} HttpProxy against the target
1490 *
1491 * @param target LinkProperties to compare.
1492 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001493 * @hide
Wink Saville051a6642011-07-13 13:44:13 -07001494 */
Mathew Inwoodbdfc1fc2018-12-20 15:30:45 +00001495 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
paulhucbbc3db2019-03-08 16:35:20 +08001496 public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) {
Aaron Huang0e1759b2019-12-17 00:33:18 +08001497 return LinkPropertiesUtils.isIdenticalHttpProxy(target, this);
Wink Saville051a6642011-07-13 13:44:13 -07001498 }
John Wang3e567d52011-04-04 12:35:42 -07001499
Lorenzo Colittic0803122013-03-07 10:59:25 -08001500 /**
1501 * Compares this {@code LinkProperties} stacked links against the target
1502 *
1503 * @param target LinkProperties to compare.
1504 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001505 * @hide
Lorenzo Colittic0803122013-03-07 10:59:25 -08001506 */
Mathew Inwoode1a17ba2020-11-04 09:29:36 +00001507 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
paulhucbbc3db2019-03-08 16:35:20 +08001508 public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) {
Lorenzo Colitti89218e52013-04-01 10:47:43 +09001509 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
Lorenzo Colittic0803122013-03-07 10:59:25 -08001510 return false;
1511 }
1512 for (LinkProperties stacked : mStackedLinks.values()) {
1513 // Hashtable values can never be null.
1514 String iface = stacked.getInterfaceName();
1515 if (!stacked.equals(target.mStackedLinks.get(iface))) {
1516 return false;
1517 }
1518 }
1519 return true;
1520 }
1521
sy.yun4aa73922013-09-02 05:24:09 +09001522 /**
1523 * Compares this {@code LinkProperties} MTU against the target
1524 *
Ying Wangcb5620b2013-09-06 22:53:16 -07001525 * @param target LinkProperties to compare.
sy.yun4aa73922013-09-02 05:24:09 +09001526 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001527 * @hide
sy.yun4aa73922013-09-02 05:24:09 +09001528 */
paulhucbbc3db2019-03-08 16:35:20 +08001529 public boolean isIdenticalMtu(@NonNull LinkProperties target) {
sy.yun4aa73922013-09-02 05:24:09 +09001530 return getMtu() == target.getMtu();
1531 }
1532
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001533 /**
1534 * Compares this {@code LinkProperties} Tcp buffer sizes against the target.
1535 *
1536 * @param target LinkProperties to compare.
1537 * @return {@code true} if both are identical, {@code false} otherwise.
1538 * @hide
1539 */
paulhucbbc3db2019-03-08 16:35:20 +08001540 public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) {
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001541 return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
1542 }
1543
John Wang3e567d52011-04-04 12:35:42 -07001544 /**
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001545 * Compares this {@code LinkProperties} NAT64 prefix against the target.
1546 *
1547 * @param target LinkProperties to compare.
1548 * @return {@code true} if both are identical, {@code false} otherwise.
1549 * @hide
1550 */
paulhucbbc3db2019-03-08 16:35:20 +08001551 public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) {
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001552 return Objects.equals(mNat64Prefix, target.mNat64Prefix);
1553 }
1554
1555 /**
Valentin Iftime9fa35092019-09-24 13:32:13 +02001556 * Compares this {@code LinkProperties} WakeOnLan supported against the target.
1557 *
1558 * @param target LinkProperties to compare.
1559 * @return {@code true} if both are identical, {@code false} otherwise.
1560 * @hide
1561 */
1562 public boolean isIdenticalWakeOnLan(LinkProperties target) {
1563 return isWakeOnLanSupported() == target.isWakeOnLanSupported();
1564 }
1565
1566 /**
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001567 * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target.
1568 *
1569 * @param target LinkProperties to compare.
1570 * @return {@code true} if both are identical, {@code false} otherwise.
1571 * @hide
1572 */
1573 public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) {
1574 return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl);
1575 }
1576
1577 /**
1578 * Compares this {@code LinkProperties}'s CaptivePortalData against the target.
1579 *
1580 * @param target LinkProperties to compare.
1581 * @return {@code true} if both are identical, {@code false} otherwise.
1582 * @hide
1583 */
1584 public boolean isIdenticalCaptivePortalData(LinkProperties target) {
1585 return Objects.equals(mCaptivePortalData, target.mCaptivePortalData);
1586 }
1587
1588 /**
Valentin Iftime9fa35092019-09-24 13:32:13 +02001589 * Set whether the network interface supports WakeOnLAN
1590 *
1591 * @param supported WakeOnLAN supported value
1592 *
1593 * @hide
1594 */
1595 public void setWakeOnLanSupported(boolean supported) {
1596 mWakeOnLanSupported = supported;
1597 }
1598
1599 /**
1600 * Returns whether the network interface supports WakeOnLAN
1601 *
1602 * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
1603 */
1604 public boolean isWakeOnLanSupported() {
1605 return mWakeOnLanSupported;
1606 }
1607
1608 /**
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001609 * Set the URL of the captive portal API endpoint to get more information about the network.
1610 * @hide
1611 */
1612 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001613 public void setCaptivePortalApiUrl(@Nullable Uri url) {
1614 mCaptivePortalApiUrl = url;
1615 }
1616
1617 /**
1618 * Get the URL of the captive portal API endpoint to get more information about the network.
1619 *
1620 * <p>This is null unless the application has
1621 * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1622 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided
1623 * the URL.
1624 * @hide
1625 */
1626 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001627 @Nullable
1628 public Uri getCaptivePortalApiUrl() {
1629 return mCaptivePortalApiUrl;
1630 }
1631
1632 /**
1633 * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1634 * @hide
1635 */
1636 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001637 public void setCaptivePortalData(@Nullable CaptivePortalData data) {
1638 mCaptivePortalData = data;
1639 }
1640
1641 /**
1642 * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1643 *
1644 * <p>This is null unless the application has
1645 * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1646 * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions.
1647 * @hide
1648 */
1649 @SystemApi
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001650 @Nullable
1651 public CaptivePortalData getCaptivePortalData() {
1652 return mCaptivePortalData;
1653 }
1654
1655 /**
John Wang3e567d52011-04-04 12:35:42 -07001656 * Compares this {@code LinkProperties} instance against the target
1657 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
1658 * all their fields are equal in values.
1659 *
1660 * For collection fields, such as mDnses, containsAll() is used to check
1661 * if two collections contains the same elements, independent of order.
1662 * There are two thoughts regarding containsAll()
1663 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
1664 * 2. Worst case performance is O(n^2).
1665 *
1666 * @param obj the object to be tested for equality.
1667 * @return {@code true} if both objects are equal, {@code false} otherwise.
1668 */
Chalard Jeand51966a2018-06-07 13:27:00 +09001669 @Override
Roman Kalukiewicz384a8c62020-10-14 15:59:06 -07001670 public boolean equals(@Nullable Object obj) {
John Wang3e567d52011-04-04 12:35:42 -07001671 if (this == obj) return true;
1672
1673 if (!(obj instanceof LinkProperties)) return false;
1674
John Wang3e567d52011-04-04 12:35:42 -07001675 LinkProperties target = (LinkProperties) obj;
Chalard Jeand51966a2018-06-07 13:27:00 +09001676 /*
Robert Greenwalteaa84d52014-05-18 22:01:38 -07001677 * This method does not check that stacked interfaces are equal, because
1678 * stacked interfaces are not so much a property of the link as a
1679 * description of connections between links.
1680 */
dalyk7643abc2018-01-17 14:20:55 -05001681 return isIdenticalInterfaceName(target)
1682 && isIdenticalAddresses(target)
ruibin zhangca75bc82019-05-23 19:35:30 +08001683 && isIdenticalDhcpServerAddress(target)
dalyk7643abc2018-01-17 14:20:55 -05001684 && isIdenticalDnses(target)
1685 && isIdenticalPrivateDns(target)
Chalard Jean299d8562018-04-11 16:36:41 +09001686 && isIdenticalValidatedPrivateDnses(target)
Hongshike2d7cf52018-06-28 20:42:19 +09001687 && isIdenticalPcscfs(target)
dalyk7643abc2018-01-17 14:20:55 -05001688 && isIdenticalRoutes(target)
1689 && isIdenticalHttpProxy(target)
1690 && isIdenticalStackedLinks(target)
1691 && isIdenticalMtu(target)
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001692 && isIdenticalTcpBufferSizes(target)
Valentin Iftime9fa35092019-09-24 13:32:13 +02001693 && isIdenticalNat64Prefix(target)
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001694 && isIdenticalWakeOnLan(target)
1695 && isIdenticalCaptivePortalApiUrl(target)
1696 && isIdenticalCaptivePortalData(target);
Wink Saville051a6642011-07-13 13:44:13 -07001697 }
John Wang3e567d52011-04-04 12:35:42 -07001698
Wink Saville051a6642011-07-13 13:44:13 -07001699 /**
Chalard Jeand51966a2018-06-07 13:27:00 +09001700 * Generate hashcode based on significant fields
1701 *
John Wang3e567d52011-04-04 12:35:42 -07001702 * Equal objects must produce the same hash code, while unequal objects
1703 * may have the same hash codes.
1704 */
Chalard Jeand51966a2018-06-07 13:27:00 +09001705 @Override
John Wang3e567d52011-04-04 12:35:42 -07001706 public int hashCode() {
1707 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
1708 + mLinkAddresses.size() * 31
1709 + mDnses.size() * 37
Chalard Jean299d8562018-04-11 16:36:41 +09001710 + mValidatedPrivateDnses.size() * 61
Robert Greenwaltcd277852012-11-09 10:52:27 -08001711 + ((null == mDomains) ? 0 : mDomains.hashCode())
Robert Greenwalt5a901292011-04-28 14:28:50 -07001712 + mRoutes.size() * 41
Lorenzo Colittic0803122013-03-07 10:59:25 -08001713 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
sy.yun4aa73922013-09-02 05:24:09 +09001714 + mStackedLinks.hashCode() * 47)
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001715 + mMtu * 51
dalyk7643abc2018-01-17 14:20:55 -05001716 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
1717 + (mUsePrivateDns ? 57 : 0)
ruibin zhangca75bc82019-05-23 19:35:30 +08001718 + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode())
Hongshike2d7cf52018-06-28 20:42:19 +09001719 + mPcscfs.size() * 67
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001720 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
Valentin Iftime9fa35092019-09-24 13:32:13 +02001721 + Objects.hash(mNat64Prefix)
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001722 + (mWakeOnLanSupported ? 71 : 0)
1723 + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData);
John Wang3e567d52011-04-04 12:35:42 -07001724 }
1725
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001726 /**
1727 * Implement the Parcelable interface.
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001728 */
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001729 public void writeToParcel(Parcel dest, int flags) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001730 dest.writeString(getInterfaceName());
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001731 dest.writeInt(mLinkAddresses.size());
Chalard Jean299d8562018-04-11 16:36:41 +09001732 for (LinkAddress linkAddress : mLinkAddresses) {
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001733 dest.writeParcelable(linkAddress, flags);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001734 }
Irfan Sherifffb7c9642010-10-01 16:08:28 -07001735
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001736 writeAddresses(dest, mDnses);
1737 writeAddresses(dest, mValidatedPrivateDnses);
dalyk7643abc2018-01-17 14:20:55 -05001738 dest.writeBoolean(mUsePrivateDns);
1739 dest.writeString(mPrivateDnsServerName);
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001740 writeAddresses(dest, mPcscfs);
Robert Greenwaltcd277852012-11-09 10:52:27 -08001741 dest.writeString(mDomains);
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001742 writeAddress(dest, mDhcpServerAddress);
sy.yun4aa73922013-09-02 05:24:09 +09001743 dest.writeInt(mMtu);
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001744 dest.writeString(mTcpBufferSizes);
Robert Greenwalt5a901292011-04-28 14:28:50 -07001745 dest.writeInt(mRoutes.size());
Chalard Jean299d8562018-04-11 16:36:41 +09001746 for (RouteInfo route : mRoutes) {
Robert Greenwalt5a901292011-04-28 14:28:50 -07001747 dest.writeParcelable(route, flags);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001748 }
Robert Greenwalt5c733972011-02-09 13:56:06 -08001749
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001750 if (mHttpProxy != null) {
1751 dest.writeByte((byte)1);
1752 dest.writeParcelable(mHttpProxy, flags);
1753 } else {
1754 dest.writeByte((byte)0);
1755 }
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001756 dest.writeParcelable(mNat64Prefix, 0);
1757
Chalard Jeand51966a2018-06-07 13:27:00 +09001758 ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
Lorenzo Colittic0803122013-03-07 10:59:25 -08001759 dest.writeList(stackedLinks);
Valentin Iftime9fa35092019-09-24 13:32:13 +02001760
1761 dest.writeBoolean(mWakeOnLanSupported);
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001762 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0);
1763 dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001764 }
1765
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001766 private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) {
1767 dest.writeInt(list.size());
1768 for (InetAddress d : list) {
1769 writeAddress(dest, d);
1770 }
1771 }
1772
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001773 private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) {
1774 byte[] addressBytes = (addr == null ? null : addr.getAddress());
1775 dest.writeByteArray(addressBytes);
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001776 if (addr instanceof Inet6Address) {
1777 final Inet6Address v6Addr = (Inet6Address) addr;
1778 final boolean hasScopeId = v6Addr.getScopeId() != 0;
1779 dest.writeBoolean(hasScopeId);
1780 if (hasScopeId) dest.writeInt(v6Addr.getScopeId());
1781 }
1782 }
1783
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001784 @Nullable
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001785 private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException {
1786 final byte[] addr = p.createByteArray();
Lorenzo Colitti279a1d62020-01-06 19:43:59 +09001787 if (addr == null) return null;
1788
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001789 if (addr.length == INET6_ADDR_LENGTH) {
1790 final boolean hasScopeId = p.readBoolean();
1791 final int scopeId = hasScopeId ? p.readInt() : 0;
1792 return Inet6Address.getByAddress(null /* host */, addr, scopeId);
1793 }
1794
1795 return InetAddress.getByAddress(addr);
1796 }
1797
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001798 /**
1799 * Implement the Parcelable interface.
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001800 */
Jeff Sharkeyf8525282019-02-28 12:06:45 -07001801 public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR =
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001802 new Creator<LinkProperties>() {
1803 public LinkProperties createFromParcel(Parcel in) {
1804 LinkProperties netProp = new LinkProperties();
Robert Greenwalt462e5702012-10-31 14:32:53 -07001805
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001806 String iface = in.readString();
1807 if (iface != null) {
Robert Greenwalt462e5702012-10-31 14:32:53 -07001808 netProp.setInterfaceName(iface);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001809 }
1810 int addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001811 for (int i = 0; i < addressCount; i++) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001812 netProp.addLinkAddress(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001813 }
1814 addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001815 for (int i = 0; i < addressCount; i++) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001816 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001817 netProp.addDnsServer(readAddress(in));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001818 } catch (UnknownHostException e) { }
1819 }
Chalard Jean299d8562018-04-11 16:36:41 +09001820 addressCount = in.readInt();
1821 for (int i = 0; i < addressCount; i++) {
1822 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001823 netProp.addValidatedPrivateDnsServer(readAddress(in));
Chalard Jean299d8562018-04-11 16:36:41 +09001824 } catch (UnknownHostException e) { }
1825 }
dalyk7643abc2018-01-17 14:20:55 -05001826 netProp.setUsePrivateDns(in.readBoolean());
1827 netProp.setPrivateDnsServerName(in.readString());
Hongshike2d7cf52018-06-28 20:42:19 +09001828 addressCount = in.readInt();
1829 for (int i = 0; i < addressCount; i++) {
1830 try {
Remi NGUYEN VAN3a59a922019-12-18 14:47:06 +09001831 netProp.addPcscfServer(readAddress(in));
Hongshike2d7cf52018-06-28 20:42:19 +09001832 } catch (UnknownHostException e) { }
1833 }
Robert Greenwaltcd277852012-11-09 10:52:27 -08001834 netProp.setDomains(in.readString());
ruibin zhangca75bc82019-05-23 19:35:30 +08001835 try {
1836 netProp.setDhcpServerAddress((Inet4Address) InetAddress
1837 .getByAddress(in.createByteArray()));
1838 } catch (UnknownHostException e) { }
sy.yun4aa73922013-09-02 05:24:09 +09001839 netProp.setMtu(in.readInt());
Robert Greenwaltdebf0e02014-08-06 12:00:25 -07001840 netProp.setTcpBufferSizes(in.readString());
Robert Greenwalt5c733972011-02-09 13:56:06 -08001841 addressCount = in.readInt();
Chalard Jean299d8562018-04-11 16:36:41 +09001842 for (int i = 0; i < addressCount; i++) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001843 netProp.addRoute(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001844 }
1845 if (in.readByte() == 1) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001846 netProp.setHttpProxy(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001847 }
Lorenzo Colitti981b34f2019-01-08 09:58:59 +09001848 netProp.setNat64Prefix(in.readParcelable(null));
Lorenzo Colittic0803122013-03-07 10:59:25 -08001849 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
1850 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
1851 for (LinkProperties stackedLink: stackedLinks) {
1852 netProp.addStackedLink(stackedLink);
1853 }
Valentin Iftime9fa35092019-09-24 13:32:13 +02001854 netProp.setWakeOnLanSupported(in.readBoolean());
Remi NGUYEN VAN0a65eed2019-12-17 16:45:42 +09001855
1856 netProp.setCaptivePortalApiUrl(in.readParcelable(null));
1857 netProp.setCaptivePortalData(in.readParcelable(null));
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001858 return netProp;
1859 }
1860
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001861 public LinkProperties[] newArray(int size) {
1862 return new LinkProperties[size];
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001863 }
1864 };
w19976e714f1d2014-08-05 15:18:11 -07001865
Chalard Jean299d8562018-04-11 16:36:41 +09001866 /**
1867 * Check the valid MTU range based on IPv4 or IPv6.
1868 * @hide
1869 */
1870 public static boolean isValidMtu(int mtu, boolean ipv6) {
1871 if (ipv6) {
Chalard Jeand51966a2018-06-07 13:27:00 +09001872 return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU;
Chalard Jean299d8562018-04-11 16:36:41 +09001873 } else {
Chalard Jeand51966a2018-06-07 13:27:00 +09001874 return mtu >= MIN_MTU && mtu <= MAX_MTU;
w19976e714f1d2014-08-05 15:18:11 -07001875 }
Chalard Jean299d8562018-04-11 16:36:41 +09001876 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001877}