Merge changes from topics "encrypted-tunnel-interface", "iketunnelparams", "vcn-encrypted-tunnel"

* changes:
  Replace VcnControlPlaneConfig with TunnelConnectionParams
  Convert TunnelConnectionParams to/from PersistableBundle
  Create TunnelConnectionParams interface
diff --git a/core/api/current.txt b/core/api/current.txt
index 5bc749f..4968a5f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -25138,6 +25138,9 @@
     field public static final int UNSUPPORTED = -1; // 0xffffffff
   }
 
+  public interface TunnelConnectionParams {
+  }
+
   public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
     method public abstract android.net.Uri.Builder buildUpon();
     method public int compareTo(android.net.Uri);
@@ -25698,15 +25701,6 @@
     method @NonNull public android.net.vcn.VcnConfig build();
   }
 
-  public abstract class VcnControlPlaneConfig {
-  }
-
-  public final class VcnControlPlaneIkeConfig extends android.net.vcn.VcnControlPlaneConfig {
-    ctor public VcnControlPlaneIkeConfig(@NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.TunnelModeChildSessionParams);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams getChildSessionParams();
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams getIkeSessionParams();
-  }
-
   public final class VcnGatewayConnectionConfig {
     method @NonNull public int[] getExposedCapabilities();
     method @NonNull public String getGatewayConnectionName();
@@ -25715,7 +25709,7 @@
   }
 
   public static final class VcnGatewayConnectionConfig.Builder {
-    ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.vcn.VcnControlPlaneConfig);
+    ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.TunnelConnectionParams);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
diff --git a/core/java/android/net/TunnelConnectionParams.java b/core/java/android/net/TunnelConnectionParams.java
new file mode 100644
index 0000000..f5b3539
--- /dev/null
+++ b/core/java/android/net/TunnelConnectionParams.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+/**
+ * TunnelConnectionParams represents a configuration to set up a tunnel connection.
+ *
+ * <p>Concrete implementations for a control plane protocol should implement this interface.
+ * Subclasses should be immutable data classes containing connection, authentication and
+ * authorization parameters required to establish a tunnel connection.
+ *
+ * @see android.net.ipsec.ike.IkeTunnelConnectionParams
+ */
+// TODO:b/186071626 Remove TunnelConnectionParams when non-updatable API stub can resolve
+// IkeTunnelConnectionParams
+public interface TunnelConnectionParams {}
diff --git a/core/java/android/net/vcn/VcnControlPlaneConfig.java b/core/java/android/net/vcn/VcnControlPlaneConfig.java
deleted file mode 100644
index 92f6c44..0000000
--- a/core/java/android/net/vcn/VcnControlPlaneConfig.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.vcn;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.os.PersistableBundle;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * This class represents a control plane configuration for a Virtual Carrier Network connection.
- *
- * <p>Each {@link VcnGatewayConnectionConfig} must have a {@link VcnControlPlaneConfig}, containing
- * all connection, authentication and authorization parameters required to establish a Gateway
- * Connection with a remote endpoint.
- *
- * <p>A {@link VcnControlPlaneConfig} object can be shared by multiple {@link
- * VcnGatewayConnectionConfig}(s) if they will used for connecting with the same remote endpoint.
- *
- * @see VcnManager
- * @see VcnGatewayConnectionConfig
- */
-public abstract class VcnControlPlaneConfig {
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({CONFIG_TYPE_IKE})
-    public @interface ConfigType {}
-
-    /** @hide */
-    public static final int CONFIG_TYPE_IKE = 1;
-
-    private static final String CONFIG_TYPE_KEY = "mConfigType";
-    @ConfigType private final int mConfigType;
-
-    /**
-     * Package private constructor.
-     *
-     * @hide
-     */
-    VcnControlPlaneConfig(int configType) {
-        mConfigType = configType;
-    }
-
-    /**
-     * Constructs a VcnControlPlaneConfig object by deserializing a PersistableBundle.
-     *
-     * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneConfig} object
-     * @hide
-     */
-    public static VcnControlPlaneConfig fromPersistableBundle(@NonNull PersistableBundle in) {
-        Objects.requireNonNull(in, "PersistableBundle was null");
-
-        int configType = in.getInt(CONFIG_TYPE_KEY);
-        switch (configType) {
-            case CONFIG_TYPE_IKE:
-                return new VcnControlPlaneIkeConfig(in);
-            default:
-                throw new IllegalStateException("Unrecognized configType: " + configType);
-        }
-    }
-
-    /**
-     * Converts this VcnControlPlaneConfig to a PersistableBundle.
-     *
-     * @hide
-     */
-    @NonNull
-    public PersistableBundle toPersistableBundle() {
-        final PersistableBundle result = new PersistableBundle();
-        result.putInt(CONFIG_TYPE_KEY, mConfigType);
-        return result;
-    }
-
-    /** @hide */
-    @Override
-    public int hashCode() {
-        return Objects.hash(mConfigType);
-    }
-
-    /** @hide */
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VcnControlPlaneConfig)) {
-            return false;
-        }
-
-        return mConfigType == ((VcnControlPlaneConfig) o).mConfigType;
-    }
-
-    /**
-     * Returns a deep copy of this object.
-     *
-     * @hide
-     */
-    public abstract VcnControlPlaneConfig copy();
-}
diff --git a/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java b/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java
deleted file mode 100644
index 22d7faf..0000000
--- a/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.vcn;
-
-import static android.net.vcn.VcnControlPlaneConfig.CONFIG_TYPE_IKE;
-
-import android.annotation.NonNull;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.TunnelModeChildSessionParams;
-import android.net.vcn.persistablebundleutils.IkeSessionParamsUtils;
-import android.net.vcn.persistablebundleutils.TunnelModeChildSessionParamsUtils;
-import android.os.PersistableBundle;
-import android.util.ArraySet;
-import android.util.Log;
-
-import java.util.Objects;
-
-/**
- * This class is an IKEv2 control plane configuration for a Virtual Carrier Network connection.
- *
- * <p>This class is an extension of the {@link VcnControlPlaneConfig}, containing IKEv2-specific
- * configuration, authentication and authorization parameters.
- *
- * @see VcnControlPlaneConfig
- */
-public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig {
-    private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName();
-
-    private static final String IKE_PARAMS_KEY = "mIkeParams";
-    @NonNull private final IkeSessionParams mIkeParams;
-
-    private static final String CHILD_PARAMS_KEY = "mChildParams";
-    @NonNull private final TunnelModeChildSessionParams mChildParams;
-
-    private static final ArraySet<String> BUNDLE_KEY_SET = new ArraySet<>();
-
-    {
-        BUNDLE_KEY_SET.add(IKE_PARAMS_KEY);
-        BUNDLE_KEY_SET.add(CHILD_PARAMS_KEY);
-    }
-
-    /**
-     * Constructs a VcnControlPlaneIkeConfig object.
-     *
-     * @param ikeParams the IKE Session negotiation parameters
-     * @param childParams the tunnel mode Child Session negotiation parameters
-     */
-    public VcnControlPlaneIkeConfig(
-            @NonNull IkeSessionParams ikeParams,
-            @NonNull TunnelModeChildSessionParams childParams) {
-        super(CONFIG_TYPE_IKE);
-        mIkeParams = ikeParams;
-        mChildParams = childParams;
-        validate();
-    }
-
-    /**
-     * Constructs a VcnControlPlaneIkeConfig object by deserializing a PersistableBundle.
-     *
-     * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneIkeConfig} object
-     * @hide
-     */
-    public VcnControlPlaneIkeConfig(@NonNull PersistableBundle in) {
-        super(CONFIG_TYPE_IKE);
-        final PersistableBundle ikeParamsBundle = in.getPersistableBundle(IKE_PARAMS_KEY);
-        final PersistableBundle childParamsBundle = in.getPersistableBundle(CHILD_PARAMS_KEY);
-
-        Objects.requireNonNull(ikeParamsBundle, "IKE Session Params was null");
-        Objects.requireNonNull(childParamsBundle, "Child Session Params was null");
-
-        mIkeParams = IkeSessionParamsUtils.fromPersistableBundle(ikeParamsBundle);
-        mChildParams = TunnelModeChildSessionParamsUtils.fromPersistableBundle(childParamsBundle);
-
-        for (String key : in.keySet()) {
-            if (!BUNDLE_KEY_SET.contains(key)) {
-                Log.w(TAG, "Found an unexpected key in the PersistableBundle: " + key);
-            }
-        }
-
-        validate();
-    }
-
-    private void validate() {
-        Objects.requireNonNull(mIkeParams, "mIkeParams was null");
-        Objects.requireNonNull(mChildParams, "mChildParams was null");
-    }
-
-    /**
-     * Converts this VcnControlPlaneConfig to a PersistableBundle.
-     *
-     * @hide
-     */
-    @Override
-    @NonNull
-    public PersistableBundle toPersistableBundle() {
-        final PersistableBundle result = super.toPersistableBundle();
-        result.putPersistableBundle(
-                IKE_PARAMS_KEY, IkeSessionParamsUtils.toPersistableBundle(mIkeParams));
-        result.putPersistableBundle(
-                CHILD_PARAMS_KEY,
-                TunnelModeChildSessionParamsUtils.toPersistableBundle(mChildParams));
-        return result;
-    }
-
-    /** Retrieves the IKE Session configuration. */
-    @NonNull
-    public IkeSessionParams getIkeSessionParams() {
-        return mIkeParams;
-    }
-
-    /** Retrieves the tunnel mode Child Session configuration. */
-    @NonNull
-    public TunnelModeChildSessionParams getChildSessionParams() {
-        return mChildParams;
-    }
-
-    /** @hide */
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), mIkeParams, mChildParams);
-    }
-
-    /** @hide */
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VcnControlPlaneIkeConfig)) {
-            return false;
-        }
-
-        VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o;
-
-        return super.equals(o)
-                && Objects.equals(mIkeParams, other.mIkeParams)
-                && Objects.equals(mChildParams, other.mChildParams);
-    }
-
-    /** @hide */
-    @Override
-    public VcnControlPlaneConfig copy() {
-        return new VcnControlPlaneIkeConfig(
-                new IkeSessionParams.Builder(mIkeParams).build(),
-                new TunnelModeChildSessionParams.Builder(mChildParams).build());
-    }
-}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 649e75e..adcbe25 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -24,6 +24,8 @@
 import android.annotation.SuppressLint;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.TunnelConnectionParams;
