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