blob: 1bb0fbb74a53f9598569b3b5b23cd5c53c90e45a [file] [log] [blame]
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001/*
Wink Saville6e809972010-09-21 09:15:35 -07002 * Copyright (C) 2010 The Android Open Source Project
Robert Greenwalt47f69fe2010-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 Sharkeyeb2c2c72014-08-11 15:22:51 -070019import android.annotation.NonNull;
Jeff Sharkey9da2f1e2014-08-14 12:55:00 -070020import android.annotation.Nullable;
Jason Monk207900c2014-04-25 15:00:09 -040021import android.net.ProxyInfo;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070022import android.os.Parcelable;
23import android.os.Parcel;
John Wang4e900092011-04-04 12:35:42 -070024import android.text.TextUtils;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070025
26import java.net.InetAddress;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080027import java.net.Inet4Address;
Lorenzo Colitti4faa0272013-08-08 11:00:12 +090028import java.net.Inet6Address;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070029import java.net.UnknownHostException;
30import java.util.ArrayList;
31import java.util.Collection;
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070032import java.util.Collections;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080033import java.util.Hashtable;
Robert Greenwaltdf2b8782014-06-06 10:30:11 -070034import java.util.List;
Lorenzo Colittic17a1b92014-06-12 23:10:17 +090035import java.util.Objects;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070036
37/**
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070038 * Describes the properties of a network link.
Robert Greenwalt992564e2011-02-09 13:56:06 -080039 *
40 * A link represents a connection to a network.
41 * It may have multiple addresses and multiple gateways,
Robert Greenwalt4f05d552014-05-18 22:01:38 -070042 * multiple dns servers but only one http proxy and one
43 * network interface.
Robert Greenwalt992564e2011-02-09 13:56:06 -080044 *
Robert Greenwalt4f05d552014-05-18 22:01:38 -070045 * Note that this is just a holder of data. Modifying it
46 * does not affect live networks.
Robert Greenwalt992564e2011-02-09 13:56:06 -080047 *
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070048 */
Robert Greenwalte595b972014-06-12 16:24:38 -070049public final class LinkProperties implements Parcelable {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080050 // The interface described by the network link.
Robert Greenwalt4717c262012-10-31 14:32:53 -070051 private String mIfaceName;
Lorenzo Colitti64483942013-11-15 18:43:52 +090052 private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
53 private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
Robert Greenwalt8058f622012-11-09 10:52:27 -080054 private String mDomains;
Lorenzo Colitti64483942013-11-15 18:43:52 +090055 private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
Jason Monk207900c2014-04-25 15:00:09 -040056 private ProxyInfo mHttpProxy;
sy.yun9d9b74a2013-09-02 05:24:09 +090057 private int mMtu;
Robert Greenwalt3f05bf42014-08-06 12:00:25 -070058 // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
59 private String mTcpBufferSizes;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070060
w1997615afd812014-08-05 15:18:11 -070061 private static final int MIN_MTU = 68;
62 private static final int MIN_MTU_V6 = 1280;
63 private static final int MAX_MTU = 10000;
64
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -080065 // Stores the properties of links that are "stacked" above this link.
66 // Indexed by interface name to allow modification and to prevent duplicates being added.
67 private Hashtable<String, LinkProperties> mStackedLinks =
68 new Hashtable<String, LinkProperties>();
69
Robert Greenwaltdf2b8782014-06-06 10:30:11 -070070 /**
71 * @hide
72 */
Robert Greenwalt0a46db52011-07-14 14:28:05 -070073 public static class CompareResult<T> {
Robert Greenwaltdf2b8782014-06-06 10:30:11 -070074 public List<T> removed = new ArrayList<T>();
75 public List<T> added = new ArrayList<T>();
Wink Savillee8222252011-07-13 13:44:13 -070076
77 @Override
78 public String toString() {
Robert Greenwalt0a46db52011-07-14 14:28:05 -070079 String retVal = "removed=[";
80 for (T addr : removed) retVal += addr.toString() + ",";
81 retVal += "] added=[";
82 for (T addr : added) retVal += addr.toString() + ",";
Wink Savillee8222252011-07-13 13:44:13 -070083 retVal += "]";
84 return retVal;
85 }
86 }
87
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070088 /**
89 * @hide
90 */
Erik Klinecd7ed162015-05-21 16:15:02 +090091 public enum ProvisioningChange {
92 STILL_NOT_PROVISIONED,
93 LOST_PROVISIONING,
94 GAINED_PROVISIONING,
95 STILL_PROVISIONED,
96 }
97
98 /**
99 * Compare the provisioning states of two LinkProperties instances.
100 *
101 * @hide
102 */
103 public static ProvisioningChange compareProvisioning(
104 LinkProperties before, LinkProperties after) {
105 if (before.isProvisioned() && after.isProvisioned()) {
106 // On dualstack networks, DHCPv4 renewals can occasionally fail.
107 // When this happens, IPv6-reachable services continue to function
108 // normally but IPv4-only services (naturally) fail.
109 //
110 // When an application using an IPv4-only service reports a bad
111 // network condition to the framework, attempts to re-validate
112 // the network succeed (since we support IPv6-only networks) and
113 // nothing is changed.
114 //
115 // For users, this is confusing and unexpected behaviour, and is
116 // not necessarily easy to diagnose. Therefore, we treat changing
117 // from a dualstack network to an IPv6-only network equivalent to
118 // a total loss of provisioning.
119 //
120 // For one such example of this, see b/18867306.
121 //
Erik Kline1ad4e222015-08-14 12:16:55 +0900122 // Additionally, losing IPv6 provisioning can result in TCP
123 // connections getting stuck until timeouts fire and other
124 // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
125 // previously dualstack network is deemed a lost of provisioning.
126 if ((before.isIPv4Provisioned() && !after.isIPv4Provisioned()) ||
127 (before.isIPv6Provisioned() && !after.isIPv6Provisioned())) {
Erik Klinecd7ed162015-05-21 16:15:02 +0900128 return ProvisioningChange.LOST_PROVISIONING;
129 }
130 return ProvisioningChange.STILL_PROVISIONED;
131 } else if (before.isProvisioned() && !after.isProvisioned()) {
132 return ProvisioningChange.LOST_PROVISIONING;
133 } else if (!before.isProvisioned() && after.isProvisioned()) {
134 return ProvisioningChange.GAINED_PROVISIONING;
135 } else { // !before.isProvisioned() && !after.isProvisioned()
136 return ProvisioningChange.STILL_NOT_PROVISIONED;
137 }
138 }
139
140 /**
141 * @hide
142 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700143 public LinkProperties() {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700144 }
145
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700146 /**
147 * @hide
148 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700149 public LinkProperties(LinkProperties source) {
Irfan Sheriffef6c1432010-08-30 20:37:17 -0700150 if (source != null) {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700151 mIfaceName = source.getInterfaceName();
Robert Greenwalt0d8acea2011-07-28 17:21:25 -0700152 for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700153 for (InetAddress i : source.getDnsServers()) mDnses.add(i);
Robert Greenwalt8058f622012-11-09 10:52:27 -0800154 mDomains = source.getDomains();
Robert Greenwalt0d8acea2011-07-28 17:21:25 -0700155 for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
Wink Savillebe2b0582011-05-18 15:59:04 -0700156 mHttpProxy = (source.getHttpProxy() == null) ?
Jason Monk207900c2014-04-25 15:00:09 -0400157 null : new ProxyInfo(source.getHttpProxy());
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800158 for (LinkProperties l: source.mStackedLinks.values()) {
159 addStackedLink(l);
160 }
sy.yun9d9b74a2013-09-02 05:24:09 +0900161 setMtu(source.getMtu());
Robert Greenwalt3f05bf42014-08-06 12:00:25 -0700162 mTcpBufferSizes = source.mTcpBufferSizes;
Irfan Sheriffef6c1432010-08-30 20:37:17 -0700163 }
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700164 }
165
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700166 /**
167 * Sets the interface name for this link. All {@link RouteInfo} already set for this
168 * will have their interface changed to match this new value.
169 *
170 * @param iface The name of the network interface used for this link.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700171 * @hide
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700172 */
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700173 public void setInterfaceName(String iface) {
174 mIfaceName = iface;
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800175 ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
176 for (RouteInfo route : mRoutes) {
177 newRoutes.add(routeWithInterface(route));
178 }
179 mRoutes = newRoutes;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700180 }
181
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700182 /**
183 * Gets the interface name for this link. May be {@code null} if not set.
184 *
185 * @return The interface name set for this link or {@code null}.
186 */
Jeff Sharkey9da2f1e2014-08-14 12:55:00 -0700187 public @Nullable String getInterfaceName() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700188 return mIfaceName;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700189 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700190
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700191 /**
192 * @hide
193 */
194 public List<String> getAllInterfaceNames() {
195 List<String> interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
Robert Greenwalt55187f12013-03-22 12:00:17 -0700196 if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
Lorenzo Colitti4aa9bcf2013-03-20 19:22:58 +0900197 for (LinkProperties stacked: mStackedLinks.values()) {
198 interfaceNames.addAll(stacked.getAllInterfaceNames());
199 }
200 return interfaceNames;
201 }
202
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900203 /**
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700204 * Returns all the addresses on this link. We often think of a link having a single address,
205 * however, particularly with Ipv6 several addresses are typical. Note that the
206 * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
207 * prefix lengths for each address. This is a simplified utility alternative to
208 * {@link LinkProperties#getLinkAddresses}.
209 *
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700210 * @return An umodifiable {@link List} of {@link InetAddress} for this link.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700211 * @hide
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900212 */
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700213 public List<InetAddress> getAddresses() {
214 List<InetAddress> addresses = new ArrayList<InetAddress>();
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700215 for (LinkAddress linkAddress : mLinkAddresses) {
216 addresses.add(linkAddress.getAddress());
217 }
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700218 return Collections.unmodifiableList(addresses);
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700219 }
220
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900221 /**
222 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700223 * @hide
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900224 */
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700225 public List<InetAddress> getAllAddresses() {
226 List<InetAddress> addresses = new ArrayList<InetAddress>();
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900227 for (LinkAddress linkAddress : mLinkAddresses) {
228 addresses.add(linkAddress.getAddress());
229 }
230 for (LinkProperties stacked: mStackedLinks.values()) {
231 addresses.addAll(stacked.getAllAddresses());
232 }
233 return addresses;
234 }
235
Lorenzo Colitti64483942013-11-15 18:43:52 +0900236 private int findLinkAddressIndex(LinkAddress address) {
237 for (int i = 0; i < mLinkAddresses.size(); i++) {
238 if (mLinkAddresses.get(i).isSameAddressAs(address)) {
239 return i;
240 }
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900241 }
Lorenzo Colitti64483942013-11-15 18:43:52 +0900242 return -1;
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900243 }
244
245 /**
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700246 * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
247 * same address/prefix does not already exist. If it does exist it is replaced.
Lorenzo Colitti64483942013-11-15 18:43:52 +0900248 * @param address The {@code LinkAddress} to add.
249 * @return true if {@code address} was added or updated, false otherwise.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700250 * @hide
Lorenzo Colitti64483942013-11-15 18:43:52 +0900251 */
252 public boolean addLinkAddress(LinkAddress address) {
253 if (address == null) {
254 return false;
255 }
256 int i = findLinkAddressIndex(address);
257 if (i < 0) {
258 // Address was not present. Add it.
259 mLinkAddresses.add(address);
260 return true;
261 } else if (mLinkAddresses.get(i).equals(address)) {
262 // Address was present and has same properties. Do nothing.
263 return false;
264 } else {
265 // Address was present and has different properties. Update it.
266 mLinkAddresses.set(i, address);
267 return true;
268 }
269 }
270
271 /**
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700272 * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches
273 * and {@link LinkAddress} with the same address and prefix.
274 *
275 * @param toRemove A {@link LinkAddress} specifying the address to remove.
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900276 * @return true if the address was removed, false if it did not exist.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700277 * @hide
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900278 */
279 public boolean removeLinkAddress(LinkAddress toRemove) {
Lorenzo Colitti64483942013-11-15 18:43:52 +0900280 int i = findLinkAddressIndex(toRemove);
281 if (i >= 0) {
282 mLinkAddresses.remove(i);
283 return true;
284 }
285 return false;
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700286 }
287
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900288 /**
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700289 * Returns all the {@link LinkAddress} on this link. Typically a link will have
290 * one IPv4 address and one or more IPv6 addresses.
291 *
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700292 * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900293 */
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700294 public List<LinkAddress> getLinkAddresses() {
295 return Collections.unmodifiableList(mLinkAddresses);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700296 }
297
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900298 /**
299 * Returns all the addresses on this link and all the links stacked above it.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700300 * @hide
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900301 */
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700302 public List<LinkAddress> getAllLinkAddresses() {
303 List<LinkAddress> addresses = new ArrayList<LinkAddress>();
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900304 addresses.addAll(mLinkAddresses);
305 for (LinkProperties stacked: mStackedLinks.values()) {
306 addresses.addAll(stacked.getAllLinkAddresses());
307 }
308 return addresses;
309 }
310
Lorenzo Colitti22f407b2013-08-23 20:54:49 +0900311 /**
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700312 * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
313 * the given {@link Collection} of {@link LinkAddress}.
314 *
315 * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
316 * object.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700317 * @hide
Lorenzo Colitti22f407b2013-08-23 20:54:49 +0900318 */
319 public void setLinkAddresses(Collection<LinkAddress> addresses) {
320 mLinkAddresses.clear();
321 for (LinkAddress address: addresses) {
322 addLinkAddress(address);
323 }
324 }
325
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700326 /**
Lorenzo Colitti309a75d2014-06-24 00:34:39 +0900327 * Adds the given {@link InetAddress} to the list of DNS servers, if not present.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700328 *
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700329 * @param dnsServer The {@link InetAddress} to add to the list of DNS servers.
Lorenzo Colitti309a75d2014-06-24 00:34:39 +0900330 * @return true if the DNS server was added, false if it was already present.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700331 * @hide
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700332 */
Lorenzo Colitti309a75d2014-06-24 00:34:39 +0900333 public boolean addDnsServer(InetAddress dnsServer) {
334 if (dnsServer != null && !mDnses.contains(dnsServer)) {
335 mDnses.add(dnsServer);
336 return true;
337 }
338 return false;
339 }
340
341 /**
Erik Klinecd7ed162015-05-21 16:15:02 +0900342 * Removes the given {@link InetAddress} from the list of DNS servers.
343 *
344 * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers.
345 * @return true if the DNS server was removed, false if it did not exist.
346 * @hide
347 */
348 public boolean removeDnsServer(InetAddress dnsServer) {
349 if (dnsServer != null) {
350 return mDnses.remove(dnsServer);
351 }
352 return false;
353 }
354
355 /**
Lorenzo Colitti309a75d2014-06-24 00:34:39 +0900356 * Replaces the DNS servers in this {@code LinkProperties} with
357 * the given {@link Collection} of {@link InetAddress} objects.
358 *
359 * @param addresses The {@link Collection} of DNS servers to set in this object.
360 * @hide
361 */
362 public void setDnsServers(Collection<InetAddress> dnsServers) {
363 mDnses.clear();
364 for (InetAddress dnsServer: dnsServers) {
365 addDnsServer(dnsServer);
366 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700367 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700368
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700369 /**
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700370 * Returns all the {@link InetAddress} for DNS servers on this link.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700371 *
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700372 * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700373 * this link.
374 */
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700375 public List<InetAddress> getDnsServers() {
376 return Collections.unmodifiableList(mDnses);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700377 }
378
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700379 /**
380 * Sets the DNS domain search path used on this link.
381 *
382 * @param domains A {@link String} listing in priority order the comma separated
383 * domains to search when resolving host names on this link.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700384 * @hide
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700385 */
Robert Greenwalt8058f622012-11-09 10:52:27 -0800386 public void setDomains(String domains) {
387 mDomains = domains;
388 }
389
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700390 /**
391 * Get the DNS domains search path set for this link.
392 *
393 * @return A {@link String} containing the comma separated domains to search when resolving
394 * host names on this link.
395 */
396 public String getDomains() {
397 return mDomains;
398 }
399
400 /**
401 * Sets the Maximum Transmission Unit size to use on this link. This should not be used
402 * unless the system default (1500) is incorrect. Values less than 68 or greater than
403 * 10000 will be ignored.
404 *
405 * @param mtu The MTU to use for this link.
406 * @hide
407 */
sy.yun9d9b74a2013-09-02 05:24:09 +0900408 public void setMtu(int mtu) {
409 mMtu = mtu;
410 }
411
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700412 /**
413 * Gets any non-default MTU size set for this link. Note that if the default is being used
414 * this will return 0.
415 *
416 * @return The mtu value set for this link.
417 * @hide
418 */
sy.yun9d9b74a2013-09-02 05:24:09 +0900419 public int getMtu() {
420 return mMtu;
421 }
422
Robert Greenwalt3f05bf42014-08-06 12:00:25 -0700423 /**
424 * Sets the tcp buffers sizes to be used when this link is the system default.
425 * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max".
426 *
427 * @param tcpBufferSizes The tcp buffers sizes to use.
428 *
429 * @hide
430 */
431 public void setTcpBufferSizes(String tcpBufferSizes) {
432 mTcpBufferSizes = tcpBufferSizes;
433 }
434
435 /**
436 * Gets the tcp buffer sizes.
437 *
438 * @return the tcp buffer sizes to use when this link is the system default.
439 *
440 * @hide
441 */
442 public String getTcpBufferSizes() {
443 return mTcpBufferSizes;
444 }
445
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800446 private RouteInfo routeWithInterface(RouteInfo route) {
447 return new RouteInfo(
448 route.getDestination(),
449 route.getGateway(),
Lorenzo Colitti4b0f8e62014-09-19 01:49:05 +0900450 mIfaceName,
451 route.getType());
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700452 }
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800453
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700454 /**
Lorenzo Colittic17a1b92014-06-12 23:10:17 +0900455 * Adds a {@link RouteInfo} to this {@code LinkProperties}, if not present. If the
456 * {@link RouteInfo} had an interface name set and that differs from the interface set for this
457 * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The proper
458 * course is to add either un-named or properly named {@link RouteInfo}.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700459 *
460 * @param route A {@link RouteInfo} to add to this object.
Lorenzo Colittic17a1b92014-06-12 23:10:17 +0900461 * @return {@code false} if the route was already present, {@code true} if it was added.
462 *
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700463 * @hide
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700464 */
Lorenzo Colittic17a1b92014-06-12 23:10:17 +0900465 public boolean addRoute(RouteInfo route) {
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800466 if (route != null) {
467 String routeIface = route.getInterface();
468 if (routeIface != null && !routeIface.equals(mIfaceName)) {
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800469 throw new IllegalArgumentException(
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800470 "Route added with non-matching interface: " + routeIface +
Lorenzo Colitti1994bc12013-03-08 19:11:40 -0800471 " vs. " + mIfaceName);
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800472 }
Lorenzo Colittic17a1b92014-06-12 23:10:17 +0900473 route = routeWithInterface(route);
474 if (!mRoutes.contains(route)) {
475 mRoutes.add(route);
476 return true;
477 }
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800478 }
Lorenzo Colittic17a1b92014-06-12 23:10:17 +0900479 return false;
480 }
481
482 /**
483 * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
484 * specify an interface and the interface must match the interface of this
485 * {@code LinkProperties}, or it will not be removed.
486 *
487 * @return {@code true} if the route was removed, {@code false} if it was not present.
488 *
489 * @hide
490 */
491 public boolean removeRoute(RouteInfo route) {
492 return route != null &&
493 Objects.equals(mIfaceName, route.getInterface()) &&
494 mRoutes.remove(route);
Lorenzo Colitti45b9a5b2013-03-08 11:30:39 -0800495 }
496
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800497 /**
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700498 * Returns all the {@link RouteInfo} set on this link.
499 *
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700500 * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800501 */
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700502 public List<RouteInfo> getRoutes() {
503 return Collections.unmodifiableList(mRoutes);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700504 }
505
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800506 /**
507 * Returns all the routes on this link and all the links stacked above it.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700508 * @hide
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800509 */
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700510 public List<RouteInfo> getAllRoutes() {
511 List<RouteInfo> routes = new ArrayList();
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800512 routes.addAll(mRoutes);
513 for (LinkProperties stacked: mStackedLinks.values()) {
514 routes.addAll(stacked.getAllRoutes());
515 }
Robert Greenwalt6629bcd2013-03-15 11:28:50 -0700516 return routes;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800517 }
518
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700519 /**
520 * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
521 * Note that Http Proxies are only a hint - the system recommends their use, but it does
522 * not enforce it and applications may ignore them.
523 *
Erik Klineb36a3132015-06-26 19:21:34 +0900524 * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700525 * @hide
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700526 */
Jason Monk207900c2014-04-25 15:00:09 -0400527 public void setHttpProxy(ProxyInfo proxy) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700528 mHttpProxy = proxy;
529 }
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700530
531 /**
532 * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
533 *
534 * @return The {@link ProxyInfo} set on this link
535 */
Jason Monk207900c2014-04-25 15:00:09 -0400536 public ProxyInfo getHttpProxy() {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700537 return mHttpProxy;
538 }
539
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800540 /**
541 * Adds a stacked link.
542 *
543 * If there is already a stacked link with the same interfacename as link,
544 * that link is replaced with link. Otherwise, link is added to the list
545 * of stacked links. If link is null, nothing changes.
546 *
547 * @param link The link to add.
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900548 * @return true if the link was stacked, false otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700549 * @hide
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800550 */
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900551 public boolean addStackedLink(LinkProperties link) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800552 if (link != null && link.getInterfaceName() != null) {
553 mStackedLinks.put(link.getInterfaceName(), link);
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900554 return true;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800555 }
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900556 return false;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800557 }
558
559 /**
560 * Removes a stacked link.
561 *
Lorenzo Colittif3cab632014-10-20 11:08:03 +0900562 * If there is a stacked link with the given interface name, it is
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800563 * removed. Otherwise, nothing changes.
564 *
Lorenzo Colittif3cab632014-10-20 11:08:03 +0900565 * @param iface The interface name of the link to remove.
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900566 * @return true if the link was removed, false otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700567 * @hide
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800568 */
Lorenzo Colittif3cab632014-10-20 11:08:03 +0900569 public boolean removeStackedLink(String iface) {
570 if (iface != null) {
571 LinkProperties removed = mStackedLinks.remove(iface);
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900572 return removed != null;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800573 }
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900574 return false;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800575 }
576
577 /**
578 * Returns all the links stacked on top of this link.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700579 * @hide
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800580 */
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -0700581 public @NonNull List<LinkProperties> getStackedLinks() {
582 if (mStackedLinks.isEmpty()) {
583 return Collections.EMPTY_LIST;
584 }
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700585 List<LinkProperties> stacked = new ArrayList<LinkProperties>();
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800586 for (LinkProperties link : mStackedLinks.values()) {
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -0700587 stacked.add(new LinkProperties(link));
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800588 }
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700589 return Collections.unmodifiableList(stacked);
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800590 }
591
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700592 /**
593 * Clears this object to its initial state.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700594 * @hide
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700595 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700596 public void clear() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700597 mIfaceName = null;
Wink Savillee8222252011-07-13 13:44:13 -0700598 mLinkAddresses.clear();
599 mDnses.clear();
Robert Greenwalt8058f622012-11-09 10:52:27 -0800600 mDomains = null;
Wink Savillee8222252011-07-13 13:44:13 -0700601 mRoutes.clear();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700602 mHttpProxy = null;
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800603 mStackedLinks.clear();
sy.yun9d9b74a2013-09-02 05:24:09 +0900604 mMtu = 0;
Robert Greenwalt3f05bf42014-08-06 12:00:25 -0700605 mTcpBufferSizes = null;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700606 }
607
608 /**
609 * Implement the Parcelable interface
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700610 */
611 public int describeContents() {
612 return 0;
613 }
614
Wink Saville1f6408a2010-08-27 11:15:18 -0700615 @Override
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700616 public String toString() {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700617 String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700618
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700619 String linkAddresses = "LinkAddresses: [";
John Wang4e900092011-04-04 12:35:42 -0700620 for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
Irfan Sheriffed5d7d12010-10-01 16:08:28 -0700621 linkAddresses += "] ";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700622
623 String dns = "DnsAddresses: [";
Wink Saville1f6408a2010-08-27 11:15:18 -0700624 for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700625 dns += "] ";
626
Robert Greenwalt8058f622012-11-09 10:52:27 -0800627 String domainName = "Domains: " + mDomains;
628
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700629 String mtu = " MTU: " + mMtu;
sy.yun9d9b74a2013-09-02 05:24:09 +0900630
Robert Greenwalt3f05bf42014-08-06 12:00:25 -0700631 String tcpBuffSizes = "";
632 if (mTcpBufferSizes != null) {
633 tcpBuffSizes = " TcpBufferSizes: " + mTcpBufferSizes;
634 }
635
Robert Greenwalt8058f622012-11-09 10:52:27 -0800636 String routes = " Routes: [";
Robert Greenwaltaa70f102011-04-28 14:28:50 -0700637 for (RouteInfo route : mRoutes) routes += route.toString() + ",";
638 routes += "] ";
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700639 String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " ");
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700640
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800641 String stacked = "";
642 if (mStackedLinks.values().size() > 0) {
643 stacked += " Stacked: [";
644 for (LinkProperties link: mStackedLinks.values()) {
645 stacked += " [" + link.toString() + " ],";
646 }
647 stacked += "] ";
648 }
sy.yun9d9b74a2013-09-02 05:24:09 +0900649 return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu
Robert Greenwalt3f05bf42014-08-06 12:00:25 -0700650 + tcpBuffSizes + proxy + stacked + "}";
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800651 }
652
653 /**
654 * Returns true if this link has an IPv4 address.
655 *
656 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700657 * @hide
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800658 */
659 public boolean hasIPv4Address() {
660 for (LinkAddress address : mLinkAddresses) {
661 if (address.getAddress() instanceof Inet4Address) {
662 return true;
663 }
664 }
665 return false;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700666 }
667
Wink Savillee8222252011-07-13 13:44:13 -0700668 /**
Lorenzo Colitti87cfc702015-07-27 16:35:33 +0900669 * Returns true if this link or any of its stacked interfaces has an IPv4 address.
670 *
671 * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
672 */
673 private boolean hasIPv4AddressOnInterface(String iface) {
Lorenzo Colitti89b63922015-07-30 23:41:43 +0900674 // mIfaceName can be null.
675 return (Objects.equals(iface, mIfaceName) && hasIPv4Address()) ||
Lorenzo Colitti87cfc702015-07-27 16:35:33 +0900676 (iface != null && mStackedLinks.containsKey(iface) &&
677 mStackedLinks.get(iface).hasIPv4Address());
678 }
679
680 /**
Lorenzo Colitti76ea6c62014-06-23 22:33:43 +0900681 * Returns true if this link has a global preferred IPv6 address.
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900682 *
Lorenzo Colitti76ea6c62014-06-23 22:33:43 +0900683 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700684 * @hide
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900685 */
Lorenzo Colitti76ea6c62014-06-23 22:33:43 +0900686 public boolean hasGlobalIPv6Address() {
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900687 for (LinkAddress address : mLinkAddresses) {
Lorenzo Colitti76ea6c62014-06-23 22:33:43 +0900688 if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
Lorenzo Colitti4faa0272013-08-08 11:00:12 +0900689 return true;
690 }
691 }
692 return false;
693 }
694
695 /**
Lorenzo Colitti76ea6c62014-06-23 22:33:43 +0900696 * Returns true if this link has an IPv4 default route.
697 *
698 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
699 * @hide
700 */
701 public boolean hasIPv4DefaultRoute() {
702 for (RouteInfo r : mRoutes) {
703 if (r.isIPv4Default()) {
704 return true;
705 }
706 }
707 return false;
708 }
709
710 /**
711 * Returns true if this link has an IPv6 default route.
712 *
713 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
714 * @hide
715 */
716 public boolean hasIPv6DefaultRoute() {
717 for (RouteInfo r : mRoutes) {
718 if (r.isIPv6Default()) {
719 return true;
720 }
721 }
722 return false;
723 }
724
725 /**
726 * Returns true if this link has an IPv4 DNS server.
727 *
728 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
729 * @hide
730 */
731 public boolean hasIPv4DnsServer() {
732 for (InetAddress ia : mDnses) {
733 if (ia instanceof Inet4Address) {
734 return true;
735 }
736 }
737 return false;
738 }
739
740 /**
741 * Returns true if this link has an IPv6 DNS server.
742 *
743 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
744 * @hide
745 */
746 public boolean hasIPv6DnsServer() {
747 for (InetAddress ia : mDnses) {
748 if (ia instanceof Inet6Address) {
749 return true;
750 }
751 }
752 return false;
753 }
754
755 /**
Erik Klined3b9fd32014-10-24 21:50:20 +0900756 * Returns true if this link is provisioned for global IPv4 connectivity.
757 * This requires an IP address, default route, and DNS server.
758 *
759 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Klinecd7ed162015-05-21 16:15:02 +0900760 * @hide
Erik Klined3b9fd32014-10-24 21:50:20 +0900761 */
Erik Klinecd7ed162015-05-21 16:15:02 +0900762 public boolean isIPv4Provisioned() {
Erik Klined3b9fd32014-10-24 21:50:20 +0900763 return (hasIPv4Address() &&
764 hasIPv4DefaultRoute() &&
765 hasIPv4DnsServer());
766 }
767
768 /**
769 * Returns true if this link is provisioned for global IPv6 connectivity.
770 * This requires an IP address, default route, and DNS server.
771 *
772 * @return {@code true} if the link is provisioned, {@code false} otherwise.
Erik Klinecd7ed162015-05-21 16:15:02 +0900773 * @hide
Erik Klined3b9fd32014-10-24 21:50:20 +0900774 */
Erik Klinecd7ed162015-05-21 16:15:02 +0900775 public boolean isIPv6Provisioned() {
Erik Klined3b9fd32014-10-24 21:50:20 +0900776 return (hasGlobalIPv6Address() &&
777 hasIPv6DefaultRoute() &&
778 hasIPv6DnsServer());
779 }
780
781 /**
782 * Returns true if this link is provisioned for global connectivity,
783 * for at least one Internet Protocol family.
Lorenzo Colitti76ea6c62014-06-23 22:33:43 +0900784 *
785 * @return {@code true} if the link is provisioned, {@code false} otherwise.
786 * @hide
787 */
788 public boolean isProvisioned() {
Erik Klinecd7ed162015-05-21 16:15:02 +0900789 return (isIPv4Provisioned() || isIPv6Provisioned());
Lorenzo Colitti76ea6c62014-06-23 22:33:43 +0900790 }
791
792 /**
Erik Klineb36a3132015-06-26 19:21:34 +0900793 * Evaluate whether the {@link InetAddress} is considered reachable.
794 *
795 * @return {@code true} if the given {@link InetAddress} is considered reachable,
796 * {@code false} otherwise.
797 * @hide
798 */
799 public boolean isReachable(InetAddress ip) {
800 final List<RouteInfo> allRoutes = getAllRoutes();
801 // If we don't have a route to this IP address, it's not reachable.
802 final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip);
803 if (bestRoute == null) {
804 return false;
805 }
806
807 // TODO: better source address evaluation for destination addresses.
808
809 if (ip instanceof Inet4Address) {
810 // For IPv4, it suffices for now to simply have any address.
Lorenzo Colitti87cfc702015-07-27 16:35:33 +0900811 return hasIPv4AddressOnInterface(bestRoute.getInterface());
Erik Klineb36a3132015-06-26 19:21:34 +0900812 } else if (ip instanceof Inet6Address) {
813 if (ip.isLinkLocalAddress()) {
814 // For now, just make sure link-local destinations have
815 // scopedIds set, since transmits will generally fail otherwise.
816 // TODO: verify it matches the ifindex of one of the interfaces.
817 return (((Inet6Address)ip).getScopeId() != 0);
818 } else {
819 // For non-link-local destinations check that either the best route
820 // is directly connected or that some global preferred address exists.
821 // TODO: reconsider all cases (disconnected ULA networks, ...).
822 return (!bestRoute.hasGateway() || hasGlobalIPv6Address());
823 }
824 }
825
826 return false;
827 }
828
829 /**
Wink Savillee8222252011-07-13 13:44:13 -0700830 * Compares this {@code LinkProperties} interface name against the target
831 *
832 * @param target LinkProperties to compare.
833 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700834 * @hide
Wink Savillee8222252011-07-13 13:44:13 -0700835 */
836 public boolean isIdenticalInterfaceName(LinkProperties target) {
837 return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
838 }
839
840 /**
Robert Greenwalt4717c262012-10-31 14:32:53 -0700841 * Compares this {@code LinkProperties} interface addresses against the target
Wink Savillee8222252011-07-13 13:44:13 -0700842 *
843 * @param target LinkProperties to compare.
844 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700845 * @hide
Wink Savillee8222252011-07-13 13:44:13 -0700846 */
847 public boolean isIdenticalAddresses(LinkProperties target) {
848 Collection<InetAddress> targetAddresses = target.getAddresses();
849 Collection<InetAddress> sourceAddresses = getAddresses();
850 return (sourceAddresses.size() == targetAddresses.size()) ?
851 sourceAddresses.containsAll(targetAddresses) : false;
852 }
853
854 /**
855 * Compares this {@code LinkProperties} DNS addresses against the target
856 *
857 * @param target LinkProperties to compare.
858 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700859 * @hide
Wink Savillee8222252011-07-13 13:44:13 -0700860 */
861 public boolean isIdenticalDnses(LinkProperties target) {
Robert Greenwaltdf2b8782014-06-06 10:30:11 -0700862 Collection<InetAddress> targetDnses = target.getDnsServers();
Robert Greenwalt8058f622012-11-09 10:52:27 -0800863 String targetDomains = target.getDomains();
864 if (mDomains == null) {
865 if (targetDomains != null) return false;
866 } else {
867 if (mDomains.equals(targetDomains) == false) return false;
868 }
Wink Savillee8222252011-07-13 13:44:13 -0700869 return (mDnses.size() == targetDnses.size()) ?
870 mDnses.containsAll(targetDnses) : false;
871 }
872
873 /**
874 * Compares this {@code LinkProperties} Routes against the target
875 *
876 * @param target LinkProperties to compare.
877 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700878 * @hide
Wink Savillee8222252011-07-13 13:44:13 -0700879 */
880 public boolean isIdenticalRoutes(LinkProperties target) {
881 Collection<RouteInfo> targetRoutes = target.getRoutes();
882 return (mRoutes.size() == targetRoutes.size()) ?
883 mRoutes.containsAll(targetRoutes) : false;
884 }
885
886 /**
887 * Compares this {@code LinkProperties} HttpProxy against the target
888 *
889 * @param target LinkProperties to compare.
890 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700891 * @hide
Wink Savillee8222252011-07-13 13:44:13 -0700892 */
893 public boolean isIdenticalHttpProxy(LinkProperties target) {
894 return getHttpProxy() == null ? target.getHttpProxy() == null :
895 getHttpProxy().equals(target.getHttpProxy());
896 }
John Wang4e900092011-04-04 12:35:42 -0700897
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800898 /**
899 * Compares this {@code LinkProperties} stacked links against the target
900 *
901 * @param target LinkProperties to compare.
902 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700903 * @hide
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800904 */
905 public boolean isIdenticalStackedLinks(LinkProperties target) {
Lorenzo Colitti213f98b2013-04-01 10:47:43 +0900906 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800907 return false;
908 }
909 for (LinkProperties stacked : mStackedLinks.values()) {
910 // Hashtable values can never be null.
911 String iface = stacked.getInterfaceName();
912 if (!stacked.equals(target.mStackedLinks.get(iface))) {
913 return false;
914 }
915 }
916 return true;
917 }
918
sy.yun9d9b74a2013-09-02 05:24:09 +0900919 /**
920 * Compares this {@code LinkProperties} MTU against the target
921 *
Ying Wangd57de6a2013-09-06 22:53:16 -0700922 * @param target LinkProperties to compare.
sy.yun9d9b74a2013-09-02 05:24:09 +0900923 * @return {@code true} if both are identical, {@code false} otherwise.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700924 * @hide
sy.yun9d9b74a2013-09-02 05:24:09 +0900925 */
926 public boolean isIdenticalMtu(LinkProperties target) {
927 return getMtu() == target.getMtu();
928 }
929
Robert Greenwalt3f05bf42014-08-06 12:00:25 -0700930 /**
931 * Compares this {@code LinkProperties} Tcp buffer sizes against the target.
932 *
933 * @param target LinkProperties to compare.
934 * @return {@code true} if both are identical, {@code false} otherwise.
935 * @hide
936 */
937 public boolean isIdenticalTcpBufferSizes(LinkProperties target) {
938 return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
939 }
940
John Wang4e900092011-04-04 12:35:42 -0700941 @Override
942 /**
943 * Compares this {@code LinkProperties} instance against the target
944 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
945 * all their fields are equal in values.
946 *
947 * For collection fields, such as mDnses, containsAll() is used to check
948 * if two collections contains the same elements, independent of order.
949 * There are two thoughts regarding containsAll()
950 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
951 * 2. Worst case performance is O(n^2).
952 *
953 * @param obj the object to be tested for equality.
954 * @return {@code true} if both objects are equal, {@code false} otherwise.
955 */
956 public boolean equals(Object obj) {
957 if (this == obj) return true;
958
959 if (!(obj instanceof LinkProperties)) return false;
960
John Wang4e900092011-04-04 12:35:42 -0700961 LinkProperties target = (LinkProperties) obj;
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700962 /**
963 * This method does not check that stacked interfaces are equal, because
964 * stacked interfaces are not so much a property of the link as a
965 * description of connections between links.
966 */
Wink Savillee8222252011-07-13 13:44:13 -0700967 return isIdenticalInterfaceName(target) &&
968 isIdenticalAddresses(target) &&
969 isIdenticalDnses(target) &&
970 isIdenticalRoutes(target) &&
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -0800971 isIdenticalHttpProxy(target) &&
sy.yun9d9b74a2013-09-02 05:24:09 +0900972 isIdenticalStackedLinks(target) &&
Robert Greenwalt3f05bf42014-08-06 12:00:25 -0700973 isIdenticalMtu(target) &&
974 isIdenticalTcpBufferSizes(target);
Wink Savillee8222252011-07-13 13:44:13 -0700975 }
John Wang4e900092011-04-04 12:35:42 -0700976
Wink Savillee8222252011-07-13 13:44:13 -0700977 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900978 * Compares the addresses in this LinkProperties with another
979 * LinkProperties, examining only addresses on the base link.
Wink Savillee8222252011-07-13 13:44:13 -0700980 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +0900981 * @param target a LinkProperties with the new list of addresses
982 * @return the differences between the addresses.
Robert Greenwalt4f05d552014-05-18 22:01:38 -0700983 * @hide
Wink Savillee8222252011-07-13 13:44:13 -0700984 */
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700985 public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
Wink Savillee8222252011-07-13 13:44:13 -0700986 /*
987 * Duplicate the LinkAddresses into removed, we will be removing
988 * address which are common between mLinkAddresses and target
989 * leaving the addresses that are different. And address which
990 * are in target but not in mLinkAddresses are placed in the
991 * addedAddresses.
992 */
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700993 CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
Wink Savillee8222252011-07-13 13:44:13 -0700994 result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
995 result.added.clear();
Robert Greenwalt0a46db52011-07-14 14:28:05 -0700996 if (target != null) {
997 for (LinkAddress newAddress : target.getLinkAddresses()) {
998 if (! result.removed.remove(newAddress)) {
999 result.added.add(newAddress);
1000 }
Wink Savillee8222252011-07-13 13:44:13 -07001001 }
1002 }
1003 return result;
John Wang4e900092011-04-04 12:35:42 -07001004 }
1005
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001006 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +09001007 * Compares the DNS addresses in this LinkProperties with another
1008 * LinkProperties, examining only DNS addresses on the base link.
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001009 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +09001010 * @param target a LinkProperties with the new list of dns addresses
1011 * @return the differences between the DNS addresses.
Robert Greenwalt4f05d552014-05-18 22:01:38 -07001012 * @hide
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001013 */
1014 public CompareResult<InetAddress> compareDnses(LinkProperties target) {
1015 /*
1016 * Duplicate the InetAddresses into removed, we will be removing
1017 * dns address which are common between mDnses and target
1018 * leaving the addresses that are different. And dns address which
1019 * are in target but not in mDnses are placed in the
1020 * addedAddresses.
1021 */
1022 CompareResult<InetAddress> result = new CompareResult<InetAddress>();
1023
1024 result.removed = new ArrayList<InetAddress>(mDnses);
1025 result.added.clear();
1026 if (target != null) {
Robert Greenwaltdf2b8782014-06-06 10:30:11 -07001027 for (InetAddress newAddress : target.getDnsServers()) {
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001028 if (! result.removed.remove(newAddress)) {
1029 result.added.add(newAddress);
1030 }
1031 }
1032 }
1033 return result;
1034 }
1035
1036 /**
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +09001037 * Compares all routes in this LinkProperties with another LinkProperties,
1038 * examining both the the base link and all stacked links.
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001039 *
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +09001040 * @param target a LinkProperties with the new list of routes
1041 * @return the differences between the routes.
Robert Greenwalt4f05d552014-05-18 22:01:38 -07001042 * @hide
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001043 */
Lorenzo Colittid1e0fae2013-07-31 23:23:21 +09001044 public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001045 /*
1046 * Duplicate the RouteInfos into removed, we will be removing
Lorenzo Colitti1994bc12013-03-08 19:11:40 -08001047 * routes which are common between mRoutes and target
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001048 * leaving the routes that are different. And route address which
1049 * are in target but not in mRoutes are placed in added.
1050 */
1051 CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
1052
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -08001053 result.removed = getAllRoutes();
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001054 result.added.clear();
1055 if (target != null) {
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -08001056 for (RouteInfo r : target.getAllRoutes()) {
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001057 if (! result.removed.remove(r)) {
1058 result.added.add(r);
1059 }
1060 }
1061 }
1062 return result;
1063 }
1064
Paul Jensen992f2522014-04-28 10:33:11 -04001065 /**
1066 * Compares all interface names in this LinkProperties with another
1067 * LinkProperties, examining both the the base link and all stacked links.
1068 *
1069 * @param target a LinkProperties with the new list of interface names
1070 * @return the differences between the interface names.
1071 * @hide
1072 */
1073 public CompareResult<String> compareAllInterfaceNames(LinkProperties target) {
1074 /*
1075 * Duplicate the interface names into removed, we will be removing
1076 * interface names which are common between this and target
1077 * leaving the interface names that are different. And interface names which
1078 * are in target but not in this are placed in added.
1079 */
1080 CompareResult<String> result = new CompareResult<String>();
1081
1082 result.removed = getAllInterfaceNames();
1083 result.added.clear();
1084 if (target != null) {
1085 for (String r : target.getAllInterfaceNames()) {
1086 if (! result.removed.remove(r)) {
1087 result.added.add(r);
1088 }
1089 }
1090 }
1091 return result;
1092 }
1093
Robert Greenwalt0a46db52011-07-14 14:28:05 -07001094
John Wang4e900092011-04-04 12:35:42 -07001095 @Override
1096 /**
1097 * generate hashcode based on significant fields
1098 * Equal objects must produce the same hash code, while unequal objects
1099 * may have the same hash codes.
1100 */
1101 public int hashCode() {
1102 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
1103 + mLinkAddresses.size() * 31
1104 + mDnses.size() * 37
Robert Greenwalt8058f622012-11-09 10:52:27 -08001105 + ((null == mDomains) ? 0 : mDomains.hashCode())
Robert Greenwaltaa70f102011-04-28 14:28:50 -07001106 + mRoutes.size() * 41
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -08001107 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
sy.yun9d9b74a2013-09-02 05:24:09 +09001108 + mStackedLinks.hashCode() * 47)
Robert Greenwalt3f05bf42014-08-06 12:00:25 -07001109 + mMtu * 51
1110 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode());
John Wang4e900092011-04-04 12:35:42 -07001111 }
1112
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001113 /**
1114 * Implement the Parcelable interface.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001115 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001116 public void writeToParcel(Parcel dest, int flags) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001117 dest.writeString(getInterfaceName());
Irfan Sheriffed5d7d12010-10-01 16:08:28 -07001118 dest.writeInt(mLinkAddresses.size());
1119 for(LinkAddress linkAddress : mLinkAddresses) {
1120 dest.writeParcelable(linkAddress, flags);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001121 }
Irfan Sheriffed5d7d12010-10-01 16:08:28 -07001122
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001123 dest.writeInt(mDnses.size());
1124 for(InetAddress d : mDnses) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001125 dest.writeByteArray(d.getAddress());
1126 }
Robert Greenwalt8058f622012-11-09 10:52:27 -08001127 dest.writeString(mDomains);
sy.yun9d9b74a2013-09-02 05:24:09 +09001128 dest.writeInt(mMtu);
Robert Greenwalt3f05bf42014-08-06 12:00:25 -07001129 dest.writeString(mTcpBufferSizes);
Robert Greenwaltaa70f102011-04-28 14:28:50 -07001130 dest.writeInt(mRoutes.size());
1131 for(RouteInfo route : mRoutes) {
1132 dest.writeParcelable(route, flags);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001133 }
Robert Greenwalt992564e2011-02-09 13:56:06 -08001134
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001135 if (mHttpProxy != null) {
1136 dest.writeByte((byte)1);
1137 dest.writeParcelable(mHttpProxy, flags);
1138 } else {
1139 dest.writeByte((byte)0);
1140 }
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -08001141 ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
1142 dest.writeList(stackedLinks);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001143 }
1144
1145 /**
1146 * Implement the Parcelable interface.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001147 */
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001148 public static final Creator<LinkProperties> CREATOR =
1149 new Creator<LinkProperties>() {
1150 public LinkProperties createFromParcel(Parcel in) {
1151 LinkProperties netProp = new LinkProperties();
Robert Greenwalt4717c262012-10-31 14:32:53 -07001152
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001153 String iface = in.readString();
1154 if (iface != null) {
Robert Greenwalt4717c262012-10-31 14:32:53 -07001155 netProp.setInterfaceName(iface);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001156 }
1157 int addressCount = in.readInt();
1158 for (int i=0; i<addressCount; i++) {
Irfan Sheriffed5d7d12010-10-01 16:08:28 -07001159 netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001160 }
1161 addressCount = in.readInt();
1162 for (int i=0; i<addressCount; i++) {
1163 try {
Robert Greenwaltdf2b8782014-06-06 10:30:11 -07001164 netProp.addDnsServer(InetAddress.getByAddress(in.createByteArray()));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001165 } catch (UnknownHostException e) { }
1166 }
Robert Greenwalt8058f622012-11-09 10:52:27 -08001167 netProp.setDomains(in.readString());
sy.yun9d9b74a2013-09-02 05:24:09 +09001168 netProp.setMtu(in.readInt());
Robert Greenwalt3f05bf42014-08-06 12:00:25 -07001169 netProp.setTcpBufferSizes(in.readString());
Robert Greenwalt992564e2011-02-09 13:56:06 -08001170 addressCount = in.readInt();
1171 for (int i=0; i<addressCount; i++) {
Robert Greenwaltaa70f102011-04-28 14:28:50 -07001172 netProp.addRoute((RouteInfo)in.readParcelable(null));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001173 }
1174 if (in.readByte() == 1) {
Jason Monk207900c2014-04-25 15:00:09 -04001175 netProp.setHttpProxy((ProxyInfo)in.readParcelable(null));
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001176 }
Lorenzo Colitti419a4ce2013-03-07 10:59:25 -08001177 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
1178 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
1179 for (LinkProperties stackedLink: stackedLinks) {
1180 netProp.addStackedLink(stackedLink);
1181 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001182 return netProp;
1183 }
1184
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001185 public LinkProperties[] newArray(int size) {
1186 return new LinkProperties[size];
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001187 }
1188 };
w1997615afd812014-08-05 15:18:11 -07001189
1190 /**
1191 * Check the valid MTU range based on IPv4 or IPv6.
1192 * @hide
1193 */
1194 public static boolean isValidMtu(int mtu, boolean ipv6) {
1195 if (ipv6) {
1196 if ((mtu >= MIN_MTU_V6 && mtu <= MAX_MTU)) return true;
1197 } else {
1198 if ((mtu >= MIN_MTU && mtu <= MAX_MTU)) return true;
1199 }
1200 return false;
1201 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001202}