1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.net.vcn; 17 18 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; 19 import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; 20 import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; 21 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; 22 23 import static com.android.internal.annotations.VisibleForTesting.Visibility; 24 25 import android.annotation.FlaggedApi; 26 import android.annotation.IntDef; 27 import android.annotation.IntRange; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.annotation.SuppressLint; 31 import android.net.Network; 32 import android.net.NetworkCapabilities; 33 import android.net.ipsec.ike.IkeTunnelConnectionParams; 34 import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils; 35 import android.net.vcn.util.PersistableBundleUtils; 36 import android.os.PersistableBundle; 37 import android.util.ArraySet; 38 39 import com.android.internal.annotations.VisibleForTesting; 40 import com.android.internal.util.Preconditions; 41 42 import java.lang.annotation.Retention; 43 import java.lang.annotation.RetentionPolicy; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.Collections; 47 import java.util.List; 48 import java.util.Objects; 49 import java.util.Set; 50 import java.util.SortedSet; 51 import java.util.TreeSet; 52 import java.util.concurrent.TimeUnit; 53 54 /** 55 * This class represents a configuration for a connection to a Virtual Carrier Network gateway. 56 * 57 * <p>Each VcnGatewayConnectionConfig represents a single logical connection to a carrier gateway, 58 * and may provide one or more telephony services (as represented by network capabilities). Each 59 * gateway is expected to provide mobility for a given session as the device roams across {@link 60 * Network}s. 61 * 62 * <p>A VCN connection based on this configuration will be brought up dynamically based on device 63 * settings, and filed NetworkRequests. Underlying Networks must provide INTERNET connectivity, and 64 * must be part of the subscription group under which this configuration is registered (see {@link 65 * VcnManager#setVcnConfig}). 66 * 67 * <p>As an abstraction of a cellular network, services that can be provided by a VCN network are 68 * limited to services provided by cellular networks: 69 * 70 * <ul> 71 * <li>{@link NetworkCapabilities#NET_CAPABILITY_MMS} 72 * <li>{@link NetworkCapabilities#NET_CAPABILITY_SUPL} 73 * <li>{@link NetworkCapabilities#NET_CAPABILITY_DUN} 74 * <li>{@link NetworkCapabilities#NET_CAPABILITY_FOTA} 75 * <li>{@link NetworkCapabilities#NET_CAPABILITY_IMS} 76 * <li>{@link NetworkCapabilities#NET_CAPABILITY_CBS} 77 * <li>{@link NetworkCapabilities#NET_CAPABILITY_IA} 78 * <li>{@link NetworkCapabilities#NET_CAPABILITY_RCS} 79 * <li>{@link NetworkCapabilities#NET_CAPABILITY_XCAP} 80 * <li>{@link NetworkCapabilities#NET_CAPABILITY_EIMS} 81 * <li>{@link NetworkCapabilities#NET_CAPABILITY_INTERNET} 82 * <li>{@link NetworkCapabilities#NET_CAPABILITY_MCX} 83 * </ul> 84 */ 85 public final class VcnGatewayConnectionConfig { 86 /** 87 * Minimum NAT timeout not set. 88 * 89 * <p>When the timeout is not set, the device will automatically choose a keepalive interval and 90 * may reduce the keepalive frequency for power-optimization. 91 */ 92 @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) 93 // This constant does not represent a minimum value. It indicates the value is not configured. 94 @SuppressLint("MinMaxConstant") 95 public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; 96 97 /** @hide */ 98 public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS = 120; 99 100 // TODO: Use MIN_MTU_V6 once it is public, @hide 101 @VisibleForTesting(visibility = Visibility.PRIVATE) 102 static final int MIN_MTU_V6 = 1280; 103 104 /** 105 * The set of allowed capabilities for exposed capabilities. 106 * 107 * @hide 108 */ 109 public static final Set<Integer> ALLOWED_CAPABILITIES; 110 111 static { 112 Set<Integer> allowedCaps = new ArraySet<>(); 113 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS); 114 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL); 115 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN); 116 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA); 117 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS); 118 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS); 119 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA); 120 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS); 121 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP); 122 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS); 123 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET); 124 allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX); 125 126 ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps); 127 } 128 129 /** @hide */ 130 @Retention(RetentionPolicy.SOURCE) 131 @IntDef( 132 prefix = {"NET_CAPABILITY_"}, 133 value = { 134 NetworkCapabilities.NET_CAPABILITY_MMS, 135 NetworkCapabilities.NET_CAPABILITY_SUPL, 136 NetworkCapabilities.NET_CAPABILITY_DUN, 137 NetworkCapabilities.NET_CAPABILITY_FOTA, 138 NetworkCapabilities.NET_CAPABILITY_IMS, 139 NetworkCapabilities.NET_CAPABILITY_CBS, 140 NetworkCapabilities.NET_CAPABILITY_IA, 141 NetworkCapabilities.NET_CAPABILITY_RCS, 142 NetworkCapabilities.NET_CAPABILITY_XCAP, 143 NetworkCapabilities.NET_CAPABILITY_EIMS, 144 NetworkCapabilities.NET_CAPABILITY_INTERNET, 145 NetworkCapabilities.NET_CAPABILITY_MCX, 146 }) 147 public @interface VcnSupportedCapability {} 148 149 /** 150 * Perform mobility update to attempt recovery from suspected data stalls. 151 * 152 * <p>If set, the gateway connection will monitor the data stall detection of the VCN network. 153 * When there is a suspected data stall, the gateway connection will attempt recovery by 154 * performing a mobility update on the underlying IKE session. 155 */ 156 public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; 157 158 /** @hide */ 159 @Retention(RetentionPolicy.SOURCE) 160 @IntDef( 161 prefix = {"VCN_GATEWAY_OPTION_"}, 162 value = { 163 VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY, 164 }) 165 public @interface VcnGatewayOption {} 166 167 private static final Set<Integer> ALLOWED_GATEWAY_OPTIONS = new ArraySet<>(); 168 169 static { 170 ALLOWED_GATEWAY_OPTIONS.add(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY); 171 } 172 173 private static final int DEFAULT_MAX_MTU = 1500; 174 175 /** 176 * The maximum number of retry intervals that may be specified. 177 * 178 * <p>Limited to ensure an upper bound on config sizes. 179 */ 180 private static final int MAX_RETRY_INTERVAL_COUNT = 10; 181 182 /** 183 * The minimum allowable repeating retry interval 184 * 185 * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater 186 * than this value. 187 * 188 * @see {@link Builder#setRetryIntervalsMillis()} 189 */ 190 private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); 191 192 private static final long[] DEFAULT_RETRY_INTERVALS_MS = 193 new long[] { 194 TimeUnit.SECONDS.toMillis(1), 195 TimeUnit.SECONDS.toMillis(2), 196 TimeUnit.SECONDS.toMillis(5), 197 TimeUnit.SECONDS.toMillis(30), 198 TimeUnit.MINUTES.toMillis(1), 199 TimeUnit.MINUTES.toMillis(5), 200 TimeUnit.MINUTES.toMillis(15) 201 }; 202 203 /** @hide */ 204 @VisibleForTesting(visibility = Visibility.PRIVATE) 205 public static final List<VcnUnderlyingNetworkTemplate> DEFAULT_UNDERLYING_NETWORK_TEMPLATES = 206 new ArrayList<>(); 207 208 static { DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .setOpportunistic(MATCH_REQUIRED) .build())209 DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( 210 new VcnCellUnderlyingNetworkTemplate.Builder() 211 .setOpportunistic(MATCH_REQUIRED) 212 .build()); 213 DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnWifiUnderlyingNetworkTemplate.Builder() .build())214 DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( 215 new VcnWifiUnderlyingNetworkTemplate.Builder() 216 .build()); 217 DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .build())218 DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( 219 new VcnCellUnderlyingNetworkTemplate.Builder() 220 .build()); 221 } 222 223 private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName"; 224 @NonNull private final String mGatewayConnectionName; 225 226 private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams"; 227 @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams; 228 229 private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; 230 @NonNull private final SortedSet<Integer> mExposedCapabilities; 231 232 /** @hide */ 233 @VisibleForTesting(visibility = Visibility.PRIVATE) 234 public static final String UNDERLYING_NETWORK_TEMPLATES_KEY = "mUnderlyingNetworkTemplates"; 235 236 @NonNull private final List<VcnUnderlyingNetworkTemplate> mUnderlyingNetworkTemplates; 237 238 private static final String MAX_MTU_KEY = "mMaxMtu"; 239 private final int mMaxMtu; 240 241 private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; 242 @NonNull private final long[] mRetryIntervalsMs; 243 244 private static final String MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY = 245 "mMinUdpPort4500NatTimeoutSeconds"; 246 private final int mMinUdpPort4500NatTimeoutSeconds; 247 248 private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled"; 249 private final boolean mIsSafeModeDisabled; 250 251 private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions"; 252 @NonNull private final Set<Integer> mGatewayOptions; 253 254 /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ VcnGatewayConnectionConfig( @onNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set<Integer> exposedCapabilities, @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu, @NonNull int minUdpPort4500NatTimeoutSeconds, boolean isSafeModeDisabled, @NonNull Set<Integer> gatewayOptions)255 private VcnGatewayConnectionConfig( 256 @NonNull String gatewayConnectionName, 257 @NonNull IkeTunnelConnectionParams tunnelConnectionParams, 258 @NonNull Set<Integer> exposedCapabilities, 259 @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, 260 @NonNull long[] retryIntervalsMs, 261 @IntRange(from = MIN_MTU_V6) int maxMtu, 262 @NonNull int minUdpPort4500NatTimeoutSeconds, 263 boolean isSafeModeDisabled, 264 @NonNull Set<Integer> gatewayOptions) { 265 mGatewayConnectionName = gatewayConnectionName; 266 mTunnelConnectionParams = tunnelConnectionParams; 267 mExposedCapabilities = new TreeSet(exposedCapabilities); 268 mRetryIntervalsMs = retryIntervalsMs; 269 mMaxMtu = maxMtu; 270 mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; 271 mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions)); 272 mIsSafeModeDisabled = isSafeModeDisabled; 273 274 mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); 275 if (mUnderlyingNetworkTemplates.isEmpty()) { 276 mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); 277 } 278 279 validate(); 280 } 281 282 // Null check MUST be done for all new fields added to VcnGatewayConnectionConfig, to avoid 283 // crashes when parsing PersistableBundle built on old platforms. 284 /** @hide */ 285 @VisibleForTesting(visibility = Visibility.PRIVATE) VcnGatewayConnectionConfig(@onNull PersistableBundle in)286 public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) { 287 final PersistableBundle tunnelConnectionParamsBundle = 288 in.getPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY); 289 Objects.requireNonNull( 290 tunnelConnectionParamsBundle, "tunnelConnectionParamsBundle was null"); 291 292 final PersistableBundle exposedCapsBundle = 293 in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); 294 mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); 295 mTunnelConnectionParams = 296 TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); 297 mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( 298 exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); 299 300 final PersistableBundle networkTemplatesBundle = 301 in.getPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY); 302 303 if (networkTemplatesBundle == null) { 304 // UNDERLYING_NETWORK_TEMPLATES_KEY was added in Android T. Thus 305 // VcnGatewayConnectionConfig created on old platforms will not have this data and will 306 // be assigned with the default value 307 mUnderlyingNetworkTemplates = new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); 308 } else { 309 mUnderlyingNetworkTemplates = 310 PersistableBundleUtils.toList( 311 networkTemplatesBundle, 312 VcnUnderlyingNetworkTemplate::fromPersistableBundle); 313 } 314 315 final PersistableBundle gatewayOptionsBundle = in.getPersistableBundle(GATEWAY_OPTIONS_KEY); 316 317 if (gatewayOptionsBundle == null) { 318 // GATEWAY_OPTIONS_KEY was added in Android U. Thus VcnGatewayConnectionConfig created 319 // on old platforms will not have this data and will be assigned with the default value 320 mGatewayOptions = Collections.emptySet(); 321 } else { 322 mGatewayOptions = 323 new ArraySet<>( 324 PersistableBundleUtils.toList( 325 gatewayOptionsBundle, 326 PersistableBundleUtils.INTEGER_DESERIALIZER)); 327 } 328 329 mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); 330 mMaxMtu = in.getInt(MAX_MTU_KEY); 331 mMinUdpPort4500NatTimeoutSeconds = 332 in.getInt( 333 MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, 334 MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); 335 mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY); 336 337 validate(); 338 } 339 validate()340 private void validate() { 341 Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null"); 342 Objects.requireNonNull(mTunnelConnectionParams, "tunnel connection parameter was null"); 343 344 Preconditions.checkArgument( 345 mExposedCapabilities != null && !mExposedCapabilities.isEmpty(), 346 "exposedCapsBundle was null or empty"); 347 for (Integer cap : getAllExposedCapabilities()) { 348 checkValidCapability(cap); 349 } 350 351 validateNetworkTemplateList(mUnderlyingNetworkTemplates); 352 Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null"); 353 validateRetryInterval(mRetryIntervalsMs); 354 355 Preconditions.checkArgument( 356 mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); 357 358 Preconditions.checkArgument( 359 mMinUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET 360 || mMinUdpPort4500NatTimeoutSeconds 361 >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, 362 "minUdpPort4500NatTimeoutSeconds must be at least 120s"); 363 364 for (int option : mGatewayOptions) { 365 validateGatewayOption(option); 366 } 367 } 368 checkValidCapability(int capability)369 private static void checkValidCapability(int capability) { 370 Preconditions.checkArgument( 371 ALLOWED_CAPABILITIES.contains(capability), 372 "NetworkCapability " + capability + "out of range"); 373 } 374 validateRetryInterval(@ullable long[] retryIntervalsMs)375 private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) { 376 Preconditions.checkArgument( 377 retryIntervalsMs != null 378 && retryIntervalsMs.length > 0 379 && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT, 380 "retryIntervalsMs was null, empty or exceed max interval count"); 381 382 final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1]; 383 if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) { 384 throw new IllegalArgumentException( 385 "Repeating retry interval was too short, must be a minimum of 15 minutes: " 386 + repeatingInterval); 387 } 388 } 389 validateNetworkTemplateList( List<VcnUnderlyingNetworkTemplate> networkPriorityRules)390 private static void validateNetworkTemplateList( 391 List<VcnUnderlyingNetworkTemplate> networkPriorityRules) { 392 Objects.requireNonNull(networkPriorityRules, "networkPriorityRules is null"); 393 394 Set<VcnUnderlyingNetworkTemplate> existingRules = new ArraySet<>(); 395 for (VcnUnderlyingNetworkTemplate rule : networkPriorityRules) { 396 Objects.requireNonNull(rule, "Found null value VcnUnderlyingNetworkTemplate"); 397 if (!existingRules.add(rule)) { 398 throw new IllegalArgumentException("Found duplicate VcnUnderlyingNetworkTemplate"); 399 } 400 } 401 } 402 validateGatewayOption(int option)403 private static void validateGatewayOption(int option) { 404 if (!ALLOWED_GATEWAY_OPTIONS.contains(option)) { 405 throw new IllegalArgumentException("Invalid vcn gateway option: " + option); 406 } 407 } 408 409 /** 410 * Returns the configured Gateway Connection name. 411 * 412 * <p>This name is used by the configuring apps to distinguish between 413 * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as 414 * the identifier in VcnStatusCallback invocations. 415 * 416 * @see VcnManager.VcnStatusCallback#onGatewayConnectionError 417 */ 418 @NonNull getGatewayConnectionName()419 public String getGatewayConnectionName() { 420 return mGatewayConnectionName; 421 } 422 423 /** 424 * Returns tunnel connection parameters. 425 * 426 * @hide 427 */ 428 @NonNull getTunnelConnectionParams()429 public IkeTunnelConnectionParams getTunnelConnectionParams() { 430 return mTunnelConnectionParams; 431 } 432 433 /** 434 * Returns all exposed capabilities. 435 * 436 * <p>The returned integer-value capabilities will not contain duplicates, and will be sorted in 437 * ascending numerical order. 438 * 439 * @see Builder#addExposedCapability(int) 440 * @see Builder#removeExposedCapability(int) 441 */ 442 @NonNull getExposedCapabilities()443 public int[] getExposedCapabilities() { 444 // Sorted set guarantees ordering 445 final int[] caps = new int[mExposedCapabilities.size()]; 446 447 int i = 0; 448 for (int c : mExposedCapabilities) { 449 caps[i++] = c; 450 } 451 452 return caps; 453 } 454 455 /** 456 * Returns all exposed capabilities. 457 * 458 * <p>Left to prevent the need to make major changes while changes are actively in flight. 459 * 460 * @deprecated use getExposedCapabilities() instead 461 * @hide 462 */ 463 @Deprecated 464 @NonNull getAllExposedCapabilities()465 public Set<Integer> getAllExposedCapabilities() { 466 return Collections.unmodifiableSet(mExposedCapabilities); 467 } 468 469 /** 470 * Retrieve the VcnUnderlyingNetworkTemplate list, or a default list if it is not configured. 471 * 472 * @see Builder#setVcnUnderlyingNetworkPriorities(List) 473 */ 474 @NonNull getVcnUnderlyingNetworkPriorities()475 public List<VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities() { 476 return new ArrayList<>(mUnderlyingNetworkTemplates); 477 } 478 479 /** 480 * Retrieves the configured retry intervals. 481 * 482 * @see Builder#setRetryIntervalsMillis(long[]) 483 */ 484 @NonNull getRetryIntervalsMillis()485 public long[] getRetryIntervalsMillis() { 486 return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); 487 } 488 489 /** 490 * Retrieves the maximum MTU allowed for this Gateway Connection. 491 * 492 * @see Builder#setMaxMtu(int) 493 */ 494 @IntRange(from = MIN_MTU_V6) getMaxMtu()495 public int getMaxMtu() { 496 return mMaxMtu; 497 } 498 499 /** 500 * Retrieves the maximum supported IKEv2/IPsec NATT keepalive timeout. 501 * 502 * @see Builder#setMinUdpPort4500NatTimeoutSeconds(int) 503 */ getMinUdpPort4500NatTimeoutSeconds()504 public int getMinUdpPort4500NatTimeoutSeconds() { 505 return mMinUdpPort4500NatTimeoutSeconds; 506 } 507 508 /** 509 * Check whether safe mode is enabled 510 * 511 * @see Builder#setSafeModeEnabled(boolean) 512 */ 513 @FlaggedApi(FLAG_SAFE_MODE_CONFIG) isSafeModeEnabled()514 public boolean isSafeModeEnabled() { 515 return !mIsSafeModeDisabled; 516 } 517 518 /** 519 * Checks if the given VCN gateway option is enabled. 520 * 521 * @param option the option to check. 522 * @throws IllegalArgumentException if the provided option is invalid. 523 * @see Builder#addGatewayOption(int) 524 * @see Builder#removeGatewayOption(int) 525 */ hasGatewayOption(@cnGatewayOption int option)526 public boolean hasGatewayOption(@VcnGatewayOption int option) { 527 validateGatewayOption(option); 528 return mGatewayOptions.contains(option); 529 } 530 531 /** 532 * Converts this config to a PersistableBundle. 533 * 534 * @hide 535 */ 536 @NonNull 537 @VisibleForTesting(visibility = Visibility.PROTECTED) toPersistableBundle()538 public PersistableBundle toPersistableBundle() { 539 final PersistableBundle result = new PersistableBundle(); 540 541 final PersistableBundle tunnelConnectionParamsBundle = 542 TunnelConnectionParamsUtils.toPersistableBundle(mTunnelConnectionParams); 543 final PersistableBundle exposedCapsBundle = 544 PersistableBundleUtils.fromList( 545 new ArrayList<>(mExposedCapabilities), 546 PersistableBundleUtils.INTEGER_SERIALIZER); 547 final PersistableBundle networkTemplatesBundle = 548 PersistableBundleUtils.fromList( 549 mUnderlyingNetworkTemplates, 550 VcnUnderlyingNetworkTemplate::toPersistableBundle); 551 final PersistableBundle gatewayOptionsBundle = 552 PersistableBundleUtils.fromList( 553 new ArrayList<>(mGatewayOptions), 554 PersistableBundleUtils.INTEGER_SERIALIZER); 555 556 result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); 557 result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); 558 result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); 559 result.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, networkTemplatesBundle); 560 result.putPersistableBundle(GATEWAY_OPTIONS_KEY, gatewayOptionsBundle); 561 result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); 562 result.putInt(MAX_MTU_KEY, mMaxMtu); 563 result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds); 564 result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled); 565 566 return result; 567 } 568 569 @Override hashCode()570 public int hashCode() { 571 return Objects.hash( 572 mGatewayConnectionName, 573 mTunnelConnectionParams, 574 mExposedCapabilities, 575 mUnderlyingNetworkTemplates, 576 Arrays.hashCode(mRetryIntervalsMs), 577 mMaxMtu, 578 mMinUdpPort4500NatTimeoutSeconds, 579 mIsSafeModeDisabled, 580 mGatewayOptions); 581 } 582 583 @Override equals(@ullable Object other)584 public boolean equals(@Nullable Object other) { 585 if (!(other instanceof VcnGatewayConnectionConfig)) { 586 return false; 587 } 588 589 final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; 590 return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) 591 && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams) 592 && mExposedCapabilities.equals(rhs.mExposedCapabilities) 593 && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates) 594 && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) 595 && mMaxMtu == rhs.mMaxMtu 596 && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds 597 && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled 598 && mGatewayOptions.equals(rhs.mGatewayOptions); 599 } 600 601 /** 602 * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. 603 */ 604 public static final class Builder { 605 @NonNull private final String mGatewayConnectionName; 606 @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; 607 @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet(); 608 609 @NonNull 610 private final List<VcnUnderlyingNetworkTemplate> mUnderlyingNetworkTemplates = 611 new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); 612 613 @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; 614 private int mMaxMtu = DEFAULT_MAX_MTU; 615 private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; 616 private boolean mIsSafeModeDisabled = false; 617 618 @NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>(); 619 620 // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent. 621 // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS 622 // when on Cell. 623 624 /** 625 * Construct a Builder object. 626 * 627 * @param gatewayConnectionName the String GatewayConnection name for this 628 * VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link 629 * VcnConfig} must be given a unique name. This name is used by the caller to 630 * distinguish between VcnGatewayConnectionConfigs configured on a single {@link 631 * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. 632 * @param tunnelConnectionParams the IKE tunnel connection configuration 633 * @throws IllegalArgumentException if the provided IkeTunnelConnectionParams is not 634 * configured to support MOBIKE 635 * @see IkeTunnelConnectionParams 636 * @see VcnManager.VcnStatusCallback#onGatewayConnectionError 637 */ Builder( @onNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams)638 public Builder( 639 @NonNull String gatewayConnectionName, 640 @NonNull IkeTunnelConnectionParams tunnelConnectionParams) { 641 Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); 642 Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null"); 643 if (!tunnelConnectionParams.getIkeSessionParams().hasIkeOption(IKE_OPTION_MOBIKE)) { 644 throw new IllegalArgumentException( 645 "MOBIKE must be configured for the provided IkeSessionParams"); 646 } 647 648 mGatewayConnectionName = gatewayConnectionName; 649 mTunnelConnectionParams = tunnelConnectionParams; 650 } 651 652 /** 653 * Add a capability that this VCN Gateway Connection will support. 654 * 655 * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway 656 * Connection (i.e., the capabilities that this VCN Gateway Connection will support). 657 * @return this {@link Builder} instance, for chaining 658 * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway 659 * Connection 660 */ 661 @NonNull addExposedCapability(@cnSupportedCapability int exposedCapability)662 public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) { 663 checkValidCapability(exposedCapability); 664 665 mExposedCapabilities.add(exposedCapability); 666 return this; 667 } 668 669 /** 670 * Remove a capability that this VCN Gateway Connection will support. 671 * 672 * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway 673 * Connection (i.e., the capabilities that this VCN Gateway Connection will support) 674 * @return this {@link Builder} instance, for chaining 675 * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway 676 * Connection 677 */ 678 @NonNull 679 @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap removeExposedCapability(@cnSupportedCapability int exposedCapability)680 public Builder removeExposedCapability(@VcnSupportedCapability int exposedCapability) { 681 checkValidCapability(exposedCapability); 682 683 mExposedCapabilities.remove(exposedCapability); 684 return this; 685 } 686 687 /** 688 * Set the list of templates to match underlying networks against, in high-to-low priority 689 * order. 690 * 691 * <p>To select the VCN underlying network, the VCN connection will go through all the 692 * network candidates and return a network matching the highest priority rule. 693 * 694 * <p>If multiple networks match the same rule, the VCN will prefer an already-selected 695 * network as opposed to a new/unselected network. However, if both are new/unselected 696 * networks, a network will be chosen arbitrarily amongst the networks matching the highest 697 * priority rule. 698 * 699 * <p>If all networks fail to match the rules provided, a carrier-owned underlying network 700 * will still be selected (if available, at random if necessary). 701 * 702 * @param underlyingNetworkTemplates a list of unique VcnUnderlyingNetworkTemplates that are 703 * ordered from most to least preferred, or an empty list to use the default 704 * prioritization. The default network prioritization order is Opportunistic cellular, 705 * Carrier WiFi and then Macro cellular. 706 * @return this {@link Builder} instance, for chaining 707 */ 708 @NonNull setVcnUnderlyingNetworkPriorities( @onNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates)709 public Builder setVcnUnderlyingNetworkPriorities( 710 @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates) { 711 validateNetworkTemplateList(underlyingNetworkTemplates); 712 713 mUnderlyingNetworkTemplates.clear(); 714 715 if (underlyingNetworkTemplates.isEmpty()) { 716 mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); 717 } else { 718 mUnderlyingNetworkTemplates.addAll(underlyingNetworkTemplates); 719 } 720 721 return this; 722 } 723 724 /** 725 * Set the retry interval between VCN establishment attempts upon successive failures. 726 * 727 * <p>The last retry interval will be repeated until safe mode is entered, or a connection 728 * is successfully established, at which point the retry timers will be reset. For power 729 * reasons, the last (repeated) retry interval MUST be at least 15 minutes. 730 * 731 * <p>Retry intervals MAY be subject to system power saving modes. That is to say that if 732 * the system enters a power saving mode, the retry may not occur until the device leaves 733 * the specified power saving mode. Intervals are sequential, and intervals will NOT be 734 * skipped if system power saving results in delaying retries (even if it exceed multiple 735 * retry intervals). 736 * 737 * <p>Each Gateway Connection will retry according to the retry intervals configured, but if 738 * safe mode is enabled, all Gateway Connection(s) will be disabled. 739 * 740 * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which 741 * the VCN will attempt to retry a session initiation. The last (repeating) retry 742 * interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m, 743 * 15m]} 744 * @return this {@link Builder} instance, for chaining 745 * @see VcnManager for additional discussion on fail-safe mode 746 */ 747 @NonNull setRetryIntervalsMillis(@onNull long[] retryIntervalsMs)748 public Builder setRetryIntervalsMillis(@NonNull long[] retryIntervalsMs) { 749 validateRetryInterval(retryIntervalsMs); 750 751 mRetryIntervalsMs = retryIntervalsMs; 752 return this; 753 } 754 755 /** 756 * Sets the maximum MTU allowed for this VCN Gateway Connection. 757 * 758 * <p>This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the 759 * MTU of the virtualized network. 760 * 761 * <p>The system may reduce the MTU below the maximum specified based on signals such as the 762 * MTU of the underlying networks (and adjusted for Gateway Connection overhead). 763 * 764 * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than 765 * the IPv6 minimum MTU of 1280. Defaults to 1500. 766 * @return this {@link Builder} instance, for chaining 767 */ 768 @NonNull setMaxMtu(@ntRangefrom = MIN_MTU_V6) int maxMtu)769 public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) { 770 Preconditions.checkArgument( 771 maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); 772 773 mMaxMtu = maxMtu; 774 return this; 775 } 776 777 /** 778 * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. 779 * 780 * <p>This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, 781 * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. 782 * 783 * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN 784 * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN 785 * Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value. 786 * @return this {@link Builder} instance, for chaining 787 */ 788 @NonNull setMinUdpPort4500NatTimeoutSeconds( @ntRangefrom = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds)789 public Builder setMinUdpPort4500NatTimeoutSeconds( 790 @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) 791 int minUdpPort4500NatTimeoutSeconds) { 792 if (Flags.mainlineVcnModuleApi()) { 793 Preconditions.checkArgument( 794 minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET 795 || minUdpPort4500NatTimeoutSeconds 796 >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, 797 "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); 798 } else { 799 Preconditions.checkArgument( 800 minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, 801 "Timeout must be at least 120s"); 802 } 803 804 mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; 805 return this; 806 } 807 808 /** 809 * Enables the specified VCN gateway option. 810 * 811 * @param option the option to be enabled 812 * @return this {@link Builder} instance, for chaining 813 * @throws IllegalArgumentException if the provided option is invalid 814 */ 815 @NonNull addGatewayOption(@cnGatewayOption int option)816 public Builder addGatewayOption(@VcnGatewayOption int option) { 817 validateGatewayOption(option); 818 mGatewayOptions.add(option); 819 return this; 820 } 821 822 /** 823 * Resets (disables) the specified VCN gateway option. 824 * 825 * @param option the option to be disabled 826 * @return this {@link Builder} instance, for chaining 827 * @throws IllegalArgumentException if the provided option is invalid 828 */ 829 @NonNull removeGatewayOption(@cnGatewayOption int option)830 public Builder removeGatewayOption(@VcnGatewayOption int option) { 831 validateGatewayOption(option); 832 mGatewayOptions.remove(option); 833 return this; 834 } 835 836 /** 837 * Enable/disable safe mode 838 * 839 * <p>If a VCN fails to provide connectivity within a system-provided timeout, it will enter 840 * safe mode. In safe mode, the VCN Network will be torn down and the system will restore 841 * connectivity by allowing underlying cellular or WiFi networks to be used as default. At 842 * the same time, VCN will continue to retry until it succeeds. 843 * 844 * <p>When safe mode is disabled and VCN connection fails to provide connectivity, end users 845 * might not have connectivity, and may not have access to carrier-owned underlying 846 * networks. 847 * 848 * @param enabled whether safe mode should be enabled. Defaults to {@code true} 849 */ 850 @FlaggedApi(FLAG_SAFE_MODE_CONFIG) 851 @NonNull setSafeModeEnabled(boolean enabled)852 public Builder setSafeModeEnabled(boolean enabled) { 853 mIsSafeModeDisabled = !enabled; 854 return this; 855 } 856 857 /** 858 * Builds and validates the VcnGatewayConnectionConfig. 859 * 860 * @return an immutable VcnGatewayConnectionConfig instance 861 */ 862 @NonNull build()863 public VcnGatewayConnectionConfig build() { 864 return new VcnGatewayConnectionConfig( 865 mGatewayConnectionName, 866 mTunnelConnectionParams, 867 mExposedCapabilities, 868 mUnderlyingNetworkTemplates, 869 mRetryIntervalsMs, 870 mMaxMtu, 871 mMinUdpPort4500NatTimeoutSeconds, 872 mIsSafeModeDisabled, 873 mGatewayOptions); 874 } 875 } 876 } 877