Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2120daf5 authored by Jack Yu's avatar Jack Yu
Browse files

Added expiration time and deprecation time support

Added link address deprecation time and expiration
time for SSC mode 3 support.

Bug: 135717900
Bug: 142949345
Test: LinkAddressTest

Change-Id: Ibc030d2a70ded66e00dd3bdae209609b9118de78
parent daa6bcdb
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -6121,13 +6121,18 @@ package android.net {
  public class LinkAddress implements android.os.Parcelable {
    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
    ctor public LinkAddress(@NonNull String);
    ctor public LinkAddress(@NonNull String, int, int);
    method public long getDeprecationTime();
    method public long getExpirationTime();
    method public boolean isGlobalPreferred();
    method public boolean isIpv4();
    method public boolean isIpv6();
    method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
    field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
    field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
  }
  public final class LinkProperties implements android.os.Parcelable {
+3 −0
Original line number Diff line number Diff line
@@ -1562,9 +1562,12 @@ package android.net {

  public class LinkAddress implements android.os.Parcelable {
    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
    ctor public LinkAddress(@NonNull String);
    ctor public LinkAddress(@NonNull String, int, int);
    method public long getDeprecationTime();
    method public long getExpirationTime();
    method public boolean isGlobalPreferred();
    method public boolean isIpv4();
    method public boolean isIpv6();
+163 −11
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.net;
import static android.system.OsConstants.IFA_F_DADFAILED;
import static android.system.OsConstants.IFA_F_DEPRECATED;
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
import static android.system.OsConstants.IFA_F_PERMANENT;
import static android.system.OsConstants.IFA_F_TENTATIVE;
import static android.system.OsConstants.RT_SCOPE_HOST;
import static android.system.OsConstants.RT_SCOPE_LINK;
@@ -34,6 +35,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.Pair;

import java.net.Inet4Address;
@@ -41,6 +43,7 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
import java.util.Objects;

/**
 * Identifies an IP address on a network link.
@@ -58,6 +61,21 @@ import java.net.UnknownHostException;
 * </ul>
 */
public class LinkAddress implements Parcelable {

    /**
     * Indicates the deprecation or expiration time is unknown
     * @hide
     */
    @SystemApi
    public static final long LIFETIME_UNKNOWN = -1;

    /**
     * Indicates this address is permanent.
     * @hide
     */
    @SystemApi
    public static final long LIFETIME_PERMANENT = Long.MAX_VALUE;

    /**
     * IPv4 or IPv6 address.
     */
@@ -71,7 +89,9 @@ public class LinkAddress implements Parcelable {
    private int prefixLength;

    /**
     * Address flags. A bitmask of IFA_F_* values.
     * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not
     * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED}
     * flag depending on the current preferred lifetime.
     */
    private int flags;

@@ -80,6 +100,23 @@ public class LinkAddress implements Parcelable {
     */
    private int scope;

    /**
     * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
     * or was deprecated. {@link #LIFETIME_UNKNOWN} indicates this information is not available. At
     * the time existing connections can still use this address until it expires, but new
     * connections should use the new address. {@link #LIFETIME_PERMANENT} indicates this
     * {@link LinkAddress} will never be deprecated.
     */
    private long deprecationTime;

    /**
     * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress}
     * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this
     * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
     * will never expire.
     */
    private long expirationTime;

    /**
     * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
     * RFC 6724 section 3.2.
@@ -152,7 +189,8 @@ public class LinkAddress implements Parcelable {
    /**
     * Utility function for the constructors.
     */
    private void init(InetAddress address, int prefixLength, int flags, int scope) {
    private void init(InetAddress address, int prefixLength, int flags, int scope,
                      long deprecationTime, long expirationTime) {
        if (address == null ||
                address.isMulticastAddress() ||
                prefixLength < 0 ||
@@ -161,15 +199,42 @@ public class LinkAddress implements Parcelable {
            throw new IllegalArgumentException("Bad LinkAddress params " + address +
                    "/" + prefixLength);
        }

        // deprecation time and expiration time must be both provided, or neither.
        if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) {
            throw new IllegalArgumentException(
                    "Must not specify only one of deprecation time and expiration time");
        }

        // deprecation time needs to be a positive value.
        if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) {
            throw new IllegalArgumentException("invalid deprecation time " + deprecationTime);
        }

        // expiration time needs to be a positive value.
        if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) {
            throw new IllegalArgumentException("invalid expiration time " + expirationTime);
        }

        // expiration time can't be earlier than deprecation time
        if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN
                && expirationTime < deprecationTime) {
            throw new IllegalArgumentException("expiration earlier than deprecation ("
                    + deprecationTime + ", " + expirationTime + ")");
        }

        this.address = address;
        this.prefixLength = prefixLength;
        this.flags = flags;
        this.scope = scope;
        this.deprecationTime = deprecationTime;
        this.expirationTime = expirationTime;
    }

    /**
     * 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. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
     * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
@@ -181,7 +246,39 @@ public class LinkAddress implements Parcelable {
    @TestApi
    public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
            int flags, int scope) {
        init(address, prefixLength, flags, scope);
        init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
    }

    /**
     * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with
     * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not
     * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT}
     * flag will be adjusted based on the passed-in lifetimes.
     *
     * @param address The IP address.
     * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
     * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
     * @param scope An integer defining the scope in which the address is unique (e.g.,
     *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
     * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
     *                        this {@link LinkAddress} will be or was deprecated.
     *                        {@link #LIFETIME_UNKNOWN} indicates this information is not available.
     *                        At the time existing connections can still use this address until it
     *                        expires, but new connections should use the new address.
     *                        {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
     *                        never be deprecated.
     * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
     *                       {@link LinkAddress} will expire and be removed from the interface.
     *                       {@link #LIFETIME_UNKNOWN} indicates this information is not available.
     *                       {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
     *                       never expire.
     * @hide
     */
    @SystemApi
    @TestApi
    public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
                       int flags, int scope, long deprecationTime, long expirationTime) {
        init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
    }

    /**
@@ -237,7 +334,7 @@ public class LinkAddress implements Parcelable {
        // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
        // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
        Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
        init(ipAndMask.first, ipAndMask.second, flags, scope);
        init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
    }

    /**
@@ -265,10 +362,12 @@ public class LinkAddress implements Parcelable {
            return false;
        }
        LinkAddress linkAddress = (LinkAddress) obj;
        return this.address.equals(linkAddress.address) &&
            this.prefixLength == linkAddress.prefixLength &&
            this.flags == linkAddress.flags &&
            this.scope == linkAddress.scope;
        return this.address.equals(linkAddress.address)
                && this.prefixLength == linkAddress.prefixLength
                && this.flags == linkAddress.flags
                && this.scope == linkAddress.scope
                && this.deprecationTime == linkAddress.deprecationTime
                && this.expirationTime == linkAddress.expirationTime;
    }

    /**
@@ -276,7 +375,7 @@ public class LinkAddress implements Parcelable {
     */
    @Override
    public int hashCode() {
        return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
        return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime);
    }

    /**
@@ -329,6 +428,25 @@ public class LinkAddress implements Parcelable {
     * Returns the flags of this {@code LinkAddress}.
     */
    public int getFlags() {
        int flags = this.flags;
        if (deprecationTime != LIFETIME_UNKNOWN) {
            if (SystemClock.elapsedRealtime() >= deprecationTime) {
                flags |= IFA_F_DEPRECATED;
            } else {
                // If deprecation time is in the future, or permanent.
                flags &= ~IFA_F_DEPRECATED;
            }
        }

        if (expirationTime == LIFETIME_PERMANENT) {
            flags |= IFA_F_PERMANENT;
        } else if (expirationTime != LIFETIME_UNKNOWN) {
            // If we know this address expired or will expire in the future or, then this address
            // should not be permanent.
            flags &= ~IFA_F_PERMANENT;
        }

        // Do no touch the original flags. Return the adjusted flags here.
        return flags;
    }

@@ -340,7 +458,35 @@ public class LinkAddress implements Parcelable {
    }

    /**
     * Returns true if this {@code LinkAddress} is global scope and preferred.
     * @return The time that this address will be deprecated. At the time the existing connection
     * can still use this address until it expires, but the new connection should use the new
     * address. This is the EPOCH time in milliseconds. 0 indicates this information is not
     * available.
     *
     * @hide
     */
    @SystemApi
    @TestApi
    public long getDeprecationTime() {
        return deprecationTime;
    }

    /**
     * @return The time that this address will expire and will be no longer valid. This is the EPOCH
     * time in milliseconds. 0 indicates this information is not available.
     *
     * @hide
     */
    @SystemApi
    @TestApi
    public long getExpirationTime() {
        return expirationTime;
    }

    /**
     * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently
     * deprecated).
     *
     * @hide
     */
    @TestApi
@@ -352,6 +498,7 @@ public class LinkAddress implements Parcelable {
         * state has cleared either DAD has succeeded or failed, and both
         * flags are cleared regardless).
         */
        int flags = getFlags();
        return (scope == RT_SCOPE_UNIVERSE
                && !isIpv6ULA()
                && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
@@ -373,6 +520,8 @@ public class LinkAddress implements Parcelable {
        dest.writeInt(prefixLength);
        dest.writeInt(this.flags);
        dest.writeInt(scope);
        dest.writeLong(deprecationTime);
        dest.writeLong(expirationTime);
    }

    /**
@@ -392,7 +541,10 @@ public class LinkAddress implements Parcelable {
                int prefixLength = in.readInt();
                int flags = in.readInt();
                int scope = in.readInt();
                return new LinkAddress(address, prefixLength, flags, scope);
                long deprecationTime = in.readLong();
                long expirationTime = in.readLong();
                return new LinkAddress(address, prefixLength, flags, scope, deprecationTime,
                        expirationTime);
            }

            public LinkAddress[] newArray(int size) {
+82 −1
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.os.SystemClock;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

@@ -316,11 +318,83 @@ public class LinkAddressTest {

        l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
        assertParcelingIsLossless(l);
        l = new LinkAddress(V6_ADDRESS, 64, 123, 456,
                1L, 3600000L);
        assertParcelingIsLossless(l);

        l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
        assertParcelSane(l, 4);
        assertParcelSane(l, 6);
    }

    @Test
    public void testDeprecationTime() {
        try {
            new LinkAddress(V6_ADDRESS, 64, 0, 456,
                    LinkAddress.LIFETIME_UNKNOWN,
                    SystemClock.elapsedRealtime() + 200000);
            fail("Only one time provided should cause exception");
        } catch (IllegalArgumentException expected) { }

        try {
            new LinkAddress(V6_ADDRESS, 64, 0, 456,
                    SystemClock.elapsedRealtime() - 100000,
                    SystemClock.elapsedRealtime() - 200000);
            fail("deprecation time later than expiration time should cause exception");
        } catch (IllegalArgumentException expected) { }

        try {
            new LinkAddress(V6_ADDRESS, 64, 0, 456,
                    -2, SystemClock.elapsedRealtime());
            fail("negative deprecation time should cause exception");
        } catch (IllegalArgumentException expected) { }
    }

    @Test
    public void testExpirationTime() {
        try {
            new LinkAddress(V6_ADDRESS, 64, 0, 456,
                    SystemClock.elapsedRealtime() + 200000,
                    LinkAddress.LIFETIME_UNKNOWN);
            fail("Only one time provided should cause exception");
        } catch (IllegalArgumentException expected) { }

        try {
            new LinkAddress(V6_ADDRESS, 64, 0, 456,
                    SystemClock.elapsedRealtime() - 10000, -2);
            fail("negative expiration time should cause exception");
        } catch (IllegalArgumentException expected) { }
    }

    @Test
    public void testGetFlags() {
        LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
        assertEquals(123, l.getFlags());

        // Test if deprecated bit was added/remove automatically based on the provided deprecation
        // time
        l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
                SystemClock.elapsedRealtime() - 100000, LinkAddress.LIFETIME_PERMANENT);
        // Check if the flag is added automatically.
        assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);

        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
                SystemClock.elapsedRealtime() + 100000, LinkAddress.LIFETIME_PERMANENT);
        // Check if the flag is removed automatically.
        assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);

        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
                LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
        // Check if the permanent flag is added.
        assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);

        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
                SystemClock.elapsedRealtime() - 100000,
                SystemClock.elapsedRealtime() + 100000);
        // Check if the permanent flag is removed
        assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
    }


    private void assertGlobalPreferred(LinkAddress l, String msg) {
        assertTrue(msg, l.isGlobalPreferred());
    }
@@ -389,5 +463,12 @@ public class LinkAddressTest {
                            (IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
                            RT_SCOPE_UNIVERSE);
        assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");

        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
                RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
                SystemClock.elapsedRealtime() + 200000);
        // Although the deprecated bit is set, but the deprecation time is in the future, test
        // if the flag is removed automatically.
        assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
    }
}