+import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
 
@@ -151,8 +153,8 @@
     private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
     @NonNull private final String mGatewayConnectionName;
 
-    private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig";
-    @NonNull private VcnControlPlaneConfig mCtrlPlaneConfig;
+    private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams";
+    @NonNull private TunnelConnectionParams mTunnelConnectionParams;
 
     private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
     @NonNull private final SortedSet<Integer> mExposedCapabilities;
@@ -169,13 +171,13 @@
     /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
     private VcnGatewayConnectionConfig(
             @NonNull String gatewayConnectionName,
-            @NonNull VcnControlPlaneConfig ctrlPlaneConfig,
+            @NonNull TunnelConnectionParams tunnelConnectionParams,
             @NonNull Set<Integer> exposedCapabilities,
             @NonNull Set<Integer> underlyingCapabilities,
             @NonNull long[] retryIntervalsMs,
             @IntRange(from = MIN_MTU_V6) int maxMtu) {
         mGatewayConnectionName = gatewayConnectionName;
-        mCtrlPlaneConfig = ctrlPlaneConfig;
+        mTunnelConnectionParams = tunnelConnectionParams;
         mExposedCapabilities = new TreeSet(exposedCapabilities);
         mUnderlyingCapabilities = new TreeSet(underlyingCapabilities);
         mRetryIntervalsMs = retryIntervalsMs;
@@ -187,9 +189,10 @@
     /** @hide */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) {
-        final PersistableBundle ctrlPlaneConfigBundle =
-                in.getPersistableBundle(CTRL_PLANE_CONFIG_KEY);
-        Objects.requireNonNull(ctrlPlaneConfigBundle, "ctrlPlaneConfigBundle was null");
+        final PersistableBundle tunnelConnectionParamsBundle =
+                in.getPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY);
+        Objects.requireNonNull(
+                tunnelConnectionParamsBundle, "tunnelConnectionParamsBundle was null");
 
         final PersistableBundle exposedCapsBundle =
                 in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
