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

Commit 9ba9e079 authored by Benedict Wong's avatar Benedict Wong
Browse files

Add API for VCN configuration of UDP port 4500 NAT Timeouts

This patch adds an API to allow VCN providers to configure the UDP port
4500 hint to improve the power implications of a VPN over the VCN.

Bug: 259000745
Test: atest FrameworksVcnTests
Change-Id: Id464ab43fa15d5f6a693f73932d95d9822320acb
parent 1d2bead4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -27335,6 +27335,7 @@ package android.net.vcn {
    method @NonNull public int[] getExposedCapabilities();
    method @NonNull public String getGatewayConnectionName();
    method @IntRange(from=0x500) public int getMaxMtu();
    method public int getMinUdpPort4500NatTimeoutSeconds();
    method @NonNull public long[] getRetryIntervalsMillis();
    method @NonNull public java.util.List<android.net.vcn.VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities();
    method public boolean hasGatewayOption(int);
@@ -27349,6 +27350,7 @@ package android.net.vcn {
    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeGatewayOption(int);
    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=0x500) int);
    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int);
    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMillis(@NonNull long[]);
    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setVcnUnderlyingNetworkPriorities(@NonNull java.util.List<android.net.vcn.VcnUnderlyingNetworkTemplate>);
  }
+59 −0
Original line number Diff line number Diff line
@@ -81,6 +81,12 @@ import java.util.concurrent.TimeUnit;
 * </ul>
 */
public final class VcnGatewayConnectionConfig {
    /** @hide */
    public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1;

    /** @hide */
    public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS = 120;

    // TODO: Use MIN_MTU_V6 once it is public, @hide
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    static final int MIN_MTU_V6 = 1280;
@@ -225,6 +231,10 @@ public final class VcnGatewayConnectionConfig {
    private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs";
    @NonNull private final long[] mRetryIntervalsMs;

    private static final String MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY =
            "mMinUdpPort4500NatTimeoutSeconds";
    private final int mMinUdpPort4500NatTimeoutSeconds;

    private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions";
    @NonNull private final Set<Integer> mGatewayOptions;

@@ -236,12 +246,14 @@ public final class VcnGatewayConnectionConfig {
            @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
            @NonNull long[] retryIntervalsMs,
            @IntRange(from = MIN_MTU_V6) int maxMtu,
            @NonNull int minUdpPort4500NatTimeoutSeconds,
            @NonNull Set<Integer> gatewayOptions) {
        mGatewayConnectionName = gatewayConnectionName;
        mTunnelConnectionParams = tunnelConnectionParams;
        mExposedCapabilities = new TreeSet(exposedCapabilities);
        mRetryIntervalsMs = retryIntervalsMs;
        mMaxMtu = maxMtu;
        mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
        mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions));

        mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates);
@@ -301,6 +313,10 @@ public final class VcnGatewayConnectionConfig {

        mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
        mMaxMtu = in.getInt(MAX_MTU_KEY);
        mMinUdpPort4500NatTimeoutSeconds =
                in.getInt(
                        MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY,
                        MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);

        validate();
    }
