summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2013-11-15 18:43:52 +0900
committerLorenzo Colitti <lorenzo@google.com>2013-12-06 13:54:35 +0900
commit64483947fdb03bf838e317ac0a4af5e0f53a5bbf (patch)
tree856dbc2a83c5b1586b1127e0b3c14f6f335a30fc /core
parent6e2d0c1d91f644ab50e0c0b7cae4306262a4ca41 (diff)
downloadframeworks_base-64483947fdb03bf838e317ac0a4af5e0f53a5bbf.zip
frameworks_base-64483947fdb03bf838e317ac0a4af5e0f53a5bbf.tar.gz
frameworks_base-64483947fdb03bf838e317ac0a4af5e0f53a5bbf.tar.bz2
Add address flags and scope to LinkAddress.
This is necessary so that the framework can know whether an IPv6 address is likely to be usable (i.e., if it's global scope and preferred). Also, it will simplify the address notification methods in INetworkManagementEventObserver, which currently take the address, the flags, and the scope as separate arguments. 1. Add flags and scope to the class and update the unit test. Use the IFA_F_* and RT_SCOPE_* constants defined by libcore. Since most callers don't know about flags and scope, provide constructors that default the flags to zero and determine the scope from the address. Addresses notified by the kernel will have these properly set. Make multicast addresses invalid. Update the class documentation. 2. Provide an isSameAddressAs() method that compares only the address and prefix information between two LinkAddress objects. This is necessary because an interface can't have two addresses with the same address/prefix but different flags. 3. Update LinkProperties's addLinkAddress and removeLinkAddress to identify existing addresses to add/remove using isSameAddressAs instead of implicit equals(). Specifically: - If addLinkAddress is called with an address that is already present, the existing address's flags and scope are updated. This allows, for example, an address on an interface to go from preferred to deprecated when it expires, without it having to be removed and re-added. - If removeLinkAddress is called with an address that is present but with different flags, it deletes that address instead of failing to find a match. 4. Update the INetworkManagementEventObserver address notification methods to take just a LinkAddress instead of LinkAddress, flags, and scope. While I'm at it, change the order of the arguments for consistency with the other functions in the interface. Change-Id: Id8fe0f09a7e8f6bee1ea3b52102178b689a9336e
Diffstat (limited to 'core')
-rw-r--r--core/java/android/net/INetworkManagementEventObserver.aidl16
-rw-r--r--core/java/android/net/LinkAddress.java158
-rw-r--r--core/java/android/net/LinkProperties.java48
-rw-r--r--core/java/com/android/server/net/BaseNetworkObserver.java4
-rw-r--r--core/tests/coretests/src/android/net/LinkAddressTest.java150
-rw-r--r--core/tests/coretests/src/android/net/LinkPropertiesTest.java36
6 files changed, 360 insertions, 52 deletions
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index 405a897..5b16f8b 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -57,24 +57,20 @@ interface INetworkManagementEventObserver {
/**
- * An interface address has been added or updated
+ * An interface address has been added or updated.
*
- * @param address The address.
* @param iface The interface.
- * @param flags The address flags.
- * @param scope The address scope.
+ * @param address The address.
*/
- void addressUpdated(in LinkAddress address, String iface, int flags, int scope);
+ void addressUpdated(String iface, in LinkAddress address);
/**
- * An interface address has been removed
+ * An interface address has been removed.
*
- * @param address The address.
* @param iface The interface.
- * @param flags The address flags.
- * @param scope The address scope.
+ * @param address The address.
*/
- void addressRemoved(in LinkAddress address, String iface, int flags, int scope);
+ void addressRemoved(String iface, in LinkAddress address);
/**
* A networking quota limit has been reached. The quota might not
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 570b6fe..22543e3 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -24,8 +24,32 @@ import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
+import static libcore.io.OsConstants.IFA_F_DADFAILED;
+import static libcore.io.OsConstants.IFA_F_DEPRECATED;
+import static libcore.io.OsConstants.IFA_F_TENTATIVE;
+import static libcore.io.OsConstants.RT_SCOPE_HOST;
+import static libcore.io.OsConstants.RT_SCOPE_LINK;
+import static libcore.io.OsConstants.RT_SCOPE_SITE;
+import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE;
+
/**
* Identifies an IP address on a network link.
+ *
+ * A {@code LinkAddress} consists of:
+ * <ul>
+ * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
+ * The address must be unicast, as multicast addresses cannot be assigned to interfaces.
+ * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties of the address.
+ * <li>Address scope: An integer defining the scope in which the address is unique (e.g.,
+ * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}).
+ * <ul>
+ *<p>
+ * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and
+ * scope are optional. If they are not specified, the flags are set to zero, and the scope will be
+ * determined based on the IP address (e.g., link-local addresses will be created with a scope of
+ * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, etc.) If they are
+ * specified, they are not checked for validity.
+ *
* @hide
*/
public class LinkAddress implements Parcelable {
@@ -39,8 +63,46 @@ public class LinkAddress implements Parcelable {
*/
private int prefixLength;
- private void init(InetAddress address, int prefixLength) {
- if (address == null || prefixLength < 0 ||
+ /**
+ * Address flags. A bitmask of IFA_F_* values.
+ */
+ private int flags;
+
+ /**
+ * Address scope. One of the RT_SCOPE_* constants.
+ */
+ private int scope;
+
+ /**
+ * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
+ * RFC 6724 section 3.2.
+ * @hide
+ */
+ static int scopeForUnicastAddress(InetAddress addr) {
+ if (addr.isAnyLocalAddress()) {
+ return RT_SCOPE_HOST;
+ }
+
+ if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
+ return RT_SCOPE_LINK;
+ }
+
+ // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2
+ // says that they are assigned global scope.
+ if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) {
+ return RT_SCOPE_SITE;
+ }
+
+ return RT_SCOPE_UNIVERSE;
+ }
+
+ /**
+ * Utility function for the constructors.
+ */
+ private void init(InetAddress address, int prefixLength, int flags, int scope) {
+ if (address == null ||
+ address.isMulticastAddress() ||
+ prefixLength < 0 ||
((address instanceof Inet4Address) && prefixLength > 32) ||
(prefixLength > 128)) {
throw new IllegalArgumentException("Bad LinkAddress params " + address +
@@ -48,32 +110,59 @@ public class LinkAddress implements Parcelable {
}
this.address = address;
this.prefixLength = prefixLength;
+ this.flags = flags;
+ this.scope = scope;
+ }
+
+ /**
+ * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
+ * the specified flags and scope. Flags and scope are not checked for validity.
+ * @param address The IP address.
+ * @param prefixLength The prefix length.
+ */
+ public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
+ init(address, prefixLength, flags, scope);
}
/**
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
+ * The flags are set to zero and the scope is determined from the address.
* @param address The IP address.
* @param prefixLength The prefix length.
*/
public LinkAddress(InetAddress address, int prefixLength) {
- init(address, prefixLength);
+ this(address, prefixLength, 0, 0);
+ this.scope = scopeForUnicastAddress(address);
}
/**
* Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
+ * The flags are set to zero and the scope is determined from the address.
* @param interfaceAddress The interface address.
*/
public LinkAddress(InterfaceAddress interfaceAddress) {
- init(interfaceAddress.getAddress(),
+ this(interfaceAddress.getAddress(),
interfaceAddress.getNetworkPrefixLength());
}
/**
* Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
- * "2001:db8::1/64".
+ * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
* @param string The string to parse.
*/
public LinkAddress(String address) {
+ this(address, 0, 0);
+ this.scope = scopeForUnicastAddress(this.address);
+ }
+
+ /**
+ * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
+ * "2001:db8::1/64", with the specified flags and scope.
+ * @param string The string to parse.
+ * @param flags The address flags.
+ * @param scope The address scope.
+ */
+ public LinkAddress(String address, int flags, int scope) {
InetAddress inetAddress = null;
int prefixLength = -1;
try {
@@ -90,18 +179,22 @@ public class LinkAddress implements Parcelable {
throw new IllegalArgumentException("Bad LinkAddress params " + address);
}
- init(inetAddress, prefixLength);
+ init(inetAddress, prefixLength, flags, scope);
}
+ /**
+ * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64".
+ * The string representation does not contain the flags and scope, just the address and prefix
+ * length.
+ */
@Override
public String toString() {
return address.getHostAddress() + "/" + prefixLength;
}
/**
- * Compares this {@code LinkAddress} instance against the specified address
- * in {@code obj}. Two addresses are equal if their InetAddress and prefixLength
- * are equal.
+ * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
+ * their address, prefix length, flags and scope are equal.
*
* @param obj the object to be tested for equality.
* @return {@code true} if both objects are equal, {@code false} otherwise.
@@ -113,7 +206,9 @@ public class LinkAddress implements Parcelable {
}
LinkAddress linkAddress = (LinkAddress) obj;
return this.address.equals(linkAddress.address) &&
- this.prefixLength == linkAddress.prefixLength;
+ this.prefixLength == linkAddress.prefixLength &&
+ this.flags == linkAddress.flags &&
+ this.scope == linkAddress.scope;
}
/**
@@ -121,7 +216,20 @@ public class LinkAddress implements Parcelable {
*/
@Override
public int hashCode() {
- return address.hashCode() + 11 * prefixLength;
+ return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
+ }
+
+ /**
+ * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} represent
+ * the same address. Two LinkAddresses represent the same address if they have the same IP
+ * address and prefix length, even if their properties are different.
+ *
+ * @param other the {@code LinkAddress} to compare to.
+ * @return {@code true} if both objects have the same address and prefix length, {@code false}
+ * otherwise.
+ */
+ public boolean isSameAddressAs(LinkAddress other) {
+ return address.equals(other.address) && prefixLength == other.prefixLength;
}
/**
@@ -139,6 +247,28 @@ public class LinkAddress implements Parcelable {
}
/**
+ * Returns the flags of this address.
+ */
+ public int getFlags() {
+ return flags;
+ }
+
+ /**
+ * Returns the scope of this address.
+ */
+ public int getScope() {
+ return scope;
+ }
+
+ /**
+ * Returns true if this {@code LinkAddress} is global scope and preferred.
+ */
+ public boolean isGlobalPreferred() {
+ return (scope == RT_SCOPE_UNIVERSE &&
+ (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L);
+ }
+
+ /**
* Implement the Parcelable interface.
* @hide
*/
@@ -153,6 +283,8 @@ public class LinkAddress implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeByteArray(address.getAddress());
dest.writeInt(prefixLength);
+ dest.writeInt(this.flags);
+ dest.writeInt(scope);
}
/**
@@ -171,7 +303,9 @@ public class LinkAddress implements Parcelable {
// InetAddress.
}
int prefixLength = in.readInt();
- return new LinkAddress(address, prefixLength);
+ int flags = in.readInt();
+ int scope = in.readInt();
+ return new LinkAddress(address, prefixLength, flags, scope);
}
public LinkAddress[] newArray(int size) {
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index b4d07a1..4dfd3d9 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -61,10 +61,10 @@ import java.util.Hashtable;
public class LinkProperties implements Parcelable {
// The interface described by the network link.
private String mIfaceName;
- private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
- private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
+ private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
+ private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
private String mDomains;
- private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+ private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
private ProxyProperties mHttpProxy;
private int mMtu;
@@ -156,28 +156,52 @@ public class LinkProperties implements Parcelable {
return addresses;
}
+ private int findLinkAddressIndex(LinkAddress address) {
+ for (int i = 0; i < mLinkAddresses.size(); i++) {
+ if (mLinkAddresses.get(i).isSameAddressAs(address)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
/**
- * Adds a link address if it does not exist, or update it if it does.
+ * Adds a link address if it does not exist, or updates it if it does.
* @param address The {@code LinkAddress} to add.
- * @return true if the address was added, false if it already existed.
+ * @return true if {@code address} was added or updated, false otherwise.
*/
public boolean addLinkAddress(LinkAddress address) {
- // TODO: when the LinkAddress has other attributes beyond the
- // address and the prefix length, update them here.
- if (address != null && !mLinkAddresses.contains(address)) {
+ if (address == null) {
+ return false;
+ }
+ int i = findLinkAddressIndex(address);
+ if (i < 0) {
+ // Address was not present. Add it.
mLinkAddresses.add(address);
return true;
+ } else if (mLinkAddresses.get(i).equals(address)) {
+ // Address was present and has same properties. Do nothing.
+ return false;
+ } else {
+ // Address was present and has different properties. Update it.
+ mLinkAddresses.set(i, address);
+ return true;
}
- return false;
}
/**
- * Removes a link address.
- * @param address The {@code LinkAddress} to remove.
+ * Removes a link address. Specifically, removes the link address, if any, for which
+ * {@code isSameAddressAs(toRemove)} returns true.
+ * @param address A {@code LinkAddress} specifying the address to remove.
* @return true if the address was removed, false if it did not exist.
*/
public boolean removeLinkAddress(LinkAddress toRemove) {
- return mLinkAddresses.remove(toRemove);
+ int i = findLinkAddressIndex(toRemove);
+ if (i >= 0) {
+ mLinkAddresses.remove(i);
+ return true;
+ }
+ return false;
}
/**
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 1e80a21..5502a17 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -37,12 +37,12 @@ public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub {
}
@Override
- public void addressUpdated(LinkAddress address, String iface, int flags, int scope) {
+ public void addressUpdated(String iface, LinkAddress address) {
// default no-op
}
@Override
- public void addressRemoved(LinkAddress address, String iface, int flags, int scope) {
+ public void addressRemoved(String iface, LinkAddress address) {
// default no-op
}
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java
index 389ff4d..17423be 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/core/tests/coretests/src/android/net/LinkAddressTest.java
@@ -22,6 +22,7 @@ import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -31,6 +32,14 @@ import android.os.Parcel;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import static libcore.io.OsConstants.IFA_F_DEPRECATED;
+import static libcore.io.OsConstants.IFA_F_PERMANENT;
+import static libcore.io.OsConstants.IFA_F_TENTATIVE;
+import static libcore.io.OsConstants.RT_SCOPE_HOST;
+import static libcore.io.OsConstants.RT_SCOPE_LINK;
+import static libcore.io.OsConstants.RT_SCOPE_SITE;
+import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE;
+
/**
* Tests for {@link LinkAddress}.
*/
@@ -48,18 +57,27 @@ public class LinkAddressTest extends AndroidTestCase {
address = new LinkAddress(V4_ADDRESS, 25);
assertEquals(V4_ADDRESS, address.getAddress());
assertEquals(25, address.getNetworkPrefixLength());
+ assertEquals(0, address.getFlags());
+ assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
address = new LinkAddress(V6_ADDRESS, 127);
assertEquals(V6_ADDRESS, address.getAddress());
assertEquals(127, address.getNetworkPrefixLength());
+ assertEquals(0, address.getFlags());
+ assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
- address = new LinkAddress(V6 + "/64");
+ // Nonsensical flags/scopes or combinations thereof are acceptable.
+ address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
assertEquals(V6_ADDRESS, address.getAddress());
assertEquals(64, address.getNetworkPrefixLength());
+ assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
+ assertEquals(RT_SCOPE_LINK, address.getScope());
- address = new LinkAddress(V4 + "/23");
+ address = new LinkAddress(V4 + "/23", 123, 456);
assertEquals(V4_ADDRESS, address.getAddress());
assertEquals(23, address.getNetworkPrefixLength());
+ assertEquals(123, address.getFlags());
+ assertEquals(456, address.getScope());
// InterfaceAddress doesn't have a constructor. Fetch some from an interface.
List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
@@ -88,7 +106,7 @@ public class LinkAddressTest extends AndroidTestCase {
} catch(IllegalArgumentException expected) {}
try {
- address = new LinkAddress((String) null);
+ address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
fail("Null string should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
@@ -99,24 +117,77 @@ public class LinkAddressTest extends AndroidTestCase {
// Invalid prefix lengths are rejected.
try {
- address = new LinkAddress(V4 + "/-1");
+ address = new LinkAddress(V4_ADDRESS, -1);
fail("Negative IPv4 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
- address = new LinkAddress(V6 + "/-1");
+ address = new LinkAddress(V6_ADDRESS, -1);
fail("Negative IPv6 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
- address = new LinkAddress(V4 + "/33");
- fail("/35 IPv4 prefix length should cause IllegalArgumentException");
+ address = new LinkAddress(V4_ADDRESS, 33);
+ fail("/33 IPv4 prefix length should cause IllegalArgumentException");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
+ fail("/33 IPv4 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
+
try {
- address = new LinkAddress(V6 + "/129");
+ address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
fail("/129 IPv6 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
+
+ try {
+ address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
+ fail("/129 IPv6 prefix length should cause IllegalArgumentException");
+ } catch(IllegalArgumentException expected) {}
+
+ // Multicast addresses are rejected.
+ try {
+ address = new LinkAddress("224.0.0.2/32");
+ fail("IPv4 multicast address should cause IllegalArgumentException");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ address = new LinkAddress("ff02::1/128");
+ fail("IPv6 multicast address should cause IllegalArgumentException");
+ } catch(IllegalArgumentException expected) {}
+ }
+
+ public void testAddressScopes() {
+ assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
+ assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
+
+ assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope());
+ assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope());
+ assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope());
+ assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope());
+
+ assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope());
+
+ assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope());
+ assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope());
+ assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope());
+ assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope());
+ }
+
+ private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) {
+ assertTrue(l1 + " unexpectedly does not have same address as " + l2,
+ l1.isSameAddressAs(l2));
+ assertTrue(l2 + " unexpectedly does not have same address as " + l1,
+ l2.isSameAddressAs(l1));
+ }
+
+ private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) {
+ assertFalse(l1 + " unexpectedly has same address as " + l2,
+ l1.isSameAddressAs(l2));
+ assertFalse(l2 + " unexpectedly has same address as " + l1,
+ l1.isSameAddressAs(l2));
}
private void assertLinkAddressesEqual(LinkAddress l1, LinkAddress l2) {
@@ -130,33 +201,73 @@ public class LinkAddressTest extends AndroidTestCase {
assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1));
}
- public void testEquals() {
- LinkAddress l1, l2;
+ public void testEqualsAndSameAddressAs() {
+ LinkAddress l1, l2, l3;
l1 = new LinkAddress("2001:db8::1/64");
l2 = new LinkAddress("2001:db8::1/64");
assertLinkAddressesEqual(l1, l2);
+ assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress("2001:db8::1/65");
assertLinkAddressesNotEqual(l1, l2);
+ assertIsNotSameAddressAs(l1, l2);
+
l2 = new LinkAddress("2001:db8::2/64");
assertLinkAddressesNotEqual(l1, l2);
+ assertIsNotSameAddressAs(l1, l2);
+
l1 = new LinkAddress("192.0.2.1/24");
l2 = new LinkAddress("192.0.2.1/24");
assertLinkAddressesEqual(l1, l2);
+ assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress("192.0.2.1/23");
assertLinkAddressesNotEqual(l1, l2);
+ assertIsNotSameAddressAs(l1, l2);
+
l2 = new LinkAddress("192.0.2.2/24");
assertLinkAddressesNotEqual(l1, l2);
+ assertIsNotSameAddressAs(l1, l2);
- // Addresses with the same start or end bytes aren't equal between families.
- l1 = new LinkAddress("255.255.255.255/24");
- l2 = new LinkAddress("ffff:ffff::/24");
+
+ // Check equals() and isSameAddressAs() on identical addresses with different flags.
+ l1 = new LinkAddress(V6_ADDRESS, 64);
+ l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
+ assertLinkAddressesEqual(l1, l2);
+ assertIsSameAddressAs(l1, l2);
+
+ l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE);
assertLinkAddressesNotEqual(l1, l2);
- l2 = new LinkAddress("::ffff:ffff/24");
+ assertIsSameAddressAs(l1, l2);
+
+ // Check equals() and isSameAddressAs() on identical addresses with different scope.
+ l1 = new LinkAddress(V4_ADDRESS, 24);
+ l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE);
+ assertLinkAddressesEqual(l1, l2);
+ assertIsSameAddressAs(l1, l2);
+
+ l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST);
+ assertLinkAddressesNotEqual(l1, l2);
+ assertIsSameAddressAs(l1, l2);
+
+ // Addresses with the same start or end bytes aren't equal between families.
+ l1 = new LinkAddress("32.1.13.184/24");
+ l2 = new LinkAddress("2001:db8::1/24");
+ l3 = new LinkAddress("::2001:db8/24");
+
+ byte[] ipv4Bytes = l1.getAddress().getAddress();
+ byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4);
+ byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16);
+ assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes));
+ assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes));
+
assertLinkAddressesNotEqual(l1, l2);
+ assertIsNotSameAddressAs(l1, l2);
+
+ assertLinkAddressesNotEqual(l1, l3);
+ assertIsNotSameAddressAs(l1, l3);
// Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address.
// TODO: Investigate fixing this.
@@ -164,6 +275,7 @@ public class LinkAddressTest extends AndroidTestCase {
l1 = new LinkAddress(addressString);
l2 = new LinkAddress("::ffff:" + addressString);
assertLinkAddressesEqual(l1, l2);
+ assertIsSameAddressAs(l1, l2);
}
public void testHashCode() {
@@ -172,6 +284,9 @@ public class LinkAddressTest extends AndroidTestCase {
l = new LinkAddress(V4_ADDRESS, 23);
assertEquals(-982787, l.hashCode());
+ l = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
+ assertEquals(-971865, l.hashCode());
+
l = new LinkAddress(V4_ADDRESS, 27);
assertEquals(-982743, l.hashCode());
@@ -180,6 +295,9 @@ public class LinkAddressTest extends AndroidTestCase {
l = new LinkAddress(V6_ADDRESS, 128);
assertEquals(1076523630, l.hashCode());
+
+ l = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
+ assertEquals(1076524846, l.hashCode());
}
private LinkAddress passThroughParcel(LinkAddress l) {
@@ -204,10 +322,10 @@ public class LinkAddressTest extends AndroidTestCase {
public void testParceling() {
LinkAddress l;
- l = new LinkAddress(V6_ADDRESS, 64);
+ l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
assertParcelingIsLossless(l);
- l = new LinkAddress(V4 + "/28");
+ l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
assertParcelingIsLossless(l);
}
}
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index e63f6b0..a602e07 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -24,6 +24,8 @@ import junit.framework.TestCase;
import java.net.InetAddress;
import java.util.ArrayList;
+import libcore.io.OsConstants;
+
public class LinkPropertiesTest extends TestCase {
private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
@@ -341,6 +343,10 @@ public class LinkPropertiesTest extends TestCase {
assertFalse(rmnet0.removeStackedLink(clat4));
}
+ private LinkAddress getFirstLinkAddress(LinkProperties lp) {
+ return lp.getLinkAddresses().iterator().next();
+ }
+
@SmallTest
public void testAddressMethods() {
LinkProperties lp = new LinkProperties();
@@ -366,26 +372,56 @@ public class LinkPropertiesTest extends TestCase {
// Addresses on the base link.
// Check the return values of hasIPvXAddress and ensure the add/remove methods return true
// iff something changes.
+ assertEquals(0, lp.getLinkAddresses().size());
assertTrue(lp.addLinkAddress(LINKADDRV6));
+ assertEquals(1, lp.getLinkAddresses().size());
assertFalse(lp.hasIPv4Address());
assertTrue(lp.hasIPv6Address());
assertTrue(lp.removeLinkAddress(LINKADDRV6));
+ assertEquals(0, lp.getLinkAddresses().size());
assertTrue(lp.addLinkAddress(LINKADDRV4));
+ assertEquals(1, lp.getLinkAddresses().size());
assertTrue(lp.hasIPv4Address());
assertFalse(lp.hasIPv6Address());
assertTrue(lp.addLinkAddress(LINKADDRV6));
+ assertEquals(2, lp.getLinkAddresses().size());
assertTrue(lp.hasIPv4Address());
assertTrue(lp.hasIPv6Address());
// Adding an address twice has no effect.
// Removing an address that's not present has no effect.
assertFalse(lp.addLinkAddress(LINKADDRV4));
+ assertEquals(2, lp.getLinkAddresses().size());
assertTrue(lp.hasIPv4Address());
assertTrue(lp.removeLinkAddress(LINKADDRV4));
+ assertEquals(1, lp.getLinkAddresses().size());
assertFalse(lp.hasIPv4Address());
assertFalse(lp.removeLinkAddress(LINKADDRV4));
+ assertEquals(1, lp.getLinkAddresses().size());
+
+ // Adding an address that's already present but with different properties causes the
+ // existing address to be updated and returns true.
+ // Start with only LINKADDRV6.
+ assertEquals(1, lp.getLinkAddresses().size());
+ assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
+
+ // Create a LinkAddress object for the same address, but with different flags.
+ LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
+ OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
+ assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
+ assertFalse(deprecated.equals(LINKADDRV6));
+
+ // Check that adding it updates the existing address instead of adding a new one.
+ assertTrue(lp.addLinkAddress(deprecated));
+ assertEquals(1, lp.getLinkAddresses().size());
+ assertEquals(deprecated, getFirstLinkAddress(lp));
+ assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
+
+ // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
+ assertTrue(lp.removeLinkAddress(LINKADDRV6));
+ assertEquals(0, lp.getLinkAddresses().size());
}
@SmallTest