@@ -197,7 +200,8 @@
                 in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
 
         mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
-        mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle);
+        mTunnelConnectionParams =
+                TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle);
         mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
                 exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
         mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
@@ -210,7 +214,7 @@
 
     private void validate() {
         Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null");
-        Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null");
+        Objects.requireNonNull(mTunnelConnectionParams, "tunnel connection parameter was null");
 
         Preconditions.checkArgument(
                 mExposedCapabilities != null && !mExposedCapabilities.isEmpty(),
@@ -262,13 +266,13 @@
     }
 
     /**
-     * Returns control plane configuration.
+     * Returns tunnel connection parameters.
      *
      * @hide
      */
     @NonNull
-    public VcnControlPlaneConfig getControlPlaneConfig() {
-        return mCtrlPlaneConfig.copy();
+    public TunnelConnectionParams getTunnelConnectionParams() {
+        return mTunnelConnectionParams;
     }
 
     /**
@@ -360,7 +364,8 @@
     public PersistableBundle toPersistableBundle() {
         final PersistableBundle result = new PersistableBundle();
 
-        final PersistableBundle ctrlPlaneConfigBundle = mCtrlPlaneConfig.toPersistableBundle();
+        final PersistableBundle tunnelConnectionParamsBundle =
+                TunnelConnectionParamsUtils.toPersistableBundle(mTunnelConnectionParams);
         final PersistableBundle exposedCapsBundle =
                 PersistableBundleUtils.fromList(
                         new ArrayList<>(mExposedCapabilities),
@@ -371,7 +376,7 @@
                         PersistableBundleUtils.INTEGER_SERIALIZER);
 
         result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
-        result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle);
+        result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle);
         result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
         result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
         result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
@@ -409,7 +414,7 @@
      */
     public static final class Builder {
         @NonNull private final String mGatewayConnectionName;
-        @NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig;
+        @NonNull private final TunnelConnectionParams mTunnelConnectionParams;
         @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
         @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
         @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
@@ -427,18 +432,18 @@
          *     VcnConfig} must be given a unique name. This name is used by the caller to
          *     distinguish between VcnGatewayConnectionConfigs configured on a single {@link
          *     VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations.
-         * @param ctrlPlaneConfig the control plane configuration
-         * @see VcnControlPlaneConfig
+         * @param tunnelConnectionParams the tunnel connection configuration
+         * @see TunnelConnectionParams
          * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
          */
         public Builder(
                 @NonNull String gatewayConnectionName,
-                @NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+                @NonNull TunnelConnectionParams tunnelConnectionParams) {
             Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null");
-            Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null");
+            Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null");
 
             mGatewayConnectionName = gatewayConnectionName;
-            mCtrlPlaneConfig = ctrlPlaneConfig;
+            mTunnelConnectionParams = tunnelConnectionParams;
         }
 
         /**
@@ -583,7 +588,7 @@
         public VcnGatewayConnectionConfig build() {
             return new VcnGatewayConnectionConfig(
                     mGatewayConnectionName,
-                    mCtrlPlaneConfig,
+                    mTunnelConnectionParams,
                     mExposedCapabilities,
                     mUnderlyingCapabilities,
                     mRetryIntervalsMs,
diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java
new file mode 100644
index 0000000..690e4e7
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.vcn.persistablebundleutils;
+
+import android.annotation.NonNull;
+import android.net.TunnelConnectionParams;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.os.PersistableBundle;
+
+import java.util.Objects;
+
+/**
+ * Utility class to convert TunnelConnectionParams to/from PersistableBundle
+ *
+ * @hide
+ */
+public final class TunnelConnectionParamsUtils {
+    private static final int EXPECTED_BUNDLE_KEY_CNT = 1;
+
+    private static final String PARAMS_TYPE_IKE = "IKE";
+
+    /** Serializes an TunnelConnectionParams to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(@NonNull TunnelConnectionParams params) {
+        final PersistableBundle result = new PersistableBundle();
+
+        if (params instanceof IkeTunnelConnectionParams) {
+            result.putPersistableBundle(
+                    PARAMS_TYPE_IKE,
+                    IkeTunnelConnectionParamsUtils.serializeIkeParams(
+                            (IkeTunnelConnectionParams) params));
+            return result;
+        } else {
+            throw new UnsupportedOperationException("Invalid TunnelConnectionParams type");
+        }
+    }
+
+    /** Constructs an TunnelConnectionParams by deserializing a PersistableBundle. */
+    @NonNull
+    public static TunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        if (in.keySet().size() != EXPECTED_BUNDLE_KEY_CNT) {
+            throw new IllegalArgumentException(
+                    "Expect PersistableBundle to have one element but found: " + in.keySet());
+        }
+
+        if (in.get(PARAMS_TYPE_IKE) != null) {
+            return IkeTunnelConnectionParamsUtils.deserializeIkeParams(
+                    in.getPersistableBundle(PARAMS_TYPE_IKE));
+        }
+
+        throw new IllegalArgumentException(
+                "Invalid TunnelConnectionParams type " + in.keySet().iterator().next());
+    }
+
+    private static final class IkeTunnelConnectionParamsUtils {
+        private static final String IKE_PARAMS_KEY = "IKE_PARAMS_KEY";
+        private static final String CHILD_PARAMS_KEY = "CHILD_PARAMS_KEY";
+
+        @NonNull
+        public static PersistableBundle serializeIkeParams(
+                @NonNull IkeTunnelConnectionParams ikeParams) {
+            final PersistableBundle result = new PersistableBundle();
+
+            result.putPersistableBundle(
+                    IKE_PARAMS_KEY,
+                    IkeSessionParamsUtils.toPersistableBundle(ikeParams.getIkeSessionParams()));
+            result.putPersistableBundle(
+                    CHILD_PARAMS_KEY,
+                    TunnelModeChildSessionParamsUtils.toPersistableBundle(
+                            ikeParams.getTunnelModeChildSessionParams()));
+            return result;
+        }
+
+        @NonNull
+        public static IkeTunnelConnectionParams deserializeIkeParams(
+                @NonNull PersistableBundle in) {
+            final PersistableBundle ikeBundle = in.getPersistableBundle(IKE_PARAMS_KEY);
+            final PersistableBundle childBundle = in.getPersistableBundle(CHILD_PARAMS_KEY);
+            Objects.requireNonNull(ikeBundle, "IkeSessionParams was null");
+            Objects.requireNonNull(ikeBundle, "TunnelModeChildSessionParams was null");
+
+            final IkeSessionParams ikeParams =
+                    IkeSessionParamsUtils.fromPersistableBundle(ikeBundle);
+            final TunnelModeChildSessionParams childParams =
+                    TunnelModeChildSessionParamsUtils.fromPersistableBundle(childBundle);
+            return new IkeTunnelConnectionParams(ikeParams, childParams);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 77bfc5f..6ca3c4b 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -52,6 +52,7 @@
 import android.net.NetworkScore;
 import android.net.RouteInfo;
 import android.net.TelephonyNetworkSpecifier;
+import android.net.TunnelConnectionParams;
 import android.net.Uri;
 import android.net.annotations.PolicyDirection;
 import android.net.ipsec.ike.ChildSessionCallback;
@@ -61,10 +62,10 @@
 import android.net.ipsec.ike.IkeSessionCallback;
 import android.net.ipsec.ike.IkeSessionConfiguration;
 import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
 import android.net.ipsec.ike.exceptions.IkeException;
 import android.net.ipsec.ike.exceptions.IkeInternalException;
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.net.vcn.VcnControlPlaneIkeConfig;
 import android.net.vcn.VcnGatewayConnectionConfig;
 import android.net.vcn.VcnTransportInfo;
 import android.net.wifi.WifiInfo;
@@ -1923,8 +1924,14 @@
             @NonNull IpSecTunnelInterface tunnelIface,
             @NonNull VcnChildSessionConfiguration childConfig,
             @Nullable UnderlyingNetworkRecord underlying) {
-        final VcnControlPlaneIkeConfig controlPlaneConfig =
-                (VcnControlPlaneIkeConfig) gatewayConnectionConfig.getControlPlaneConfig();
+        final TunnelConnectionParams tunnelParams =
+                gatewayConnectionConfig.getTunnelConnectionParams();
+        if (!(tunnelParams instanceof IkeTunnelConnectionParams)) {
+            throw new IllegalStateException(
+                    "TunnelConnectionParams is not IkeTunnelConnectionParams");
+        }
+
+        final IkeTunnelConnectionParams ikeTunnelParams = (IkeTunnelConnectionParams) tunnelParams;
         final LinkProperties lp = new LinkProperties();
 
         lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -1943,7 +1950,7 @@
         final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu();
         lp.setMtu(
                 MtuUtils.getMtu(
-                        controlPlaneConfig.getChildSessionParams().getSaProposals(),
+                        ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(),
                         gatewayConnectionConfig.getMaxMtu(),
                         underlyingMtu));
 
@@ -2131,19 +2138,32 @@
     }
 
     private IkeSessionParams buildIkeParams(@NonNull Network network) {
-        final VcnControlPlaneIkeConfig controlPlaneConfig =
-                (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig();
-        final IkeSessionParams.Builder builder =
-                new IkeSessionParams.Builder(controlPlaneConfig.getIkeSessionParams());
-        builder.setNetwork(network);
+        final TunnelConnectionParams tunnelConnectionParams =
+                mConnectionConfig.getTunnelConnectionParams();
 
-        return builder.build();
+        if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) {
+            final IkeTunnelConnectionParams ikeTunnelConnectionParams =
+                    (IkeTunnelConnectionParams) tunnelConnectionParams;
+            final IkeSessionParams.Builder builder =
+                    new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams());
+            builder.setNetwork(network);
+
+            return builder.build();
+        }
+
+        throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams");
     }
 
     private ChildSessionParams buildChildParams() {
-        final VcnControlPlaneIkeConfig controlPlaneConfig =
-                (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig();
-        return controlPlaneConfig.getChildSessionParams();
+        final TunnelConnectionParams tunnelConnectionParams =
+                mConnectionConfig.getTunnelConnectionParams();
+
+        if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) {
+            return ((IkeTunnelConnectionParams) tunnelConnectionParams)
+                    .getTunnelModeChildSessionParams();
+        }
+
+        throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams");
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
diff --git a/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java b/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java
deleted file mode 100644
index 43b80e4..0000000
--- a/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.vcn;
-
-import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
-import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
-import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.TunnelModeChildSessionParams;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VcnControlPlaneIkeConfigTest {
-    private static final IkeSessionParams IKE_PARAMS;
-    private static final TunnelModeChildSessionParams CHILD_PARAMS;
-
-    static {
-        IkeSaProposal ikeProposal =
-                new IkeSaProposal.Builder()
-                        .addEncryptionAlgorithm(
-                                ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
-                        .addDhGroup(DH_GROUP_2048_BIT_MODP)
-                        .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC)
-                        .build();
-
-        final String serverHostname = "192.0.2.100";
-        final String testLocalId = "test.client.com";
-        final String testRemoteId = "test.server.com";
-        final byte[] psk = "psk".getBytes();
-
-        IKE_PARAMS =
-                new IkeSessionParams.Builder()
-                        .setServerHostname(serverHostname)
-                        .addSaProposal(ikeProposal)
-                        .setLocalIdentification(new IkeFqdnIdentification(testLocalId))
-                        .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId))
-                        .setAuthPsk(psk)
-                        .build();
-
-        ChildSaProposal childProposal =
-                new ChildSaProposal.Builder()
-                        .addEncryptionAlgorithm(
-                                ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
-                        .build();
-        CHILD_PARAMS =
-                new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build();
-    }
-
-    // Package private for use in VcnGatewayConnectionConfigTest
-    static VcnControlPlaneIkeConfig buildTestConfig() {
-        return new VcnControlPlaneIkeConfig(IKE_PARAMS, CHILD_PARAMS);
-    }
-
-    @Test
-    public void testGetters() {
-        final VcnControlPlaneIkeConfig config = buildTestConfig();
-        assertEquals(IKE_PARAMS, config.getIkeSessionParams());
-        assertEquals(CHILD_PARAMS, config.getChildSessionParams());
-    }
-
-    @Test
-    public void testPersistableBundle() {
-        final VcnControlPlaneIkeConfig config = buildTestConfig();
-
-        assertEquals(config, new VcnControlPlaneIkeConfig(config.toPersistableBundle()));
-    }
-
-    @Test
-    public void testConstructConfigWithoutIkeParams() {
-        try {
-            new VcnControlPlaneIkeConfig(null, CHILD_PARAMS);
-            fail("Expect to fail because ikeParams was null");
-        } catch (NullPointerException expected) {
-        }
-    }
-
-    @Test
-    public void testBuilderConfigWithoutChildParams() {
-        try {
-            new VcnControlPlaneIkeConfig(IKE_PARAMS, null);
-            fail("Expect to fail because childParams was null");
-        } catch (NullPointerException expected) {
-        }
-    }
-}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index db00670..0d3fd3f 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -18,11 +18,12 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.net.NetworkCapabilities;
+import android.net.TunnelConnectionParams;
+import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -59,8 +60,8 @@
             };
     public static final int MAX_MTU = 1360;
 
-    public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG =
-            VcnControlPlaneIkeConfigTest.buildTestConfig();
+    public static final TunnelConnectionParams TUNNEL_CONNECTION_PARAMS =
+            TunnelConnectionParamsUtilsTest.buildTestParams();
 
     public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
     private static int sGatewayConnectionConfigCount = 0;
@@ -75,7 +76,7 @@
         // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
         return new VcnGatewayConnectionConfig.Builder(
                 GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++,
-                CONTROL_PLANE_CONFIG);
+                TUNNEL_CONNECTION_PARAMS);
     }
 
     // Public for use in VcnGatewayConnectionTest