@@ -323,6 +339,12 @@ public final class VcnGatewayConnectionConfig {
        Preconditions.checkArgument(
                mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");

        Preconditions.checkArgument(
                mMinUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
                        || mMinUdpPort4500NatTimeoutSeconds
                                >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
                "minUdpPort4500NatTimeoutSeconds must be at least 120s");

        for (int option : mGatewayOptions) {
            validateGatewayOption(option);
        }
@@ -451,6 +473,15 @@ public final class VcnGatewayConnectionConfig {
        return mMaxMtu;
    }

    /**
     * Retrieves the maximum supported IKEv2/IPsec NATT keepalive timeout.
     *
     * @see Builder#setMinUdpPort4500NatTimeoutSeconds(int)
     */
    public int getMinUdpPort4500NatTimeoutSeconds() {
        return mMinUdpPort4500NatTimeoutSeconds;
    }

    /**
     * Checks if the given VCN gateway option is enabled.
     *
@@ -496,6 +527,7 @@ public final class VcnGatewayConnectionConfig {
        result.putPersistableBundle(GATEWAY_OPTIONS_KEY, gatewayOptionsBundle);
        result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
        result.putInt(MAX_MTU_KEY, mMaxMtu);
        result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds);

        return result;
    }
@@ -509,6 +541,7 @@ public final class VcnGatewayConnectionConfig {
                mUnderlyingNetworkTemplates,
                Arrays.hashCode(mRetryIntervalsMs),
                mMaxMtu,
                mMinUdpPort4500NatTimeoutSeconds,
                mGatewayOptions);
    }

@@ -525,6 +558,7 @@ public final class VcnGatewayConnectionConfig {
                && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates)
                && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
                && mMaxMtu == rhs.mMaxMtu
                && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds
                && mGatewayOptions.equals(rhs.mGatewayOptions);
    }

@@ -542,6 +576,7 @@ public final class VcnGatewayConnectionConfig {

        @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
        private int mMaxMtu = DEFAULT_MAX_MTU;
        private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;

        @NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>();

@@ -702,6 +737,29 @@ public final class VcnGatewayConnectionConfig {
            return this;
        }

        /**
         * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout.
         *
         * <p>This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs,
         * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data.
         *
         * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN
         *     Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN
         *     Gateway.
         * @return this {@link Builder} instance, for chaining
         */
        @NonNull
        public Builder setMinUdpPort4500NatTimeoutSeconds(
                @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS)
                        int minUdpPort4500NatTimeoutSeconds) {
            Preconditions.checkArgument(
                    minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
                    "Timeout must be at least 120s");

            mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
            return this;
        }

        /**
         * Enables the specified VCN gateway option.
         *
@@ -744,6 +802,7 @@ public final class VcnGatewayConnectionConfig {
                    mUnderlyingNetworkTemplates,
                    mRetryIntervalsMs,
                    mMaxMtu,
                    mMinUdpPort4500NatTimeoutSeconds,
                    mGatewayOptions);
        }
    }
+43 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.net.vcn;

import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;

import android.annotation.NonNull;
@@ -49,18 +50,29 @@ import java.util.Objects;
public class VcnTransportInfo implements TransportInfo, Parcelable {
    @Nullable private final WifiInfo mWifiInfo;
    private final int mSubId;
    private final int mMinUdpPort4500NatTimeoutSeconds;

    public VcnTransportInfo(@NonNull WifiInfo wifiInfo) {
        this(wifiInfo, INVALID_SUBSCRIPTION_ID);
        this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
    }

    public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) {
        this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds);
    }

    public VcnTransportInfo(int subId) {
        this(null /* wifiInfo */, subId);
        this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
    }

    private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) {
    public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) {
        this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds);
    }

    private VcnTransportInfo(
            @Nullable WifiInfo wifiInfo, int subId, int minUdpPort4500NatTimeoutSeconds) {
        mWifiInfo = wifiInfo;
        mSubId = subId;
        mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
    }

    /**
@@ -88,16 +100,28 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
        return mSubId;
    }

    /**
     * Get the VCN provided UDP port 4500 NAT timeout
     *
     * @return the UDP 4500 NAT timeout, or
     *     VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set.
     */
    public int getMinUdpPort4500NatTimeoutSeconds() {
        return mMinUdpPort4500NatTimeoutSeconds;
    }

    @Override
    public int hashCode() {
        return Objects.hash(mWifiInfo, mSubId);
        return Objects.hash(mWifiInfo, mSubId, mMinUdpPort4500NatTimeoutSeconds);
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof VcnTransportInfo)) return false;
        final VcnTransportInfo that = (VcnTransportInfo) o;
        return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId;
        return Objects.equals(mWifiInfo, that.mWifiInfo)
                && mSubId == that.mSubId
                && mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds;
    }

    /** {@inheritDoc} */
