1 /* 2 * Copyright (C) 2021 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 17 package android.net.vcn.persistablebundleutils; 18 19 import static android.system.OsConstants.AF_INET; 20 import static android.system.OsConstants.AF_INET6; 21 22 import static com.android.internal.annotations.VisibleForTesting.Visibility; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.net.InetAddresses; 27 import android.net.eap.EapSessionConfig; 28 import android.net.ipsec.ike.IkeSaProposal; 29 import android.net.ipsec.ike.IkeSessionParams; 30 import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer; 31 import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer; 32 import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; 33 import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; 34 import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; 35 import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; 36 import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; 37 import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; 38 import android.os.PersistableBundle; 39 import android.util.ArraySet; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.server.vcn.util.PersistableBundleUtils; 43 44 import java.net.InetAddress; 45 import java.security.PrivateKey; 46 import java.security.cert.CertificateEncodingException; 47 import java.security.cert.X509Certificate; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.List; 51 import java.util.Objects; 52 import java.util.Set; 53 54 /** 55 * Abstract utility class to convert IkeSessionParams to/from PersistableBundle. 56 * 57 * @hide 58 */ 59 @VisibleForTesting(visibility = Visibility.PRIVATE) 60 public final class IkeSessionParamsUtils { 61 private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY"; 62 private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; 63 private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY"; 64 private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY"; 65 private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY"; 66 private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY"; 67 private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY"; 68 private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY"; 69 private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; 70 private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; 71 private static final String DPD_DELAY_SEC_KEY = "DPD_DELAY_SEC_KEY"; 72 private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; 73 private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY"; 74 75 private static final Set<Integer> IKE_OPTIONS = new ArraySet<>(); 76 77 static { 78 IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID); 79 IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH); 80 IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); 81 IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); 82 } 83 84 /** Serializes an IkeSessionParams to a PersistableBundle. */ 85 @NonNull toPersistableBundle(@onNull IkeSessionParams params)86 public static PersistableBundle toPersistableBundle(@NonNull IkeSessionParams params) { 87 if (params.getNetwork() != null || params.getIke3gppExtension() != null) { 88 throw new IllegalStateException( 89 "Cannot convert a IkeSessionParams with a caller configured network or with" 90 + " 3GPP extension enabled"); 91 } 92 93 final PersistableBundle result = new PersistableBundle(); 94 95 result.putString(SERVER_HOST_NAME_KEY, params.getServerHostname()); 96 97 final PersistableBundle saProposalBundle = 98 PersistableBundleUtils.fromList( 99 params.getSaProposals(), IkeSaProposalUtils::toPersistableBundle); 100 result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle); 101 102 result.putPersistableBundle( 103 LOCAL_ID_KEY, 104 IkeIdentificationUtils.toPersistableBundle(params.getLocalIdentification())); 105 result.putPersistableBundle( 106 REMOTE_ID_KEY, 107 IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification())); 108 109 result.putPersistableBundle( 110 LOCAL_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getLocalAuthConfig())); 111 result.putPersistableBundle( 112 REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig())); 113 114 final List<ConfigRequest> reqList = new ArrayList<>(); 115 for (IkeConfigRequest req : params.getConfigurationRequests()) { 116 reqList.add(new ConfigRequest(req)); 117 } 118 final PersistableBundle configReqListBundle = 119 PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle); 120 result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle); 121 122 result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis()); 123 result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); 124 result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); 125 result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); 126 result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); 127 128 // TODO: b/185941731 Make sure IkeSessionParamsUtils is automatically updated when a new 129 // IKE_OPTION is defined in IKE module and added in the IkeSessionParams 130 final List<Integer> enabledIkeOptions = new ArrayList<>(); 131 for (int option : IKE_OPTIONS) { 132 if (params.hasIkeOption(option)) { 133 enabledIkeOptions.add(option); 134 } 135 } 136 137 final int[] optionArray = enabledIkeOptions.stream().mapToInt(i -> i).toArray(); 138 result.putIntArray(IKE_OPTIONS_KEY, optionArray); 139 140 return result; 141 } 142 143 /** Constructs an IkeSessionParams by deserializing a PersistableBundle. */ 144 @NonNull fromPersistableBundle(@onNull PersistableBundle in)145 public static IkeSessionParams fromPersistableBundle(@NonNull PersistableBundle in) { 146 Objects.requireNonNull(in, "PersistableBundle is null"); 147 148 final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(); 149 150 builder.setServerHostname(in.getString(SERVER_HOST_NAME_KEY)); 151 152 PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY); 153 Objects.requireNonNull(in, "SA Proposals was null"); 154 List<IkeSaProposal> saProposals = 155 PersistableBundleUtils.toList( 156 proposalBundle, IkeSaProposalUtils::fromPersistableBundle); 157 for (IkeSaProposal proposal : saProposals) { 158 builder.addSaProposal(proposal); 159 } 160 161 builder.setLocalIdentification( 162 IkeIdentificationUtils.fromPersistableBundle( 163 in.getPersistableBundle(LOCAL_ID_KEY))); 164 builder.setRemoteIdentification( 165 IkeIdentificationUtils.fromPersistableBundle( 166 in.getPersistableBundle(REMOTE_ID_KEY))); 167 168 AuthConfigUtils.setBuilderByReadingPersistableBundle( 169 in.getPersistableBundle(LOCAL_AUTH_KEY), 170 in.getPersistableBundle(REMOTE_AUTH_KEY), 171 builder); 172 173 builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY)); 174 builder.setLifetimeSeconds( 175 in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); 176 builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY)); 177 builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY)); 178 179 final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY); 180 Objects.requireNonNull(configReqListBundle, "Config request list was null"); 181 final List<ConfigRequest> reqList = 182 PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new); 183 for (ConfigRequest req : reqList) { 184 switch (req.type) { 185 case ConfigRequest.IPV4_P_CSCF_ADDRESS: 186 if (req.address == null) { 187 builder.addPcscfServerRequest(AF_INET); 188 } else { 189 builder.addPcscfServerRequest(req.address); 190 } 191 break; 192 case ConfigRequest.IPV6_P_CSCF_ADDRESS: 193 if (req.address == null) { 194 builder.addPcscfServerRequest(AF_INET6); 195 } else { 196 builder.addPcscfServerRequest(req.address); 197 } 198 break; 199 default: 200 throw new IllegalArgumentException( 201 "Unrecognized config request type: " + req.type); 202 } 203 } 204 205 // Clear IKE Options that are by default enabled 206 for (int option : IKE_OPTIONS) { 207 builder.removeIkeOption(option); 208 } 209 210 final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY); 211 for (int option : optionArray) { 212 builder.addIkeOption(option); 213 } 214 215 return builder.build(); 216 } 217 218 private static final class AuthConfigUtils { 219 private static final int IKE_AUTH_METHOD_PSK = 1; 220 private static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2; 221 private static final int IKE_AUTH_METHOD_EAP = 3; 222 223 private static final String AUTH_METHOD_KEY = "AUTH_METHOD_KEY"; 224 225 @NonNull toPersistableBundle(@onNull IkeAuthConfig authConfig)226 public static PersistableBundle toPersistableBundle(@NonNull IkeAuthConfig authConfig) { 227 if (authConfig instanceof IkeAuthPskConfig) { 228 IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig; 229 return IkeAuthPskConfigUtils.toPersistableBundle( 230 config, createPersistableBundle(IKE_AUTH_METHOD_PSK)); 231 } else if (authConfig instanceof IkeAuthDigitalSignLocalConfig) { 232 IkeAuthDigitalSignLocalConfig config = (IkeAuthDigitalSignLocalConfig) authConfig; 233 return IkeAuthDigitalSignConfigUtils.toPersistableBundle( 234 config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE)); 235 } else if (authConfig instanceof IkeAuthDigitalSignRemoteConfig) { 236 IkeAuthDigitalSignRemoteConfig config = (IkeAuthDigitalSignRemoteConfig) authConfig; 237 return IkeAuthDigitalSignConfigUtils.toPersistableBundle( 238 config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE)); 239 } else if (authConfig instanceof IkeAuthEapConfig) { 240 IkeAuthEapConfig config = (IkeAuthEapConfig) authConfig; 241 return IkeAuthEapConfigUtils.toPersistableBundle( 242 config, createPersistableBundle(IKE_AUTH_METHOD_EAP)); 243 } else { 244 throw new IllegalStateException("Invalid IkeAuthConfig subclass"); 245 } 246 } 247 createPersistableBundle(int type)248 private static PersistableBundle createPersistableBundle(int type) { 249 final PersistableBundle result = new PersistableBundle(); 250 result.putInt(AUTH_METHOD_KEY, type); 251 return result; 252 } 253 setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)254 public static void setBuilderByReadingPersistableBundle( 255 @NonNull PersistableBundle localAuthBundle, 256 @NonNull PersistableBundle remoteAuthBundle, 257 @NonNull IkeSessionParams.Builder builder) { 258 Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); 259 Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); 260 261 final int localMethodType = localAuthBundle.getInt(AUTH_METHOD_KEY); 262 final int remoteMethodType = remoteAuthBundle.getInt(AUTH_METHOD_KEY); 263 switch (localMethodType) { 264 case IKE_AUTH_METHOD_PSK: 265 if (remoteMethodType != IKE_AUTH_METHOD_PSK) { 266 throw new IllegalArgumentException( 267 "Expect remote auth method to be PSK based, but was " 268 + remoteMethodType); 269 } 270 IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle( 271 localAuthBundle, remoteAuthBundle, builder); 272 return; 273 case IKE_AUTH_METHOD_PUB_KEY_SIGNATURE: 274 if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) { 275 throw new IllegalArgumentException( 276 "Expect remote auth method to be digital signature based, but was " 277 + remoteMethodType); 278 } 279 IkeAuthDigitalSignConfigUtils.setBuilderByReadingPersistableBundle( 280 localAuthBundle, remoteAuthBundle, builder); 281 return; 282 case IKE_AUTH_METHOD_EAP: 283 if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) { 284 throw new IllegalArgumentException( 285 "When using EAP for local authentication, expect remote auth" 286 + " method to be digital signature based, but was " 287 + remoteMethodType); 288 } 289 IkeAuthEapConfigUtils.setBuilderByReadingPersistableBundle( 290 localAuthBundle, remoteAuthBundle, builder); 291 return; 292 default: 293 throw new IllegalArgumentException( 294 "Invalid EAP method type " + localMethodType); 295 } 296 } 297 } 298 299 private static final class IkeAuthPskConfigUtils { 300 private static final String PSK_KEY = "PSK_KEY"; 301 302 @NonNull toPersistableBundle( @onNull IkeAuthPskConfig config, @NonNull PersistableBundle result)303 public static PersistableBundle toPersistableBundle( 304 @NonNull IkeAuthPskConfig config, @NonNull PersistableBundle result) { 305 result.putPersistableBundle( 306 PSK_KEY, PersistableBundleUtils.fromByteArray(config.getPsk())); 307 return result; 308 } 309 setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)310 public static void setBuilderByReadingPersistableBundle( 311 @NonNull PersistableBundle localAuthBundle, 312 @NonNull PersistableBundle remoteAuthBundle, 313 @NonNull IkeSessionParams.Builder builder) { 314 Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); 315 Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); 316 317 final PersistableBundle localPskBundle = localAuthBundle.getPersistableBundle(PSK_KEY); 318 final PersistableBundle remotePskBundle = 319 remoteAuthBundle.getPersistableBundle(PSK_KEY); 320 Objects.requireNonNull(localAuthBundle, "Local PSK was null"); 321 Objects.requireNonNull(remoteAuthBundle, "Remote PSK was null"); 322 323 final byte[] localPsk = PersistableBundleUtils.toByteArray(localPskBundle); 324 final byte[] remotePsk = PersistableBundleUtils.toByteArray(remotePskBundle); 325 if (!Arrays.equals(localPsk, remotePsk)) { 326 throw new IllegalArgumentException("Local PSK and remote PSK are different"); 327 } 328 builder.setAuthPsk(localPsk); 329 } 330 } 331 332 private static class IkeAuthDigitalSignConfigUtils { 333 private static final String END_CERT_KEY = "END_CERT_KEY"; 334 private static final String INTERMEDIATE_CERTS_KEY = "INTERMEDIATE_CERTS_KEY"; 335 private static final String PRIVATE_KEY_KEY = "PRIVATE_KEY_KEY"; 336 private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY"; 337 338 @NonNull toPersistableBundle( @onNull IkeAuthDigitalSignLocalConfig config, @NonNull PersistableBundle result)339 public static PersistableBundle toPersistableBundle( 340 @NonNull IkeAuthDigitalSignLocalConfig config, @NonNull PersistableBundle result) { 341 try { 342 result.putPersistableBundle( 343 END_CERT_KEY, 344 PersistableBundleUtils.fromByteArray( 345 config.getClientEndCertificate().getEncoded())); 346 347 final List<X509Certificate> certList = config.getIntermediateCertificates(); 348 final List<byte[]> encodedCertList = new ArrayList<>(certList.size()); 349 for (X509Certificate cert : certList) { 350 encodedCertList.add(cert.getEncoded()); 351 } 352 353 final PersistableBundle certsBundle = 354 PersistableBundleUtils.fromList( 355 encodedCertList, PersistableBundleUtils::fromByteArray); 356 result.putPersistableBundle(INTERMEDIATE_CERTS_KEY, certsBundle); 357 } catch (CertificateEncodingException e) { 358 throw new IllegalArgumentException("Fail to encode certificate"); 359 } 360 361 // TODO: b/170670506 Consider putting PrivateKey in Android KeyStore 362 result.putPersistableBundle( 363 PRIVATE_KEY_KEY, 364 PersistableBundleUtils.fromByteArray(config.getPrivateKey().getEncoded())); 365 return result; 366 } 367 368 @NonNull toPersistableBundle( @onNull IkeAuthDigitalSignRemoteConfig config, @NonNull PersistableBundle result)369 public static PersistableBundle toPersistableBundle( 370 @NonNull IkeAuthDigitalSignRemoteConfig config, @NonNull PersistableBundle result) { 371 try { 372 X509Certificate caCert = config.getRemoteCaCert(); 373 if (caCert != null) { 374 result.putPersistableBundle( 375 TRUST_CERT_KEY, 376 PersistableBundleUtils.fromByteArray(caCert.getEncoded())); 377 } 378 } catch (CertificateEncodingException e) { 379 throw new IllegalArgumentException("Fail to encode the certificate"); 380 } 381 382 return result; 383 } 384 setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)385 public static void setBuilderByReadingPersistableBundle( 386 @NonNull PersistableBundle localAuthBundle, 387 @NonNull PersistableBundle remoteAuthBundle, 388 @NonNull IkeSessionParams.Builder builder) { 389 Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); 390 Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); 391 392 // Deserialize localAuth 393 final PersistableBundle endCertBundle = 394 localAuthBundle.getPersistableBundle(END_CERT_KEY); 395 Objects.requireNonNull(endCertBundle, "End cert was null"); 396 final byte[] encodedCert = PersistableBundleUtils.toByteArray(endCertBundle); 397 final X509Certificate endCert = CertUtils.certificateFromByteArray(encodedCert); 398 399 final PersistableBundle certsBundle = 400 localAuthBundle.getPersistableBundle(INTERMEDIATE_CERTS_KEY); 401 Objects.requireNonNull(certsBundle, "Intermediate certs was null"); 402 final List<byte[]> encodedCertList = 403 PersistableBundleUtils.toList(certsBundle, PersistableBundleUtils::toByteArray); 404 final List<X509Certificate> certList = new ArrayList<>(encodedCertList.size()); 405 for (byte[] encoded : encodedCertList) { 406 certList.add(CertUtils.certificateFromByteArray(encoded)); 407 } 408 409 final PersistableBundle privateKeyBundle = 410 localAuthBundle.getPersistableBundle(PRIVATE_KEY_KEY); 411 Objects.requireNonNull(privateKeyBundle, "PrivateKey bundle was null"); 412 final PrivateKey privateKey = 413 CertUtils.privateKeyFromByteArray( 414 PersistableBundleUtils.toByteArray(privateKeyBundle)); 415 416 // Deserialize remoteAuth 417 final PersistableBundle trustCertBundle = 418 remoteAuthBundle.getPersistableBundle(TRUST_CERT_KEY); 419 420 X509Certificate caCert = null; 421 if (trustCertBundle != null) { 422 final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle); 423 caCert = CertUtils.certificateFromByteArray(encodedCaCert); 424 } 425 426 builder.setAuthDigitalSignature(caCert, endCert, certList, privateKey); 427 } 428 } 429 430 private static final class IkeAuthEapConfigUtils { 431 private static final String EAP_CONFIG_KEY = "EAP_CONFIG_KEY"; 432 433 @NonNull toPersistableBundle( @onNull IkeAuthEapConfig config, @NonNull PersistableBundle result)434 public static PersistableBundle toPersistableBundle( 435 @NonNull IkeAuthEapConfig config, @NonNull PersistableBundle result) { 436 result.putPersistableBundle( 437 EAP_CONFIG_KEY, 438 EapSessionConfigUtils.toPersistableBundle(config.getEapConfig())); 439 return result; 440 } 441 setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)442 public static void setBuilderByReadingPersistableBundle( 443 @NonNull PersistableBundle localAuthBundle, 444 @NonNull PersistableBundle remoteAuthBundle, 445 @NonNull IkeSessionParams.Builder builder) { 446 // Deserialize localAuth 447 final PersistableBundle eapBundle = 448 localAuthBundle.getPersistableBundle(EAP_CONFIG_KEY); 449 Objects.requireNonNull(eapBundle, "EAP Config was null"); 450 final EapSessionConfig eapConfig = 451 EapSessionConfigUtils.fromPersistableBundle(eapBundle); 452 453 // Deserialize remoteAuth 454 final PersistableBundle trustCertBundle = 455 remoteAuthBundle.getPersistableBundle( 456 IkeAuthDigitalSignConfigUtils.TRUST_CERT_KEY); 457 458 X509Certificate serverCaCert = null; 459 if (trustCertBundle != null) { 460 final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle); 461 serverCaCert = CertUtils.certificateFromByteArray(encodedCaCert); 462 } 463 builder.setAuthEap(serverCaCert, eapConfig); 464 } 465 } 466 467 private static final class ConfigRequest { 468 private static final int IPV4_P_CSCF_ADDRESS = 1; 469 private static final int IPV6_P_CSCF_ADDRESS = 2; 470 471 private static final String TYPE_KEY = "type"; 472 private static final String ADDRESS_KEY = "address"; 473 474 public final int type; 475 476 // Null when it is an empty request 477 @Nullable public final InetAddress address; 478 ConfigRequest(IkeConfigRequest config)479 ConfigRequest(IkeConfigRequest config) { 480 if (config instanceof ConfigRequestIpv4PcscfServer) { 481 type = IPV4_P_CSCF_ADDRESS; 482 address = ((ConfigRequestIpv4PcscfServer) config).getAddress(); 483 } else if (config instanceof ConfigRequestIpv6PcscfServer) { 484 type = IPV6_P_CSCF_ADDRESS; 485 address = ((ConfigRequestIpv6PcscfServer) config).getAddress(); 486 } else { 487 throw new IllegalStateException("Unknown TunnelModeChildConfigRequest"); 488 } 489 } 490 ConfigRequest(PersistableBundle in)491 ConfigRequest(PersistableBundle in) { 492 Objects.requireNonNull(in, "PersistableBundle was null"); 493 494 type = in.getInt(TYPE_KEY); 495 496 String addressStr = in.getString(ADDRESS_KEY); 497 if (addressStr == null) { 498 address = null; 499 } else { 500 address = InetAddresses.parseNumericAddress(addressStr); 501 } 502 } 503 504 @NonNull toPersistableBundle()505 public PersistableBundle toPersistableBundle() { 506 final PersistableBundle result = new PersistableBundle(); 507 508 result.putInt(TYPE_KEY, type); 509 if (address != null) { 510 result.putString(ADDRESS_KEY, address.getHostAddress()); 511 } 512 513 return result; 514 } 515 } 516 } 517