@@ -98,7 +99,7 @@
     public void testBuilderRequiresNonNullGatewayConnectionName() {
         try {
             new VcnGatewayConnectionConfig.Builder(
-                            null /* gatewayConnectionName */, CONTROL_PLANE_CONFIG)
+                            null /* gatewayConnectionName */, TUNNEL_CONNECTION_PARAMS)
                     .build();
 
             fail("Expected exception due to invalid gateway connection name");
@@ -107,13 +108,13 @@
     }
 
     @Test
-    public void testBuilderRequiresNonNullControlPlaneConfig() {
+    public void testBuilderRequiresNonNullTunnelConnectionParams() {
         try {
             new VcnGatewayConnectionConfig.Builder(
-                            GATEWAY_CONNECTION_NAME_PREFIX, null /* ctrlPlaneConfig */)
+                            GATEWAY_CONNECTION_NAME_PREFIX, null /* tunnelConnectionParams */)
                     .build();
 
-            fail("Expected exception due to invalid control plane config");
+            fail("Expected exception due to the absence of tunnel connection parameters");
         } catch (NullPointerException e) {
         }
     }
@@ -171,8 +172,7 @@
         Arrays.sort(underlyingCaps);
         assertArrayEquals(UNDERLYING_CAPS, underlyingCaps);
 