@@ -110,11 +134,14 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
    @NonNull
    public TransportInfo makeCopy(long redactions) {
        if ((redactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) != 0) {
            return new VcnTransportInfo(null, INVALID_SUBSCRIPTION_ID);
            return new VcnTransportInfo(
                    null, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
        }

        return new VcnTransportInfo(
                (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), mSubId);
                (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions),
                mSubId,
                mMinUdpPort4500NatTimeoutSeconds);
    }

    @Override
@@ -134,6 +161,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mSubId);
        dest.writeParcelable(mWifiInfo, flags);
        dest.writeInt(mMinUdpPort4500NatTimeoutSeconds);
    }

    @Override
@@ -146,16 +174,21 @@ public class VcnTransportInfo implements TransportInfo, Parcelable {
            new Creator<VcnTransportInfo>() {
                public VcnTransportInfo createFromParcel(Parcel in) {
                    final int subId = in.readInt();
                    final WifiInfo wifiInfo = in.readParcelable(null, android.net.wifi.WifiInfo.class);
                    final WifiInfo wifiInfo =
                            in.readParcelable(null, android.net.wifi.WifiInfo.class);
                    final int minUdpPort4500NatTimeoutSeconds = in.readInt();

                    // If all fields are their null values, return null TransportInfo to avoid
                    // leaking information about this being a VCN Network (instead of macro
                    // cellular, etc)
                    if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) {
                    if (wifiInfo == null
                            && subId == INVALID_SUBSCRIPTION_ID
                            && minUdpPort4500NatTimeoutSeconds
                                    == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET) {
                        return null;
                    }

                    return new VcnTransportInfo(wifiInfo, subId);
                    return new VcnTransportInfo(wifiInfo, subId, minUdpPort4500NatTimeoutSeconds);
                }

                public VcnTransportInfo[] newArray(int size) {
+8 −2
Original line number Diff line number Diff line
@@ -2255,12 +2255,18 @@ public class VcnGatewayConnection extends StateMachine {
            if (underlyingCaps.hasTransport(TRANSPORT_WIFI)
                    && underlyingCaps.getTransportInfo() instanceof WifiInfo) {
                final WifiInfo wifiInfo = (WifiInfo) underlyingCaps.getTransportInfo();
                builder.setTransportInfo(new VcnTransportInfo(wifiInfo));
                builder.setTransportInfo(
                        new VcnTransportInfo(
                                wifiInfo,
                                gatewayConnectionConfig.getMinUdpPort4500NatTimeoutSeconds()));
            } else if (underlyingCaps.hasTransport(TRANSPORT_CELLULAR)
                    && underlyingCaps.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) {
                final TelephonyNetworkSpecifier telNetSpecifier =
                        (TelephonyNetworkSpecifier) underlyingCaps.getNetworkSpecifier();
                builder.setTransportInfo(new VcnTransportInfo(telNetSpecifier.getSubscriptionId()));
                builder.setTransportInfo(
                        new VcnTransportInfo(
                                telNetSpecifier.getSubscriptionId(),
                                gatewayConnectionConfig.getMinUdpPort4500NatTimeoutSeconds()));
            } else {
                Slog.wtf(
                        TAG,
+4 −1
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ public class VcnGatewayConnectionConfigTest {
                TimeUnit.MINUTES.toMillis(30)
            };
    public static final int MAX_MTU = 1360;
    public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT = 120;

    private static final Set<Integer> GATEWAY_OPTIONS =
            Collections.singleton(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY);
@@ -104,7 +105,9 @@ public class VcnGatewayConnectionConfigTest {
    public static VcnGatewayConnectionConfig buildTestConfig(
            List<VcnUnderlyingNetworkTemplate> nwTemplates) {
        final VcnGatewayConnectionConfig.Builder builder =
                newBuilder().setVcnUnderlyingNetworkPriorities(nwTemplates);
                newBuilder()
                        .setVcnUnderlyingNetworkPriorities(nwTemplates)
                        .setMinUdpPort4500NatTimeoutSeconds(MIN_UDP_PORT_4500_NAT_TIMEOUT);

        return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS);
    }
Loading