-        assertEquals(CONTROL_PLANE_CONFIG, config.getControlPlaneConfig());
-        assertFalse(CONTROL_PLANE_CONFIG == config.getControlPlaneConfig());
+        assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams());
 
         assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs());
         assertEquals(MAX_MTU, config.getMaxMtu());
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
index 4226e64..393787f 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
@@ -52,7 +52,8 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class IkeSessionParamsUtilsTest {
-    private static IkeSessionParams.Builder createBuilderMinimum() {
+    // Package private for use in EncryptedTunnelParamsUtilsTest
+    static IkeSessionParams.Builder createBuilderMinimum() {
         final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100");
 
         // TODO: b/185941731 Make sure all valid IKE_OPTIONS are added and validated.
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java
new file mode 100644
index 0000000..0c8ad32
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunnelConnectionParamsUtilsTest {
+    // Public for use in VcnGatewayConnectionConfigTest
+    public static IkeTunnelConnectionParams buildTestParams() {
+        return new IkeTunnelConnectionParams(
+                IkeSessionParamsUtilsTest.createBuilderMinimum().build(),
+                TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build());
+    }
+
+    @Test
+    public void testIkeTunnelConnectionParamsToFromPersistableBundle() {
+        final IkeTunnelConnectionParams params = buildTestParams();
+
+        assertEquals(
+                params,
+                TunnelConnectionParamsUtils.fromPersistableBundle(
+                        TunnelConnectionParamsUtils.toPersistableBundle(params)));
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
index b3cd0ab..e0b5f0e 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
@@ -40,7 +40,8 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class TunnelModeChildSessionParamsUtilsTest {
-    private TunnelModeChildSessionParams.Builder createBuilderMinimum() {
+    // Package private for use in EncryptedTunnelParamsUtilsTest
+    static TunnelModeChildSessionParams.Builder createBuilderMinimum() {
         final ChildSaProposal saProposal = SaProposalUtilsTest.buildTestChildSaProposal();
         return new TunnelModeChildSessionParams.Builder().addSaProposal(saProposal);
     }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 95a9726..530e636 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -51,10 +51,10 @@
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
 import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
 import android.net.ipsec.ike.exceptions.IkeException;
 import android.net.ipsec.ike.exceptions.IkeInternalException;
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.net.vcn.VcnControlPlaneIkeConfig;
 import android.net.vcn.VcnManager.VcnErrorCode;
 
 import androidx.test.filters.SmallTest;
@@ -181,8 +181,8 @@
         assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
 
         final List<ChildSaProposal> saProposals =
-                ((VcnControlPlaneIkeConfig) mConfig.getControlPlaneConfig())
-                        .getChildSessionParams()
+                ((IkeTunnelConnectionParams) mConfig.getTunnelConnectionParams())
+                        .getTunnelModeChildSessionParams()
                         .getSaProposals();
         final int expectedMtu =
                 MtuUtils.getMtu(