• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 
17 package com.google.android.iwlan.epdg;
18 
19 import static android.net.ipsec.ike.ike3gpp.Ike3gppData.DATA_TYPE_NOTIFY_BACKOFF_TIMER;
20 import static android.net.ipsec.ike.ike3gpp.Ike3gppData.DATA_TYPE_NOTIFY_N1_MODE_INFORMATION;
21 import static android.net.ipsec.ike.ike3gpp.Ike3gppParams.PDU_SESSION_ID_UNSET;
22 import static android.system.OsConstants.AF_INET;
23 import static android.system.OsConstants.AF_INET6;
24 import static android.telephony.PreciseDataConnectionState.NetworkValidationStatus;
25 
26 import static com.google.android.iwlan.proto.MetricsAtom.*;
27 
28 import android.content.Context;
29 import android.net.ConnectivityDiagnosticsManager;
30 import android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
31 import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
32 import android.net.ConnectivityManager;
33 import android.net.InetAddresses;
34 import android.net.IpPrefix;
35 import android.net.IpSecManager;
36 import android.net.IpSecTransform;
37 import android.net.LinkAddress;
38 import android.net.LinkProperties;
39 import android.net.Network;
40 import android.net.NetworkCapabilities;
41 import android.net.NetworkRequest;
42 import android.net.eap.EapAkaInfo;
43 import android.net.eap.EapInfo;
44 import android.net.eap.EapSessionConfig;
45 import android.net.ipsec.ike.ChildSaProposal;
46 import android.net.ipsec.ike.ChildSessionCallback;
47 import android.net.ipsec.ike.ChildSessionConfiguration;
48 import android.net.ipsec.ike.ChildSessionParams;
49 import android.net.ipsec.ike.IkeFqdnIdentification;
50 import android.net.ipsec.ike.IkeIdentification;
51 import android.net.ipsec.ike.IkeKeyIdIdentification;
52 import android.net.ipsec.ike.IkeRfc822AddrIdentification;
53 import android.net.ipsec.ike.IkeSaProposal;
54 import android.net.ipsec.ike.IkeSession;
55 import android.net.ipsec.ike.IkeSessionCallback;
56 import android.net.ipsec.ike.IkeSessionConfiguration;
57 import android.net.ipsec.ike.IkeSessionConnectionInfo;
58 import android.net.ipsec.ike.IkeSessionParams;
59 import android.net.ipsec.ike.IkeTrafficSelector;
60 import android.net.ipsec.ike.SaProposal;
61 import android.net.ipsec.ike.TunnelModeChildSessionParams;
62 import android.net.ipsec.ike.exceptions.IkeException;
63 import android.net.ipsec.ike.exceptions.IkeIOException;
64 import android.net.ipsec.ike.exceptions.IkeProtocolException;
65 import android.net.ipsec.ike.ike3gpp.Ike3gppBackoffTimer;
66 import android.net.ipsec.ike.ike3gpp.Ike3gppData;
67 import android.net.ipsec.ike.ike3gpp.Ike3gppExtension;
68 import android.net.ipsec.ike.ike3gpp.Ike3gppN1ModeInformation;
69 import android.net.ipsec.ike.ike3gpp.Ike3gppParams;
70 import android.os.Handler;
71 import android.os.HandlerExecutor;
72 import android.os.HandlerThread;
73 import android.os.Looper;
74 import android.os.Message;
75 import android.support.annotation.IntDef;
76 import android.support.annotation.NonNull;
77 import android.support.annotation.Nullable;
78 import android.telephony.CarrierConfigManager;
79 import android.telephony.PreciseDataConnectionState;
80 import android.telephony.SubscriptionManager;
81 import android.telephony.TelephonyManager;
82 import android.telephony.data.ApnSetting;
83 import android.telephony.data.NetworkSliceInfo;
84 import android.util.Log;
85 
86 import com.android.internal.annotations.VisibleForTesting;
87 
88 import com.google.android.iwlan.ErrorPolicyManager;
89 import com.google.android.iwlan.IwlanCarrierConfig;
90 import com.google.android.iwlan.IwlanError;
91 import com.google.android.iwlan.IwlanHelper;
92 import com.google.android.iwlan.IwlanStatsLog;
93 import com.google.android.iwlan.TunnelMetricsInterface.OnClosedMetrics;
94 import com.google.android.iwlan.TunnelMetricsInterface.OnOpenedMetrics;
95 import com.google.android.iwlan.exceptions.IwlanSimNotReadyException;
96 import com.google.android.iwlan.flags.FeatureFlags;
97 import com.google.android.iwlan.flags.FeatureFlagsImpl;
98 import com.google.android.iwlan.proto.MetricsAtom;
99 
100 import java.io.IOException;
101 import java.io.PrintWriter;
102 import java.net.Inet4Address;
103 import java.net.Inet6Address;
104 import java.net.InetAddress;
105 import java.nio.charset.StandardCharsets;
106 import java.util.ArrayDeque;
107 import java.util.ArrayList;
108 import java.util.Arrays;
109 import java.util.List;
110 import java.util.Map;
111 import java.util.Objects;
112 import java.util.Queue;
113 import java.util.Set;
114 import java.util.concurrent.ConcurrentHashMap;
115 import java.util.concurrent.Executor;
116 import java.util.concurrent.Executors;
117 import java.util.concurrent.TimeUnit;
118 
119 public class EpdgTunnelManager {
120     private final FeatureFlags mFeatureFlags;
121     private final Context mContext;
122     private final int mSlotId;
123     private Handler mHandler;
124     private ConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
125 
126     private static final int EVENT_TUNNEL_BRINGUP_REQUEST = 0;
127     private static final int EVENT_TUNNEL_BRINGDOWN_REQUEST = 1;
128     private static final int EVENT_CHILD_SESSION_OPENED = 2;
129     private static final int EVENT_CHILD_SESSION_CLOSED = 3;
130     private static final int EVENT_IKE_SESSION_CLOSED = 5;
131     private static final int EVENT_EPDG_ADDRESS_SELECTION_REQUEST_COMPLETE = 6;
132     private static final int EVENT_IPSEC_TRANSFORM_CREATED = 7;
133     private static final int EVENT_IPSEC_TRANSFORM_DELETED = 8;
134     private static final int EVENT_UPDATE_NETWORK = 9;
135     private static final int EVENT_IKE_SESSION_OPENED = 10;
136     private static final int EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED = 11;
137     private static final int EVENT_IKE_3GPP_DATA_RECEIVED = 12;
138     private static final int EVENT_IKE_LIVENESS_STATUS_CHANGED = 13;
139     private static final int EVENT_REQUEST_NETWORK_VALIDATION_CHECK = 14;
140     private static final int IKE_HARD_LIFETIME_SEC_MINIMUM = 300;
141     private static final int IKE_HARD_LIFETIME_SEC_MAXIMUM = 86400;
142     private static final int IKE_SOFT_LIFETIME_SEC_MINIMUM = 120;
143     private static final int CHILD_HARD_LIFETIME_SEC_MINIMUM = 300;
144     private static final int CHILD_HARD_LIFETIME_SEC_MAXIMUM = 14400;
145     private static final int CHILD_SOFT_LIFETIME_SEC_MINIMUM = 120;
146     private static final int LIFETIME_MARGIN_SEC_MINIMUM = (int) TimeUnit.MINUTES.toSeconds(1L);
147     private static final int IKE_RETRANS_TIMEOUT_MS_MIN = 500;
148 
149     private static final int IKE_RETRANS_TIMEOUT_MS_MAX = (int) TimeUnit.MINUTES.toMillis(30L);
150 
151     private static final int IKE_RETRANS_MAX_ATTEMPTS_MAX = 10;
152     private static final int IKE_DPD_DELAY_SEC_MIN = 20;
153     private static final int IKE_DPD_DELAY_SEC_MAX = 1800; // 30 minutes
154     private static final int NATT_KEEPALIVE_DELAY_SEC_MIN = 10;
155     private static final int NATT_KEEPALIVE_DELAY_SEC_MAX = 120;
156 
157     private static final int DEVICE_IMEI_LEN = 15;
158     private static final int DEVICE_IMEISV_SUFFIX_LEN = 2;
159 
160     private static final int TRAFFIC_SELECTOR_START_PORT = 0;
161     private static final int TRAFFIC_SELECTOR_END_PORT = 65535;
162     private static final String TRAFFIC_SELECTOR_IPV4_START_ADDR = "0.0.0.0";
163     private static final String TRAFFIC_SELECTOR_IPV4_END_ADDR = "255.255.255.255";
164     private static final String TRAFFIC_SELECTOR_IPV6_START_ADDR = "::";
165     private static final String TRAFFIC_SELECTOR_IPV6_END_ADDR =
166             "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
167 
168     private static final int NETWORK_VALIDATION_MIN_INTERVAL_MS = 10000;
169 
170     private static long sLastUnderlyingNetworkValidationMs = 0;
171     private static final Object sLastUnderlyingNetworkValidationLock = new Object();
172 
173     // "192.0.2.0" is selected from RFC5737, "IPv4 Address Blocks Reserved for Documentation"
174     private static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0");
175 
176     private static final Map<Integer, EpdgTunnelManager> mTunnelManagerInstances =
177             new ConcurrentHashMap<>();
178     private final Map<Network, MetricsAtom> mMetricsAtomForNetwork = new ConcurrentHashMap<>();
179 
180     private final Queue<TunnelRequestWrapper> mPendingBringUpRequests = new ArrayDeque<>();
181 
182     private final EpdgInfo mValidEpdgInfo = new EpdgInfo();
183 
184     // The most recently updated system default network as seen by IwlanDataService.
185     @Nullable private Network mDefaultNetwork;
186     // The latest Network provided to the IKE session. Only for debugging purposes.
187     @Nullable private Network mIkeSessionNetwork;
188 
189     private int mTransactionId = 0;
190     private boolean mHasConnectedToEpdg;
191     private final IkeSessionCreator mIkeSessionCreator;
192     private final IpSecManager mIpSecManager;
193     private final EpdgSelector mEpdgSelector;
194 
195     private final Map<String, TunnelConfig> mApnNameToTunnelConfig = new ConcurrentHashMap<>();
196     private final Map<String, IpsecTransformData> mApnNameToIpsecTransform =
197             new ConcurrentHashMap<>();
198     private final Map<String, Integer> mApnNameToCurrentToken = new ConcurrentHashMap<>();
199 
200     private final String TAG;
201 
202     @Nullable private byte[] mNextReauthId = null;
203     private long mEpdgServerSelectionDuration = 0;
204     private long mEpdgServerSelectionStartTime = 0;
205     private long mIkeTunnelEstablishmentStartTime = 0;
206 
207     private static final Set<Integer> VALID_DH_GROUPS;
208     private static final Set<Integer> VALID_KEY_LENGTHS;
209     private static final Set<Integer> VALID_PRF_ALGOS;
210     private static final Set<Integer> VALID_INTEGRITY_ALGOS;
211     private static final Set<Integer> VALID_ENCRYPTION_ALGOS;
212     private static final Set<Integer> VALID_AEAD_ALGOS;
213 
214     private static final String CONFIG_TYPE_DH_GROUP = "dh group";
215     private static final String CONFIG_TYPE_KEY_LEN = "algorithm key length";
216     private static final String CONFIG_TYPE_PRF_ALGO = "prf algorithm";
217     private static final String CONFIG_TYPE_INTEGRITY_ALGO = "integrity algorithm";
218     private static final String CONFIG_TYPE_ENCRYPT_ALGO = "encryption algorithm";
219 
220     static {
221         VALID_DH_GROUPS =
222                 Set.of(
223                         SaProposal.DH_GROUP_1024_BIT_MODP,
224                         SaProposal.DH_GROUP_1536_BIT_MODP,
225                         SaProposal.DH_GROUP_2048_BIT_MODP,
226                         SaProposal.DH_GROUP_3072_BIT_MODP,
227                         SaProposal.DH_GROUP_4096_BIT_MODP);
228         VALID_KEY_LENGTHS =
229                 Set.of(
230                         SaProposal.KEY_LEN_AES_128,
231                         SaProposal.KEY_LEN_AES_192,
232                         SaProposal.KEY_LEN_AES_256);
233 
234         VALID_ENCRYPTION_ALGOS =
235                 Set.of(
236                         SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
237                         SaProposal.ENCRYPTION_ALGORITHM_AES_CTR);
238 
239         VALID_INTEGRITY_ALGOS =
240                 Set.of(
241                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96,
242                         SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96,
243                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
244                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
245                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
246 
247         VALID_AEAD_ALGOS =
248                 Set.of(
249                         SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
250                         SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
251                         SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16);
252 
253         VALID_PRF_ALGOS =
254                 Set.of(
255                         SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1,
256                         SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC,
257                         SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256,
258                         SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384,
259                         SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512);
260     }
261 
262     @VisibleForTesting protected EpdgMonitor mEpdgMonitor = new EpdgMonitor();
263 
264     public static final int BRINGDOWN_REASON_UNKNOWN = 0;
265     public static final int BRINGDOWN_REASON_DISABLE_N1_MODE = 1;
266     public static final int BRINGDOWN_REASON_ENABLE_N1_MODE = 2;
267     public static final int BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC = 3;
268     public static final int BRINGDOWN_REASON_IN_DEACTIVATING_STATE = 4;
269     public static final int BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP = 5;
270     public static final int BRINGDOWN_REASON_DEACTIVATE_DATA_CALL = 6;
271 
272     @IntDef({
273         BRINGDOWN_REASON_UNKNOWN,
274         BRINGDOWN_REASON_DISABLE_N1_MODE,
275         BRINGDOWN_REASON_ENABLE_N1_MODE,
276         BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC,
277         BRINGDOWN_REASON_IN_DEACTIVATING_STATE,
278         BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP,
279         BRINGDOWN_REASON_DEACTIVATE_DATA_CALL,
280     })
281     public @interface TunnelBringDownReason {}
282 
bringdownReasonToString(@unnelBringDownReason int reason)283     private static String bringdownReasonToString(@TunnelBringDownReason int reason) {
284         return switch (reason) {
285             case BRINGDOWN_REASON_UNKNOWN -> "BRINGDOWN_REASON_UNKNOWN";
286             case BRINGDOWN_REASON_DISABLE_N1_MODE -> "BRINGDOWN_REASON_DISABLE_N1_MODE";
287             case BRINGDOWN_REASON_ENABLE_N1_MODE -> "BRINGDOWN_REASON_ENABLE_N1_MODE";
288             case BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC -> "BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC";
289             case BRINGDOWN_REASON_IN_DEACTIVATING_STATE -> "BRINGDOWN_REASON_IN_DEACTIVATING_STATE";
290             case BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP ->
291                     "BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP";
292             case BRINGDOWN_REASON_DEACTIVATE_DATA_CALL -> "BRINGDOWN_REASON_DEACTIVATE_DATA_CALL";
293             default -> "Unknown(" + reason + ")";
294         };
295     }
296 
297     private final EpdgSelector.EpdgSelectorCallback mSelectorCallback =
298             new EpdgSelector.EpdgSelectorCallback() {
299                 @Override
300                 public void onServerListChanged(int transactionId, List<InetAddress> validIPList) {
301                     sendSelectionRequestComplete(
302                             validIPList, new IwlanError(IwlanError.NO_ERROR), transactionId);
303                 }
304 
305                 @Override
306                 public void onError(int transactionId, IwlanError epdgSelectorError) {
307                     sendSelectionRequestComplete(null, epdgSelectorError, transactionId);
308                 }
309             };
310 
311     @VisibleForTesting
312     class TunnelConfig {
313         @NonNull final TunnelCallback mTunnelCallback;
314         // TODO: Change this to TunnelLinkProperties after removing autovalue
315         private List<InetAddress> mPcscfAddrList;
316         private List<InetAddress> mDnsAddrList;
317         private List<LinkAddress> mInternalAddrList;
318 
319         private final InetAddress mSrcIpv6Address;
320         private final int mSrcIpv6AddressPrefixLen;
321         private NetworkSliceInfo mSliceInfo;
322         private boolean mIsBackoffTimeValid = false;
323         private long mBackoffTime;
324 
325         @NonNull final IkeSession mIkeSession;
326 
327         IwlanError mError;
328         private final IpSecManager.IpSecTunnelInterface mIface;
329         private IkeSessionState mIkeSessionState;
330         private final boolean mIsEmergency;
331         private final InetAddress mEpdgAddress;
332 
TunnelConfig( IkeSession ikeSession, TunnelCallback tunnelCallback, IpSecManager.IpSecTunnelInterface iface, InetAddress srcIpv6Addr, int srcIpv6PrefixLength, boolean isEmergency, InetAddress epdgAddress)333         public TunnelConfig(
334                 IkeSession ikeSession,
335                 TunnelCallback tunnelCallback,
336                 IpSecManager.IpSecTunnelInterface iface,
337                 InetAddress srcIpv6Addr,
338                 int srcIpv6PrefixLength,
339                 boolean isEmergency,
340                 InetAddress epdgAddress) {
341             mTunnelCallback = tunnelCallback;
342             mIkeSession = ikeSession;
343             mError = new IwlanError(IwlanError.NO_ERROR);
344             mSrcIpv6Address = srcIpv6Addr;
345             mSrcIpv6AddressPrefixLen = srcIpv6PrefixLength;
346             mIface = iface;
347             setIkeSessionState(IkeSessionState.IKE_SESSION_INIT_IN_PROGRESS);
348             mIsEmergency = isEmergency;
349             mEpdgAddress = epdgAddress;
350         }
351 
getIkeSessionState()352         public IkeSessionState getIkeSessionState() {
353             return mIkeSessionState;
354         }
355 
setIkeSessionState(IkeSessionState ikeSessionState)356         public void setIkeSessionState(IkeSessionState ikeSessionState) {
357             mIkeSessionState = ikeSessionState;
358         }
359 
getSliceInfo()360         public NetworkSliceInfo getSliceInfo() {
361             return mSliceInfo;
362         }
363 
setSliceInfo(NetworkSliceInfo si)364         public void setSliceInfo(NetworkSliceInfo si) {
365             mSliceInfo = si;
366         }
367 
isBackoffTimeValid()368         public boolean isBackoffTimeValid() {
369             return mIsBackoffTimeValid;
370         }
371 
getBackoffTime()372         public long getBackoffTime() {
373             return mBackoffTime;
374         }
375 
setBackoffTime(long backoffTime)376         public void setBackoffTime(long backoffTime) {
377             mIsBackoffTimeValid = true;
378             mBackoffTime = backoffTime;
379         }
380 
381         @NonNull
getTunnelCallback()382         TunnelCallback getTunnelCallback() {
383             return mTunnelCallback;
384         }
385 
getPcscfAddrList()386         List<InetAddress> getPcscfAddrList() {
387             return mPcscfAddrList;
388         }
389 
setPcscfAddrList(List<InetAddress> pcscfAddrList)390         void setPcscfAddrList(List<InetAddress> pcscfAddrList) {
391             mPcscfAddrList = pcscfAddrList;
392         }
393 
getDnsAddrList()394         public List<InetAddress> getDnsAddrList() {
395             return mDnsAddrList;
396         }
397 
setDnsAddrList(List<InetAddress> dnsAddrList)398         public void setDnsAddrList(List<InetAddress> dnsAddrList) {
399             this.mDnsAddrList = dnsAddrList;
400         }
401 
getInternalAddrList()402         public List<LinkAddress> getInternalAddrList() {
403             return mInternalAddrList;
404         }
405 
isPrefixSameAsSrcIP(LinkAddress laddr)406         boolean isPrefixSameAsSrcIP(LinkAddress laddr) {
407             if (laddr.isIpv6() && (laddr.getPrefixLength() == mSrcIpv6AddressPrefixLen)) {
408                 IpPrefix assignedPrefix = new IpPrefix(laddr.getAddress(), laddr.getPrefixLength());
409                 IpPrefix srcPrefix = new IpPrefix(mSrcIpv6Address, mSrcIpv6AddressPrefixLen);
410                 return assignedPrefix.equals(srcPrefix);
411             }
412             return false;
413         }
414 
setInternalAddrList(List<LinkAddress> internalAddrList)415         public void setInternalAddrList(List<LinkAddress> internalAddrList) {
416             mInternalAddrList = new ArrayList<LinkAddress>(internalAddrList);
417             if (getSrcIpv6Address() != null) {
418                 // check if we can reuse src ipv6 address (i.e. if prefix is same)
419                 for (LinkAddress assignedAddr : internalAddrList) {
420                     if (isPrefixSameAsSrcIP(assignedAddr)) {
421                         // the assigned IPv6 address is same as pre-Handover IPv6
422                         // addr. Just reuse the pre-Handover Address so the IID is
423                         // preserved
424                         mInternalAddrList.remove(assignedAddr);
425 
426                         // add original address
427                         mInternalAddrList.add(
428                                 new LinkAddress(mSrcIpv6Address, mSrcIpv6AddressPrefixLen));
429 
430                         Log.d(
431                                 TAG,
432                                 "Network assigned IP replaced OLD:"
433                                         + internalAddrList
434                                         + " NEW:"
435                                         + mInternalAddrList);
436                         break;
437                     }
438                 }
439             }
440         }
441 
442         @NonNull
getIkeSession()443         public IkeSession getIkeSession() {
444             return mIkeSession;
445         }
446 
getError()447         public IwlanError getError() {
448             return mError;
449         }
450 
setError(IwlanError error)451         public void setError(IwlanError error) {
452             this.mError = error;
453         }
454 
getIface()455         public IpSecManager.IpSecTunnelInterface getIface() {
456             return mIface;
457         }
458 
getSrcIpv6Address()459         public InetAddress getSrcIpv6Address() {
460             return mSrcIpv6Address;
461         }
462 
isEmergency()463         public boolean isEmergency() {
464             return mIsEmergency;
465         }
466 
getEpdgAddress()467         public InetAddress getEpdgAddress() {
468             return mEpdgAddress;
469         }
470 
hasTunnelOpened()471         public boolean hasTunnelOpened() {
472             return mInternalAddrList != null
473                     && !mInternalAddrList.isEmpty() /* The child session is opened */
474                     && mIface != null; /* The tunnel interface is bring up */
475         }
476 
477         @Override
toString()478         public String toString() {
479             StringBuilder sb = new StringBuilder();
480             sb.append("TunnelConfig { ");
481 
482             if (mSliceInfo != null) {
483                 sb.append("mSliceInfo: ").append(mSliceInfo).append(", ");
484             }
485 
486             if (mIsBackoffTimeValid) {
487                 sb.append("mBackoffTime: ").append(mBackoffTime).append(", ");
488             }
489             sb.append(" }");
490             return sb.toString();
491         }
492     }
493 
494     @VisibleForTesting
495     class TmIkeSessionCallback implements IkeSessionCallback {
496 
497         private final String mApnName;
498         private final int mToken;
499 
TmIkeSessionCallback(String apnName, int token)500         TmIkeSessionCallback(String apnName, int token) {
501             this.mApnName = apnName;
502             this.mToken = token;
503         }
504 
505         @Override
onOpened(IkeSessionConfiguration sessionConfiguration)506         public void onOpened(IkeSessionConfiguration sessionConfiguration) {
507             if (mHandler == null) {
508                 Log.d(TAG, "Handler unavailable");
509                 return;
510             }
511             Log.d(TAG, "Ike session opened for apn: " + mApnName + " with token: " + mToken);
512             mHandler.obtainMessage(
513                             EVENT_IKE_SESSION_OPENED,
514                             new IkeSessionOpenedData(mApnName, mToken, sessionConfiguration))
515                     .sendToTarget();
516         }
517 
518         @Override
onClosed()519         public void onClosed() {
520             if (mHandler == null) {
521                 Log.d(TAG, "Handler unavailable");
522                 return;
523             }
524             Log.d(TAG, "Ike session closed for apn: " + mApnName + " with token: " + mToken);
525             mHandler.obtainMessage(
526                             EVENT_IKE_SESSION_CLOSED,
527                             new SessionClosedData(mApnName, mToken, null /* ikeException */))
528                     .sendToTarget();
529         }
530 
531         @Override
onClosedWithException(IkeException exception)532         public void onClosedWithException(IkeException exception) {
533             mNextReauthId = null;
534             onSessionClosedWithException(exception, mApnName, mToken, EVENT_IKE_SESSION_CLOSED);
535         }
536 
537         @Override
onError(IkeProtocolException exception)538         public void onError(IkeProtocolException exception) {
539             Log.d(TAG, "Ike session onError for apn: " + mApnName + " with token: " + mToken);
540 
541             mNextReauthId = null;
542 
543             Log.d(
544                     TAG,
545                     "ErrorType:"
546                             + exception.getErrorType()
547                             + " ErrorData:"
548                             + exception.getMessage());
549         }
550 
551         @Override
onIkeSessionConnectionInfoChanged( IkeSessionConnectionInfo ikeSessionConnectionInfo)552         public void onIkeSessionConnectionInfoChanged(
553                 IkeSessionConnectionInfo ikeSessionConnectionInfo) {
554             if (mHandler == null) {
555                 Log.d(TAG, "Handler unavailable");
556                 return;
557             }
558             Network network = ikeSessionConnectionInfo.getNetwork();
559             Log.d(
560                     TAG,
561                     "Ike session connection info changed for apn: "
562                             + mApnName
563                             + " with token: "
564                             + mToken
565                             + " Network: "
566                             + network);
567             mHandler.obtainMessage(
568                             EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED,
569                             new IkeSessionConnectionInfoData(
570                                     mApnName, mToken, ikeSessionConnectionInfo))
571                     .sendToTarget();
572         }
573 
574         @Override
onLivenessStatusChanged(int status)575         public void onLivenessStatusChanged(int status) {
576             if (mHandler == null) {
577                 Log.d(TAG, "Handler unavailable");
578                 return;
579             }
580             Log.d(
581                     TAG,
582                     "Ike liveness status changed for apn: " + mApnName + " with status: " + status);
583             @NetworkValidationStatus int validationStatus;
584             switch (status) {
585                 case IkeSessionCallback.LIVENESS_STATUS_ON_DEMAND_STARTED:
586                 case IkeSessionCallback.LIVENESS_STATUS_BACKGROUND_STARTED:
587                 case IkeSessionCallback.LIVENESS_STATUS_ON_DEMAND_ONGOING:
588                 case IkeSessionCallback.LIVENESS_STATUS_BACKGROUND_ONGOING:
589                     validationStatus = PreciseDataConnectionState.NETWORK_VALIDATION_IN_PROGRESS;
590                     break;
591                 case IkeSessionCallback.LIVENESS_STATUS_SUCCESS:
592                     validationStatus = PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS;
593                     break;
594                 case IkeSessionCallback.LIVENESS_STATUS_FAILURE:
595                     validationStatus = PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE;
596                     break;
597                 default:
598                     validationStatus = PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS;
599             }
600 
601             mHandler.obtainMessage(
602                             EVENT_IKE_LIVENESS_STATUS_CHANGED,
603                             new IkeSessionValidationStatusData(mApnName, mToken, validationStatus))
604                     .sendToTarget();
605         }
606     }
607 
608     @VisibleForTesting
609     class TmIke3gppCallback implements Ike3gppExtension.Ike3gppDataListener {
610         private final String mApnName;
611         private final int mToken;
612 
TmIke3gppCallback(String apnName, int token)613         private TmIke3gppCallback(String apnName, int token) {
614             mApnName = apnName;
615             mToken = token;
616         }
617 
618         @Override
onIke3gppDataReceived(List<Ike3gppData> payloads)619         public void onIke3gppDataReceived(List<Ike3gppData> payloads) {
620             if (mHandler == null) {
621                 Log.d(TAG, "Handler unavailable");
622                 return;
623             }
624             mHandler.obtainMessage(
625                             EVENT_IKE_3GPP_DATA_RECEIVED,
626                             new Ike3gppDataReceived(mApnName, mToken, payloads))
627                     .sendToTarget();
628         }
629     }
630 
631     @VisibleForTesting
632     class TmChildSessionCallback implements ChildSessionCallback {
633 
634         private final String mApnName;
635         private final int mToken;
636 
TmChildSessionCallback(String apnName, int token)637         TmChildSessionCallback(String apnName, int token) {
638             this.mApnName = apnName;
639             this.mToken = token;
640         }
641 
642         @Override
onOpened(ChildSessionConfiguration sessionConfiguration)643         public void onOpened(ChildSessionConfiguration sessionConfiguration) {
644             if (mHandler == null) {
645                 Log.d(TAG, "Handler unavailable");
646                 return;
647             }
648             Log.d(TAG, "onOpened child session for apn: " + mApnName + " with token: " + mToken);
649             mHandler.obtainMessage(
650                             EVENT_CHILD_SESSION_OPENED,
651                             new TunnelOpenedData(
652                                     mApnName,
653                                     mToken,
654                                     sessionConfiguration.getInternalDnsServers(),
655                                     sessionConfiguration.getInternalAddresses()))
656                     .sendToTarget();
657         }
658 
659         @Override
onClosed()660         public void onClosed() {
661             if (mHandler == null) {
662                 Log.d(TAG, "Handler unavailable");
663                 return;
664             }
665             Log.d(TAG, "onClosed child session for apn: " + mApnName + " with token: " + mToken);
666             mHandler.obtainMessage(
667                             EVENT_CHILD_SESSION_CLOSED,
668                             new SessionClosedData(mApnName, mToken, null /* ikeException */))
669                     .sendToTarget();
670         }
671 
672         @Override
onClosedWithException(IkeException exception)673         public void onClosedWithException(IkeException exception) {
674             onSessionClosedWithException(exception, mApnName, mToken, EVENT_CHILD_SESSION_CLOSED);
675         }
676 
677         @Override
onIpSecTransformsMigrated( IpSecTransform inIpSecTransform, IpSecTransform outIpSecTransform)678         public void onIpSecTransformsMigrated(
679                 IpSecTransform inIpSecTransform, IpSecTransform outIpSecTransform) {
680             if (mHandler == null) {
681                 Log.d(TAG, "Handler unavailable");
682                 return;
683             }
684             // migration is similar to addition
685             Log.d(TAG, "Transforms migrated for apn: " + mApnName + " with token: " + mToken);
686             mHandler.obtainMessage(
687                             EVENT_IPSEC_TRANSFORM_CREATED,
688                             new IpsecTransformData(
689                                     inIpSecTransform, IpSecManager.DIRECTION_IN, mApnName, mToken))
690                     .sendToTarget();
691             mHandler.obtainMessage(
692                             EVENT_IPSEC_TRANSFORM_CREATED,
693                             new IpsecTransformData(
694                                     outIpSecTransform,
695                                     IpSecManager.DIRECTION_OUT,
696                                     mApnName,
697                                     mToken))
698                     .sendToTarget();
699         }
700 
701         @Override
onIpSecTransformCreated(IpSecTransform ipSecTransform, int direction)702         public void onIpSecTransformCreated(IpSecTransform ipSecTransform, int direction) {
703             if (mHandler == null) {
704                 Log.d(TAG, "Handler unavailable");
705                 return;
706             }
707             Log.d(
708                     TAG,
709                     "Transform created, direction: "
710                             + direction
711                             + ", apn: "
712                             + mApnName
713                             + ", token: "
714                             + mToken);
715             mHandler.obtainMessage(
716                             EVENT_IPSEC_TRANSFORM_CREATED,
717                             new IpsecTransformData(ipSecTransform, direction, mApnName, mToken))
718                     .sendToTarget();
719         }
720 
721         @Override
onIpSecTransformDeleted(IpSecTransform ipSecTransform, int direction)722         public void onIpSecTransformDeleted(IpSecTransform ipSecTransform, int direction) {
723             if (mHandler == null) {
724                 Log.d(TAG, "Handler unavailable");
725                 return;
726             }
727             Log.d(
728                     TAG,
729                     "Transform deleted, direction: "
730                             + direction
731                             + ", apn: "
732                             + mApnName
733                             + ", token: "
734                             + mToken);
735             mHandler.obtainMessage(
736                             EVENT_IPSEC_TRANSFORM_DELETED,
737                             new IpsecTransformData(ipSecTransform, direction, mApnName, mToken))
738                     .sendToTarget();
739         }
740     }
741 
EpdgTunnelManager(Context context, int slotId, FeatureFlags featureFlags)742     private EpdgTunnelManager(Context context, int slotId, FeatureFlags featureFlags) {
743         this(
744                 context,
745                 slotId,
746                 featureFlags,
747                 new IkeSessionCreator(),
748                 new EpdgSelector(context, slotId, featureFlags));
749     }
750 
751     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
EpdgTunnelManager( Context context, int slotIndex, FeatureFlags featureFlags, IkeSessionCreator ikeSessionCreator, EpdgSelector epdgSelector)752     EpdgTunnelManager(
753             Context context,
754             int slotIndex,
755             FeatureFlags featureFlags,
756             IkeSessionCreator ikeSessionCreator,
757             EpdgSelector epdgSelector) {
758         mContext = context;
759         mSlotId = slotIndex;
760         mFeatureFlags = featureFlags;
761         mIkeSessionCreator = ikeSessionCreator;
762         mIpSecManager = mContext.getSystemService(IpSecManager.class);
763         // Adding this here is necessary because we need to initialize EpdgSelector at the beginning
764         // to ensure no broadcasts are missed.
765         mEpdgSelector = epdgSelector;
766         TAG = EpdgTunnelManager.class.getSimpleName() + "[" + mSlotId + "]";
767         initHandler();
768         registerConnectivityDiagnosticsCallback();
769     }
770 
registerConnectivityDiagnosticsCallback()771     private void registerConnectivityDiagnosticsCallback() {
772         ConnectivityDiagnosticsManager connectivityDiagnosticsManager =
773                 Objects.requireNonNull(mContext)
774                         .getSystemService(ConnectivityDiagnosticsManager.class);
775         NetworkRequest networkRequest =
776                 new NetworkRequest.Builder()
777                         .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
778                         .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
779                         .build();
780         mConnectivityDiagnosticsCallback =
781                 new ConnectivityDiagnosticsCallback() {
782                     @Override
783                     public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {
784                         Network network = report.getNetwork();
785                         int mNetworkValidationResult =
786                                 report.getAdditionalInfo()
787                                         .getInt(ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT);
788                         if (!mMetricsAtomForNetwork.containsKey(network)) {
789                             return;
790                         }
791                         reportValidationMetricsAtom(
792                                 network,
793                                 getMetricsValidationResult(mNetworkValidationResult),
794                                 /* validationTriggered */ true);
795                     }
796                 };
797         connectivityDiagnosticsManager.registerConnectivityDiagnosticsCallback(
798                 networkRequest, new HandlerExecutor(mHandler), mConnectivityDiagnosticsCallback);
799     }
800 
reportValidationMetricsAtom( @onNull Network network, int validationResult, boolean validationTriggered)801     private void reportValidationMetricsAtom(
802             @NonNull Network network, int validationResult, boolean validationTriggered) {
803         if (!mMetricsAtomForNetwork.containsKey(network)) {
804             return;
805         }
806         MetricsAtom metricsAtom = mMetricsAtomForNetwork.get(network);
807         metricsAtom.setValidationResult(validationResult);
808         metricsAtom.setValidationTriggered(validationTriggered);
809         metricsAtom.setValidationDurationMills(
810                 validationTriggered
811                         ? (int)
812                                 (IwlanHelper.elapsedRealtime()
813                                         - metricsAtom.getValidationStartTimeMills())
814                         : 0);
815         Log.d(
816                 TAG,
817                 "reportValidationMetricsAtom: reason="
818                         + metricsAtom.getTriggerReason()
819                         + " validationResult="
820                         + metricsAtom.getValidationResult()
821                         + " transportType="
822                         + metricsAtom.getValidationTransportType()
823                         + " duration="
824                         + metricsAtom.getValidationDurationMills()
825                         + " validationTriggered="
826                         + metricsAtom.getValidationTriggered());
827         metricsAtom.sendMetricsData();
828         mMetricsAtomForNetwork.remove(network);
829     }
830 
831     @VisibleForTesting
getValidationMetricsAtom(Network network)832     MetricsAtom getValidationMetricsAtom(Network network) {
833         return mMetricsAtomForNetwork.get(network);
834     }
835 
unregisterConnectivityDiagnosticsCallback()836     private void unregisterConnectivityDiagnosticsCallback() {
837         ConnectivityDiagnosticsManager connectivityDiagnosticsManager =
838                 Objects.requireNonNull(mContext)
839                         .getSystemService(ConnectivityDiagnosticsManager.class);
840         if (connectivityDiagnosticsManager != null) {
841             connectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback(
842                     mConnectivityDiagnosticsCallback);
843         }
844     }
845 
846     @VisibleForTesting
initHandler()847     void initHandler() {
848         mHandler = new TmHandler(getLooper());
849     }
850 
851     @VisibleForTesting
getLooper()852     Looper getLooper() {
853         HandlerThread handlerThread = new HandlerThread("EpdgTunnelManagerThread");
854         handlerThread.start();
855         return handlerThread.getLooper();
856     }
857 
858     /**
859      * Gets a EpdgTunnelManager instance.
860      *
861      * @param context the context at which EpdgTunnelManager instance to be created
862      * @param slotId the slot index at which EpdgTunnelManager instance to be created
863      * @return EpdgTunnelManager instance for the specified slot id
864      */
getInstance(@onNull Context context, int slotId)865     public static EpdgTunnelManager getInstance(@NonNull Context context, int slotId) {
866         return mTunnelManagerInstances.computeIfAbsent(
867                 slotId, k -> new EpdgTunnelManager(context, slotId, new FeatureFlagsImpl()));
868     }
869 
870     @VisibleForTesting
resetAllInstances()871     public static void resetAllInstances() {
872         mTunnelManagerInstances.clear();
873         sLastUnderlyingNetworkValidationMs = 0;
874     }
875 
reset()876     private void reset() {
877         if (mHandler != null) {
878             mHandler.getLooper().quit();
879             mHandler = null;
880         }
881 
882         mApnNameToTunnelConfig.forEach(
883                 (apn, config) -> {
884                     config.getIkeSession().kill();
885                     IpSecManager.IpSecTunnelInterface iface = config.getIface();
886                     if (iface != null) {
887                         iface.close();
888                     }
889                     IpsecTransformData transformData = mApnNameToIpsecTransform.get(apn);
890                     if (transformData != null) {
891                         transformData.getTransform().close();
892                         mApnNameToIpsecTransform.remove(apn);
893                     }
894                 });
895 
896         mApnNameToTunnelConfig.clear();
897     }
898 
deinit()899     public static void deinit() {
900         mTunnelManagerInstances.values().forEach(EpdgTunnelManager::reset);
901     }
902 
903     public interface TunnelCallback {
904         /**
905          * Called when the tunnel is opened.
906          *
907          * @param apnName apn for which the tunnel was opened
908          * @param linkProperties link properties of the tunnel
909          * @param onOpenedMetrics metrics for the tunnel
910          */
onOpened( @onNull String apnName, @NonNull TunnelLinkProperties linkProperties, OnOpenedMetrics onOpenedMetrics)911         void onOpened(
912                 @NonNull String apnName,
913                 @NonNull TunnelLinkProperties linkProperties,
914                 OnOpenedMetrics onOpenedMetrics);
915 
916         /**
917          * Called when the tunnel is closed OR if bring up fails
918          *
919          * @param apnName apn for which the tunnel was closed
920          * @param error IwlanError carrying details of the error
921          * @param onClosedMetrics metrics for the tunnel
922          */
onClosed( @onNull String apnName, @NonNull IwlanError error, OnClosedMetrics onClosedMetrics)923         void onClosed(
924                 @NonNull String apnName,
925                 @NonNull IwlanError error,
926                 OnClosedMetrics onClosedMetrics);
927 
928         /**
929          * Called when updates upon network validation status change.
930          *
931          * @param apnName APN affected.
932          * @param status The updated validation status of the network.
933          */
onNetworkValidationStatusChanged( @onNull String apnName, @NetworkValidationStatus int status)934         void onNetworkValidationStatusChanged(
935                 @NonNull String apnName, @NetworkValidationStatus int status);
936     }
937 
938     /**
939      * Close tunnel for an apn. Confirmation of closing will be delivered in TunnelCallback that was
940      * provided in {@link #bringUpTunnel}. If no tunnel was available, callback will be delivered
941      * using client-provided provided tunnelCallback and iwlanTunnelMetrics
942      *
943      * @param apnName APN name
944      * @param forceClose if {@code true}, triggers a local cleanup of the tunnel; if {@code false},
945      *     performs a normal closure procedure
946      * @param tunnelCallback The tunnelCallback for tunnel to be closed
947      * @param reason The reason for tunnel to be closed
948      */
closeTunnel( @onNull String apnName, boolean forceClose, @NonNull TunnelCallback tunnelCallback, @TunnelBringDownReason int reason)949     public void closeTunnel(
950             @NonNull String apnName,
951             boolean forceClose,
952             @NonNull TunnelCallback tunnelCallback,
953             @TunnelBringDownReason int reason) {
954         mHandler.obtainMessage(
955                         EVENT_TUNNEL_BRINGDOWN_REQUEST,
956                         new TunnelBringdownRequest(apnName, forceClose, tunnelCallback, reason))
957                 .sendToTarget();
958     }
959 
960     /**
961      * Update the local Network. This will trigger a revaluation for every tunnel for which tunnel
962      * manager has state.
963      *
964      * @param network the network to be updated
965      * @param linkProperties the linkProperties to be updated
966      */
updateNetwork(Network network, LinkProperties linkProperties)967     public void updateNetwork(Network network, LinkProperties linkProperties) {
968         UpdateNetworkWrapper updateNetworkWrapper =
969                 new UpdateNetworkWrapper(network, linkProperties);
970         mHandler.obtainMessage(EVENT_UPDATE_NETWORK, updateNetworkWrapper).sendToTarget();
971     }
972 
973     /**
974      * Bring up epdg tunnel. Only one bring up request per apn is expected. All active tunnel
975      * requests and tunnels are expected to be on the same network.
976      *
977      * @param setupRequest {@link TunnelSetupRequest} tunnel configurations
978      * @param tunnelCallback {@link TunnelCallback} interface to notify clients about the tunnel
979      *     state
980      * @return true if params are valid and no existing tunnel. False otherwise.
981      */
bringUpTunnel( @onNull TunnelSetupRequest setupRequest, @NonNull TunnelCallback tunnelCallback)982     public boolean bringUpTunnel(
983             @NonNull TunnelSetupRequest setupRequest, @NonNull TunnelCallback tunnelCallback) {
984         String apnName = setupRequest.apnName();
985 
986         if (getTunnelSetupRequestApnName(setupRequest) == null) {
987             Log.e(TAG, "APN is null.");
988             return false;
989         }
990 
991         if (isTunnelConfigContainExistApn(apnName)) {
992             Log.e(TAG, "Tunnel exists for apn:" + apnName);
993             return false;
994         }
995 
996         if (!isValidApnProtocol(setupRequest.apnIpProtocol())) {
997             Log.e(TAG, "Invalid protocol for APN");
998             return false;
999         }
1000 
1001         int pduSessionId = setupRequest.pduSessionId();
1002         if (pduSessionId < 0 || pduSessionId > 15) {
1003             Log.e(TAG, "Invalid pduSessionId: " + pduSessionId);
1004             return false;
1005         }
1006 
1007         TunnelRequestWrapper tunnelRequestWrapper =
1008                 new TunnelRequestWrapper(setupRequest, tunnelCallback);
1009 
1010         mHandler.obtainMessage(EVENT_TUNNEL_BRINGUP_REQUEST, tunnelRequestWrapper).sendToTarget();
1011 
1012         return true;
1013     }
1014 
tryBuildIkeSessionParams( TunnelSetupRequest setupRequest, String apnName, int token, InetAddress epdgAddress)1015     private IkeSessionParams tryBuildIkeSessionParams(
1016             TunnelSetupRequest setupRequest, String apnName, int token, InetAddress epdgAddress) {
1017         try {
1018             return buildIkeSessionParams(setupRequest, apnName, token, epdgAddress);
1019         } catch (IwlanSimNotReadyException e) {
1020             return null;
1021         }
1022     }
1023 
tryCreateIpSecTunnelInterface()1024     private IpSecManager.IpSecTunnelInterface tryCreateIpSecTunnelInterface() {
1025         try {
1026             return mIpSecManager.createIpSecTunnelInterface(
1027                     DUMMY_ADDR /* unused */, DUMMY_ADDR /* unused */, mDefaultNetwork);
1028         } catch (IpSecManager.ResourceUnavailableException | IOException e) {
1029             Log.e(TAG, "Failed to create tunnel interface. " + e);
1030             return null;
1031         }
1032     }
1033 
onBringUpTunnel( TunnelRequestWrapper tunnelRequestWrapper, InetAddress epdgAddress)1034     private void onBringUpTunnel(
1035             TunnelRequestWrapper tunnelRequestWrapper, InetAddress epdgAddress) {
1036         TunnelSetupRequest setupRequest = tunnelRequestWrapper.getSetupRequest();
1037         TunnelCallback tunnelCallback = tunnelRequestWrapper.getTunnelCallback();
1038         String apnName = setupRequest.apnName();
1039         IkeSessionParams ikeSessionParams;
1040         IpSecManager.IpSecTunnelInterface iface;
1041 
1042         Log.d(
1043                 TAG,
1044                 "Bringing up tunnel for apn: "
1045                         + apnName
1046                         + " ePDG: "
1047                         + epdgAddress.getHostAddress());
1048 
1049         final int token = incrementAndGetCurrentTokenForApn(apnName);
1050 
1051         ikeSessionParams = tryBuildIkeSessionParams(setupRequest, apnName, token, epdgAddress);
1052         if (Objects.isNull(ikeSessionParams)) {
1053             IwlanError iwlanError = new IwlanError(IwlanError.SIM_NOT_READY_EXCEPTION);
1054             reportIwlanError(apnName, iwlanError);
1055             tunnelCallback.onClosed(
1056                     apnName, iwlanError, new OnClosedMetrics.Builder().setApnName(apnName).build());
1057             return;
1058         }
1059 
1060         iface = tryCreateIpSecTunnelInterface();
1061         if (Objects.isNull(iface)) {
1062             IwlanError iwlanError = new IwlanError(IwlanError.TUNNEL_TRANSFORM_FAILED);
1063             reportIwlanError(apnName, iwlanError);
1064             tunnelCallback.onClosed(
1065                     apnName, iwlanError, new OnClosedMetrics.Builder().setApnName(apnName).build());
1066             return;
1067         }
1068 
1069         mIkeTunnelEstablishmentStartTime = System.currentTimeMillis();
1070         IkeSession ikeSession =
1071                 getIkeSessionCreator()
1072                         .createIkeSession(
1073                                 mContext,
1074                                 ikeSessionParams,
1075                                 buildChildSessionParams(setupRequest),
1076                                 Executors.newSingleThreadExecutor(),
1077                                 getTmIkeSessionCallback(apnName, token),
1078                                 new TmChildSessionCallback(apnName, token));
1079 
1080         boolean isSrcIpv6Present = setupRequest.srcIpv6Address().isPresent();
1081         putApnNameToTunnelConfig(
1082                 apnName,
1083                 ikeSession,
1084                 tunnelCallback,
1085                 iface,
1086                 isSrcIpv6Present ? setupRequest.srcIpv6Address().get() : null,
1087                 setupRequest.srcIpv6AddressPrefixLength(),
1088                 setupRequest.isEmergency(),
1089                 epdgAddress);
1090     }
1091 
1092     /**
1093      * Proxy to allow testing
1094      *
1095      * @hide
1096      */
1097     @VisibleForTesting
1098     static class IkeSessionCreator {
1099         /** Creates a IKE session */
createIkeSession( @onNull Context context, @NonNull IkeSessionParams ikeSessionParams, @NonNull ChildSessionParams firstChildSessionParams, @NonNull Executor userCbExecutor, @NonNull IkeSessionCallback ikeSessionCallback, @NonNull ChildSessionCallback firstChildSessionCallback)1100         public IkeSession createIkeSession(
1101                 @NonNull Context context,
1102                 @NonNull IkeSessionParams ikeSessionParams,
1103                 @NonNull ChildSessionParams firstChildSessionParams,
1104                 @NonNull Executor userCbExecutor,
1105                 @NonNull IkeSessionCallback ikeSessionCallback,
1106                 @NonNull ChildSessionCallback firstChildSessionCallback) {
1107             return new IkeSession(
1108                     context,
1109                     ikeSessionParams,
1110                     firstChildSessionParams,
1111                     userCbExecutor,
1112                     ikeSessionCallback,
1113                     firstChildSessionCallback);
1114         }
1115     }
1116 
buildChildSessionParams(TunnelSetupRequest setupRequest)1117     private ChildSessionParams buildChildSessionParams(TunnelSetupRequest setupRequest) {
1118         int proto = setupRequest.apnIpProtocol();
1119         int hardTimeSeconds =
1120                 IwlanCarrierConfig.getConfigInt(
1121                         mContext,
1122                         mSlotId,
1123                         CarrierConfigManager.Iwlan.KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT);
1124         int softTimeSeconds =
1125                 IwlanCarrierConfig.getConfigInt(
1126                         mContext,
1127                         mSlotId,
1128                         CarrierConfigManager.Iwlan.KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT);
1129         if (!isValidChildSessionLifetime(hardTimeSeconds, softTimeSeconds)) {
1130             if (hardTimeSeconds > CHILD_HARD_LIFETIME_SEC_MAXIMUM
1131                     && softTimeSeconds > CHILD_SOFT_LIFETIME_SEC_MINIMUM) {
1132                 hardTimeSeconds = CHILD_HARD_LIFETIME_SEC_MAXIMUM;
1133                 softTimeSeconds = CHILD_HARD_LIFETIME_SEC_MAXIMUM - LIFETIME_MARGIN_SEC_MINIMUM;
1134             } else {
1135                 hardTimeSeconds =
1136                         IwlanCarrierConfig.getDefaultConfigInt(
1137                                 CarrierConfigManager.Iwlan.KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT);
1138                 softTimeSeconds =
1139                         IwlanCarrierConfig.getDefaultConfigInt(
1140                                 CarrierConfigManager.Iwlan.KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT);
1141             }
1142             Log.d(
1143                     TAG,
1144                     "Invalid child session lifetime values, set hard: "
1145                             + hardTimeSeconds
1146                             + ", soft: "
1147                             + softTimeSeconds);
1148         }
1149 
1150         TunnelModeChildSessionParams.Builder childSessionParamsBuilder =
1151                 new TunnelModeChildSessionParams.Builder()
1152                         .setLifetimeSeconds(hardTimeSeconds, softTimeSeconds);
1153 
1154         // Else block and it's related functionality can be removed once
1155         // multipleSaProposals, highSecureTransformsPrioritized and aeadAlgosEnabled feature flags
1156         // related functionality becomes stable and gets instruction to remove feature flags.
1157         if (mFeatureFlags.multipleSaProposals()
1158                 || mFeatureFlags.highSecureTransformsPrioritized()) {
1159             EpdgChildSaProposal epdgChildSaProposal = createEpdgChildSaProposal();
1160 
1161             if (IwlanCarrierConfig.getConfigBoolean(
1162                     mContext,
1163                     mSlotId,
1164                     CarrierConfigManager.Iwlan.KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL)) {
1165                 epdgChildSaProposal.enableAddChildSessionRekeyKePayload();
1166             }
1167             // Adds single SA proposal, priority is for AEAD if configured else non-AEAD proposal.
1168             if (isChildSessionAeadAlgosAvailable()) {
1169                 childSessionParamsBuilder.addChildSaProposal(
1170                         epdgChildSaProposal.buildProposedChildSaAeadProposal());
1171             } else {
1172                 childSessionParamsBuilder.addChildSaProposal(
1173                         epdgChildSaProposal.buildProposedChildSaProposal());
1174             }
1175             // Adds multiple proposals. If AEAD proposal already added then adds
1176             // configured non-AEAD proposal followed by supported AEAD and non-AEAD proposals.
1177             if (IwlanCarrierConfig.getConfigBoolean(
1178                     mContext,
1179                     mSlotId,
1180                     CarrierConfigManager.Iwlan
1181                             .KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL)) {
1182                 if (isChildSessionAeadAlgosAvailable() && isChildSessionNonAeadAlgosAvailable()) {
1183                     childSessionParamsBuilder.addChildSaProposal(
1184                             epdgChildSaProposal.buildProposedChildSaProposal());
1185                 }
1186                 childSessionParamsBuilder.addChildSaProposal(
1187                         epdgChildSaProposal.buildSupportedChildSaAeadProposal());
1188                 childSessionParamsBuilder.addChildSaProposal(
1189                         epdgChildSaProposal.buildSupportedChildSaProposal());
1190             }
1191         } else {
1192             if (isChildSessionAeadAlgosAvailable()) {
1193                 childSessionParamsBuilder.addChildSaProposal(buildAeadChildSaProposal());
1194             } else {
1195                 childSessionParamsBuilder.addChildSaProposal(buildChildSaProposal());
1196             }
1197         }
1198 
1199         boolean handoverIPv4Present = setupRequest.srcIpv4Address().isPresent();
1200         boolean handoverIPv6Present = setupRequest.srcIpv6Address().isPresent();
1201         if (handoverIPv4Present || handoverIPv6Present) {
1202             if (handoverIPv4Present) {
1203                 childSessionParamsBuilder.addInternalAddressRequest(
1204                         (Inet4Address) setupRequest.srcIpv4Address().get());
1205                 childSessionParamsBuilder.addInternalDnsServerRequest(AF_INET);
1206                 childSessionParamsBuilder.addInboundTrafficSelectors(
1207                         getDefaultTrafficSelectorIpv4());
1208                 childSessionParamsBuilder.addOutboundTrafficSelectors(
1209                         getDefaultTrafficSelectorIpv4());
1210             }
1211             if (handoverIPv6Present) {
1212                 childSessionParamsBuilder.addInternalAddressRequest(
1213                         (Inet6Address) setupRequest.srcIpv6Address().get(),
1214                         setupRequest.srcIpv6AddressPrefixLength());
1215                 childSessionParamsBuilder.addInternalDnsServerRequest(AF_INET6);
1216                 childSessionParamsBuilder.addInboundTrafficSelectors(
1217                         getDefaultTrafficSelectorIpv6());
1218                 childSessionParamsBuilder.addOutboundTrafficSelectors(
1219                         getDefaultTrafficSelectorIpv6());
1220             }
1221         } else {
1222             // non-handover case
1223             if (proto == ApnSetting.PROTOCOL_IP || proto == ApnSetting.PROTOCOL_IPV4V6) {
1224                 childSessionParamsBuilder.addInternalAddressRequest(AF_INET);
1225                 childSessionParamsBuilder.addInternalDnsServerRequest(AF_INET);
1226                 childSessionParamsBuilder.addInboundTrafficSelectors(
1227                         getDefaultTrafficSelectorIpv4());
1228                 childSessionParamsBuilder.addOutboundTrafficSelectors(
1229                         getDefaultTrafficSelectorIpv4());
1230             }
1231             if (proto == ApnSetting.PROTOCOL_IPV6 || proto == ApnSetting.PROTOCOL_IPV4V6) {
1232                 childSessionParamsBuilder.addInternalAddressRequest(AF_INET6);
1233                 childSessionParamsBuilder.addInternalDnsServerRequest(AF_INET6);
1234                 childSessionParamsBuilder.addInboundTrafficSelectors(
1235                         getDefaultTrafficSelectorIpv6());
1236                 childSessionParamsBuilder.addOutboundTrafficSelectors(
1237                         getDefaultTrafficSelectorIpv6());
1238             }
1239         }
1240 
1241         return childSessionParamsBuilder.build();
1242     }
1243 
getDefaultTrafficSelectorIpv4()1244     private static IkeTrafficSelector getDefaultTrafficSelectorIpv4() {
1245         return new IkeTrafficSelector(
1246                 TRAFFIC_SELECTOR_START_PORT,
1247                 TRAFFIC_SELECTOR_END_PORT,
1248                 InetAddresses.parseNumericAddress(TRAFFIC_SELECTOR_IPV4_START_ADDR),
1249                 InetAddresses.parseNumericAddress(TRAFFIC_SELECTOR_IPV4_END_ADDR));
1250     }
1251 
getDefaultTrafficSelectorIpv6()1252     private static IkeTrafficSelector getDefaultTrafficSelectorIpv6() {
1253         return new IkeTrafficSelector(
1254                 TRAFFIC_SELECTOR_START_PORT,
1255                 TRAFFIC_SELECTOR_END_PORT,
1256                 InetAddresses.parseNumericAddress(TRAFFIC_SELECTOR_IPV6_START_ADDR),
1257                 InetAddresses.parseNumericAddress(TRAFFIC_SELECTOR_IPV6_END_ADDR));
1258     }
1259 
needIncludeInitialContact(InetAddress epdgAddress)1260     private boolean needIncludeInitialContact(InetAddress epdgAddress) {
1261         return !mEpdgMonitor.isConnectedEpdg(epdgAddress);
1262     }
1263 
1264     // Returns the IMEISV or device IMEI, in that order of priority.
getMobileDeviceIdentity()1265     private @Nullable String getMobileDeviceIdentity() {
1266         TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
1267         telephonyManager =
1268                 Objects.requireNonNull(telephonyManager)
1269                         .createForSubscriptionId(IwlanHelper.getSubId(mContext, mSlotId));
1270         if (telephonyManager == null) {
1271             return null;
1272         }
1273         // Queries the 15-digit device IMEI.
1274         String imei = telephonyManager.getImei();
1275         if (imei == null || imei.length() != DEVICE_IMEI_LEN) {
1276             Log.i(TAG, "Unable to query valid Mobile Device Identity (IMEI)!");
1277             return null;
1278         }
1279         String imeisv_suffix = telephonyManager.getDeviceSoftwareVersion();
1280         if (imeisv_suffix == null || imeisv_suffix.length() != DEVICE_IMEISV_SUFFIX_LEN) {
1281             // Unable to retrieve 2-digit suffix for IMEISV, so returns device IMEI.
1282             return imei;
1283         }
1284         // Splices the first 14 digit of device IMEI with 2-digit SV suffix to form IMEISV.
1285         return imei.substring(0, imei.length() - 1) + imeisv_suffix;
1286     }
1287 
buildIkeSessionParams( TunnelSetupRequest setupRequest, String apnName, int token, InetAddress epdgAddress)1288     private IkeSessionParams buildIkeSessionParams(
1289             TunnelSetupRequest setupRequest, String apnName, int token, InetAddress epdgAddress)
1290             throws IwlanSimNotReadyException {
1291         int hardTimeSeconds =
1292                 IwlanCarrierConfig.getConfigInt(
1293                         mContext,
1294                         mSlotId,
1295                         CarrierConfigManager.Iwlan.KEY_IKE_REKEY_HARD_TIMER_SEC_INT);
1296         int softTimeSeconds =
1297                 IwlanCarrierConfig.getConfigInt(
1298                         mContext,
1299                         mSlotId,
1300                         CarrierConfigManager.Iwlan.KEY_IKE_REKEY_SOFT_TIMER_SEC_INT);
1301         if (!isValidIkeSessionLifetime(hardTimeSeconds, softTimeSeconds)) {
1302             if (hardTimeSeconds > IKE_HARD_LIFETIME_SEC_MAXIMUM
1303                     && softTimeSeconds > IKE_SOFT_LIFETIME_SEC_MINIMUM) {
1304                 hardTimeSeconds = IKE_HARD_LIFETIME_SEC_MAXIMUM;
1305                 softTimeSeconds = IKE_HARD_LIFETIME_SEC_MAXIMUM - LIFETIME_MARGIN_SEC_MINIMUM;
1306             } else {
1307                 hardTimeSeconds =
1308                         IwlanCarrierConfig.getDefaultConfigInt(
1309                                 CarrierConfigManager.Iwlan.KEY_IKE_REKEY_HARD_TIMER_SEC_INT);
1310                 softTimeSeconds =
1311                         IwlanCarrierConfig.getDefaultConfigInt(
1312                                 CarrierConfigManager.Iwlan.KEY_IKE_REKEY_SOFT_TIMER_SEC_INT);
1313             }
1314             Log.d(
1315                     TAG,
1316                     "Invalid ike session lifetime values, set hard: "
1317                             + hardTimeSeconds
1318                             + ", soft: "
1319                             + softTimeSeconds);
1320         }
1321 
1322         IkeSessionParams.Builder builder =
1323                 new IkeSessionParams.Builder()
1324                         // permanently hardcode DSCP to 46 (Expedited Forwarding class)
1325                         // See https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml
1326                         // This will make WiFi prioritize IKE signallig under WMM AC_VO
1327                         .setDscp(46)
1328                         .setServerHostname(epdgAddress.getHostAddress())
1329                         .setLocalIdentification(getLocalIdentification())
1330                         .setRemoteIdentification(getId(setupRequest.apnName(), false))
1331                         .setAuthEap(null, getEapConfig())
1332                         .setNetwork(mDefaultNetwork)
1333                         .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
1334                         .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
1335                         .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY)
1336                         .setLifetimeSeconds(hardTimeSeconds, softTimeSeconds)
1337                         .setRetransmissionTimeoutsMillis(getRetransmissionTimeoutsFromConfig())
1338                         .setDpdDelaySeconds(getDpdDelayFromConfig());
1339 
1340         // Else block and it's related functionality can be removed once
1341         // multipleSaProposals, highSecureTransformsPrioritized and aeadAlgosEnabled feature flags
1342         // related functionality becomes stable and gets instruction to remove feature flags.
1343         if (mFeatureFlags.multipleSaProposals()
1344                 || mFeatureFlags.highSecureTransformsPrioritized()) {
1345             EpdgIkeSaProposal epdgIkeSaProposal = createEpdgIkeSaProposal();
1346 
1347             // Adds single SA proposal, priority is for AEAD if configured else non-AEAD proposal.
1348             if (isIkeSessionAeadAlgosAvailable()) {
1349                 builder.addIkeSaProposal(epdgIkeSaProposal.buildProposedIkeSaAeadProposal());
1350             } else {
1351                 builder.addIkeSaProposal(epdgIkeSaProposal.buildProposedIkeSaProposal());
1352             }
1353             // Adds multiple proposals. If AEAD proposal already added then adds
1354             // configured non-AEAD proposal followed by supported AEAD and non-AEAD proposals.
1355             if (IwlanCarrierConfig.getConfigBoolean(
1356                     mContext,
1357                     mSlotId,
1358                     CarrierConfigManager.Iwlan
1359                             .KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL)) {
1360                 if (isIkeSessionAeadAlgosAvailable() && isIkeSessionNonAeadAlgosAvailable()) {
1361                     builder.addIkeSaProposal(epdgIkeSaProposal.buildProposedIkeSaProposal());
1362                 }
1363                 builder.addIkeSaProposal(epdgIkeSaProposal.buildSupportedIkeSaAeadProposal());
1364                 builder.addIkeSaProposal(epdgIkeSaProposal.buildSupportedIkeSaProposal());
1365             }
1366         } else {
1367             if (isIkeSessionAeadAlgosAvailable()) {
1368                 builder.addIkeSaProposal(buildIkeSaAeadProposal());
1369             } else {
1370                 builder.addIkeSaProposal(buildIkeSaProposal());
1371             }
1372         }
1373 
1374         if (needIncludeInitialContact(epdgAddress)) {
1375             builder.addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT);
1376             Log.d(TAG, "IKE_OPTION_INITIAL_CONTACT");
1377         }
1378 
1379         if (IwlanCarrierConfig.getConfigInt(
1380                         mContext,
1381                         mSlotId,
1382                         CarrierConfigManager.Iwlan.KEY_EPDG_AUTHENTICATION_METHOD_INT)
1383                 == CarrierConfigManager.Iwlan.AUTHENTICATION_METHOD_EAP_ONLY) {
1384             builder.addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH);
1385         }
1386 
1387         if (setupRequest.requestPcscf()) {
1388             int proto = setupRequest.apnIpProtocol();
1389             if (proto == ApnSetting.PROTOCOL_IP || proto == ApnSetting.PROTOCOL_IPV4V6) {
1390                 builder.addPcscfServerRequest(AF_INET);
1391             }
1392             if (proto == ApnSetting.PROTOCOL_IPV6 || proto == ApnSetting.PROTOCOL_IPV4V6) {
1393                 builder.addPcscfServerRequest(AF_INET6);
1394             }
1395         }
1396 
1397         // If MOBIKE is configured, ePDGs may force IPv6 UDP encapsulation- as specified by
1398         // RFC 4555- which Android connectivity stack presently does not support.
1399         if (epdgAddress instanceof Inet6Address) {
1400             builder.removeIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE);
1401         }
1402 
1403         builder.setIke3gppExtension(buildIke3gppExtension(setupRequest, apnName, token));
1404 
1405         int nattKeepAliveTimer =
1406                 IwlanCarrierConfig.getConfigInt(
1407                         mContext,
1408                         mSlotId,
1409                         CarrierConfigManager.Iwlan.KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT);
1410         if (nattKeepAliveTimer < NATT_KEEPALIVE_DELAY_SEC_MIN
1411                 || nattKeepAliveTimer > NATT_KEEPALIVE_DELAY_SEC_MAX) {
1412             Log.d(TAG, "Falling back to default natt keep alive timer" + nattKeepAliveTimer);
1413             nattKeepAliveTimer =
1414                     IwlanCarrierConfig.getDefaultConfigInt(
1415                             CarrierConfigManager.Iwlan.KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT);
1416         }
1417         builder.setNattKeepAliveDelaySeconds(nattKeepAliveTimer);
1418 
1419         return builder.build();
1420     }
1421 
buildIke3gppExtension( TunnelSetupRequest setupRequest, String apnName, int token)1422     private Ike3gppExtension buildIke3gppExtension(
1423             TunnelSetupRequest setupRequest, String apnName, int token) {
1424         Ike3gppParams.Builder builder3gppParams = new Ike3gppParams.Builder();
1425 
1426         if (IwlanCarrierConfig.getConfigBoolean(
1427                 mContext, mSlotId, IwlanCarrierConfig.KEY_IKE_DEVICE_IDENTITY_SUPPORTED_BOOL)) {
1428             String imei = getMobileDeviceIdentity();
1429             if (imei != null) {
1430                 Log.d(TAG, "DEVICE_IDENTITY set in Ike3gppParams");
1431                 builder3gppParams.setMobileDeviceIdentity(imei);
1432             }
1433         }
1434 
1435         if (setupRequest.pduSessionId() != PDU_SESSION_ID_UNSET) {
1436             // Includes N1_MODE_CAPABILITY NOTIFY payload in IKE_AUTH exchange when PDU session ID
1437             // is set; otherwise, do not include.
1438             builder3gppParams.setPduSessionId((byte) setupRequest.pduSessionId());
1439         }
1440 
1441         return new Ike3gppExtension(
1442                 builder3gppParams.build(), new TmIke3gppCallback(apnName, token));
1443     }
1444 
isChildSessionAeadAlgosAvailable()1445     private boolean isChildSessionAeadAlgosAvailable() {
1446         if (!mFeatureFlags.aeadAlgosEnabled()) {
1447             return false;
1448         }
1449 
1450         int[] encryptionAlgos =
1451                 IwlanCarrierConfig.getConfigIntArray(
1452                         mContext,
1453                         mSlotId,
1454                         CarrierConfigManager.Iwlan
1455                                 .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
1456         for (int encryptionAlgo : encryptionAlgos) {
1457             if (validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1458                 return true;
1459             }
1460         }
1461         return false;
1462     }
1463 
isChildSessionNonAeadAlgosAvailable()1464     private boolean isChildSessionNonAeadAlgosAvailable() {
1465         int[] encryptionAlgos =
1466                 IwlanCarrierConfig.getConfigIntArray(
1467                         mContext,
1468                         mSlotId,
1469                         CarrierConfigManager.Iwlan
1470                                 .KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY);
1471         for (int encryptionAlgo : encryptionAlgos) {
1472             if (validateConfig(encryptionAlgo, VALID_ENCRYPTION_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1473                 return true;
1474             }
1475         }
1476         return false;
1477     }
1478 
isIkeSessionAeadAlgosAvailable()1479     private boolean isIkeSessionAeadAlgosAvailable() {
1480         if (!mFeatureFlags.aeadAlgosEnabled()) {
1481             return false;
1482         }
1483 
1484         int[] encryptionAlgos =
1485                 IwlanCarrierConfig.getConfigIntArray(
1486                         mContext,
1487                         mSlotId,
1488                         CarrierConfigManager.Iwlan
1489                                 .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
1490         for (int encryptionAlgo : encryptionAlgos) {
1491             if (validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1492                 return true;
1493             }
1494         }
1495         return false;
1496     }
1497 
isIkeSessionNonAeadAlgosAvailable()1498     private boolean isIkeSessionNonAeadAlgosAvailable() {
1499         int[] encryptionAlgos =
1500                 IwlanCarrierConfig.getConfigIntArray(
1501                         mContext,
1502                         mSlotId,
1503                         CarrierConfigManager.Iwlan
1504                                 .KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY);
1505         for (int encryptionAlgo : encryptionAlgos) {
1506             if (validateConfig(encryptionAlgo, VALID_ENCRYPTION_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1507                 return true;
1508             }
1509         }
1510         return false;
1511     }
1512 
isValidChildSessionLifetime(int hardLifetimeSeconds, int softLifetimeSeconds)1513     private boolean isValidChildSessionLifetime(int hardLifetimeSeconds, int softLifetimeSeconds) {
1514         return hardLifetimeSeconds >= CHILD_HARD_LIFETIME_SEC_MINIMUM
1515                 && hardLifetimeSeconds <= CHILD_HARD_LIFETIME_SEC_MAXIMUM
1516                 && softLifetimeSeconds >= CHILD_SOFT_LIFETIME_SEC_MINIMUM
1517                 && hardLifetimeSeconds - softLifetimeSeconds >= LIFETIME_MARGIN_SEC_MINIMUM;
1518     }
1519 
isValidIkeSessionLifetime(int hardLifetimeSeconds, int softLifetimeSeconds)1520     private boolean isValidIkeSessionLifetime(int hardLifetimeSeconds, int softLifetimeSeconds) {
1521         return hardLifetimeSeconds >= IKE_HARD_LIFETIME_SEC_MINIMUM
1522                 && hardLifetimeSeconds <= IKE_HARD_LIFETIME_SEC_MAXIMUM
1523                 && softLifetimeSeconds >= IKE_SOFT_LIFETIME_SEC_MINIMUM
1524                 && hardLifetimeSeconds - softLifetimeSeconds >= LIFETIME_MARGIN_SEC_MINIMUM;
1525     }
1526 
createEpdgSaProposal(EpdgSaProposal epdgSaProposal, boolean isChildProposal)1527     private void createEpdgSaProposal(EpdgSaProposal epdgSaProposal, boolean isChildProposal) {
1528         epdgSaProposal.addProposedDhGroups(
1529                 IwlanCarrierConfig.getConfigIntArray(
1530                         mContext,
1531                         mSlotId,
1532                         CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY));
1533 
1534         String encryptionAlgosConfigKey =
1535                 isChildProposal
1536                         ? CarrierConfigManager.Iwlan
1537                                 .KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY
1538                         : CarrierConfigManager.Iwlan
1539                                 .KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY;
1540 
1541         int[] encryptionAlgos =
1542                 IwlanCarrierConfig.getConfigIntArray(mContext, mSlotId, encryptionAlgosConfigKey);
1543 
1544         for (int encryptionAlgo : encryptionAlgos) {
1545             if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CBC) {
1546                 String aesCbcKeyLensConfigKey =
1547                         isChildProposal
1548                                 ? CarrierConfigManager.Iwlan
1549                                         .KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY
1550                                 : CarrierConfigManager.Iwlan
1551                                         .KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY;
1552 
1553                 int[] aesCbcKeyLens =
1554                         IwlanCarrierConfig.getConfigIntArray(
1555                                 mContext, mSlotId, aesCbcKeyLensConfigKey);
1556                 epdgSaProposal.addProposedEncryptionAlgorithm(encryptionAlgo, aesCbcKeyLens);
1557             }
1558 
1559             if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CTR) {
1560                 String aesCtrKeyLensConfigKey =
1561                         isChildProposal
1562                                 ? CarrierConfigManager.Iwlan
1563                                         .KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY
1564                                 : CarrierConfigManager.Iwlan
1565                                         .KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY;
1566                 int[] aesCtrKeyLens =
1567                         IwlanCarrierConfig.getConfigIntArray(
1568                                 mContext, mSlotId, aesCtrKeyLensConfigKey);
1569                 epdgSaProposal.addProposedEncryptionAlgorithm(encryptionAlgo, aesCtrKeyLens);
1570             }
1571         }
1572 
1573         if (encryptionAlgos.length > 0) {
1574             epdgSaProposal.addProposedIntegrityAlgorithm(
1575                     IwlanCarrierConfig.getConfigIntArray(
1576                             mContext,
1577                             mSlotId,
1578                             CarrierConfigManager.Iwlan
1579                                     .KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY));
1580         }
1581 
1582         String aeadAlgosConfigKey =
1583                 isChildProposal
1584                         ? CarrierConfigManager.Iwlan
1585                                 .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY
1586                         : CarrierConfigManager.Iwlan
1587                                 .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY;
1588         int[] aeadAlgos =
1589                 IwlanCarrierConfig.getConfigIntArray(mContext, mSlotId, aeadAlgosConfigKey);
1590         for (int aeadAlgo : aeadAlgos) {
1591             if (!validateConfig(aeadAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1592                 continue;
1593             }
1594             if ((aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)
1595                     || (aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12)
1596                     || (aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) {
1597                 String aesGcmKeyLensConfigKey =
1598                         isChildProposal
1599                                 ? CarrierConfigManager.Iwlan
1600                                         .KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY
1601                                 : CarrierConfigManager.Iwlan
1602                                         .KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY;
1603                 int[] aesGcmKeyLens =
1604                         IwlanCarrierConfig.getConfigIntArray(
1605                                 mContext, mSlotId, aesGcmKeyLensConfigKey);
1606                 epdgSaProposal.addProposedAeadAlgorithm(aeadAlgo, aesGcmKeyLens);
1607             }
1608         }
1609 
1610         if (IwlanCarrierConfig.getConfigBoolean(
1611                 mContext, mSlotId, IwlanCarrierConfig.KEY_IKE_SA_TRANSFORMS_REORDER_BOOL)) {
1612             epdgSaProposal.enableReorderingSaferProposals();
1613         }
1614     }
1615 
createEpdgChildSaProposal()1616     private EpdgChildSaProposal createEpdgChildSaProposal() {
1617         EpdgChildSaProposal epdgChildSaProposal = new EpdgChildSaProposal();
1618         createEpdgSaProposal(epdgChildSaProposal, true);
1619         return epdgChildSaProposal;
1620     }
1621 
createEpdgIkeSaProposal()1622     private EpdgIkeSaProposal createEpdgIkeSaProposal() {
1623         EpdgIkeSaProposal epdgIkeSaProposal = new EpdgIkeSaProposal();
1624 
1625         createEpdgSaProposal(epdgIkeSaProposal, false);
1626 
1627         epdgIkeSaProposal.addProposedPrfAlgorithm(
1628                 IwlanCarrierConfig.getConfigIntArray(
1629                         mContext,
1630                         mSlotId,
1631                         CarrierConfigManager.Iwlan.KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY));
1632         return epdgIkeSaProposal;
1633     }
1634 
buildIkeSaProposal()1635     private IkeSaProposal buildIkeSaProposal() {
1636         IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder();
1637 
1638         int[] dhGroups =
1639                 IwlanCarrierConfig.getConfigIntArray(
1640                         mContext,
1641                         mSlotId,
1642                         CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY);
1643         for (int dhGroup : dhGroups) {
1644             if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
1645                 saProposalBuilder.addDhGroup(dhGroup);
1646             }
1647         }
1648 
1649         int[] encryptionAlgos =
1650                 IwlanCarrierConfig.getConfigIntArray(
1651                         mContext,
1652                         mSlotId,
1653                         CarrierConfigManager.Iwlan
1654                                 .KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY);
1655         for (int encryptionAlgo : encryptionAlgos) {
1656             validateConfig(encryptionAlgo, VALID_ENCRYPTION_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO);
1657 
1658             if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CBC) {
1659                 int[] aesCbcKeyLens =
1660                         IwlanCarrierConfig.getConfigIntArray(
1661                                 mContext,
1662                                 mSlotId,
1663                                 CarrierConfigManager.Iwlan
1664                                         .KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY);
1665                 for (int aesCbcKeyLen : aesCbcKeyLens) {
1666                     if (validateConfig(aesCbcKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
1667                         saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesCbcKeyLen);
1668                     }
1669                 }
1670             }
1671 
1672             if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CTR) {
1673                 int[] aesCtrKeyLens =
1674                         IwlanCarrierConfig.getConfigIntArray(
1675                                 mContext,
1676                                 mSlotId,
1677                                 CarrierConfigManager.Iwlan
1678                                         .KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY);
1679                 for (int aesCtrKeyLen : aesCtrKeyLens) {
1680                     if (validateConfig(aesCtrKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
1681                         saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesCtrKeyLen);
1682                     }
1683                 }
1684             }
1685         }
1686 
1687         int[] integrityAlgos =
1688                 IwlanCarrierConfig.getConfigIntArray(
1689                         mContext,
1690                         mSlotId,
1691                         CarrierConfigManager.Iwlan.KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY);
1692         for (int integrityAlgo : integrityAlgos) {
1693             if (validateConfig(integrityAlgo, VALID_INTEGRITY_ALGOS, CONFIG_TYPE_INTEGRITY_ALGO)) {
1694                 saProposalBuilder.addIntegrityAlgorithm(integrityAlgo);
1695             }
1696         }
1697 
1698         int[] prfAlgos =
1699                 IwlanCarrierConfig.getConfigIntArray(
1700                         mContext,
1701                         mSlotId,
1702                         CarrierConfigManager.Iwlan.KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY);
1703         for (int prfAlgo : prfAlgos) {
1704             if (validateConfig(prfAlgo, VALID_PRF_ALGOS, CONFIG_TYPE_PRF_ALGO)) {
1705                 saProposalBuilder.addPseudorandomFunction(prfAlgo);
1706             }
1707         }
1708 
1709         return saProposalBuilder.build();
1710     }
1711 
buildIkeSaAeadProposal()1712     private IkeSaProposal buildIkeSaAeadProposal() {
1713         IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder();
1714 
1715         int[] dhGroups =
1716                 IwlanCarrierConfig.getConfigIntArray(
1717                         mContext,
1718                         mSlotId,
1719                         CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY);
1720         for (int dhGroup : dhGroups) {
1721             if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
1722                 saProposalBuilder.addDhGroup(dhGroup);
1723             }
1724         }
1725 
1726         int[] encryptionAlgos =
1727                 IwlanCarrierConfig.getConfigIntArray(
1728                         mContext,
1729                         mSlotId,
1730                         CarrierConfigManager.Iwlan
1731                                 .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
1732         for (int encryptionAlgo : encryptionAlgos) {
1733             if (!validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1734                 continue;
1735             }
1736             if ((encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)
1737                     || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12)
1738                     || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) {
1739                 int[] aesGcmKeyLens =
1740                         IwlanCarrierConfig.getConfigIntArray(
1741                                 mContext,
1742                                 mSlotId,
1743                                 CarrierConfigManager.Iwlan
1744                                         .KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY);
1745                 for (int aesGcmKeyLen : aesGcmKeyLens) {
1746                     if (validateConfig(aesGcmKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
1747                         saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesGcmKeyLen);
1748                     }
1749                 }
1750             }
1751         }
1752 
1753         int[] prfAlgos =
1754                 IwlanCarrierConfig.getConfigIntArray(
1755                         mContext,
1756                         mSlotId,
1757                         CarrierConfigManager.Iwlan.KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY);
1758         for (int prfAlgo : prfAlgos) {
1759             if (validateConfig(prfAlgo, VALID_PRF_ALGOS, CONFIG_TYPE_PRF_ALGO)) {
1760                 saProposalBuilder.addPseudorandomFunction(prfAlgo);
1761             }
1762         }
1763 
1764         return saProposalBuilder.build();
1765     }
1766 
validateConfig(int config, Set<Integer> validConfigValues, String configType)1767     private boolean validateConfig(int config, Set<Integer> validConfigValues, String configType) {
1768         if (validConfigValues.contains(config)) {
1769             return true;
1770         }
1771 
1772         Log.e(TAG, "Invalid config value for " + configType + ":" + config);
1773         return false;
1774     }
1775 
buildChildSaProposal()1776     private ChildSaProposal buildChildSaProposal() {
1777         ChildSaProposal.Builder saProposalBuilder = new ChildSaProposal.Builder();
1778 
1779         // IKE library doesn't add KE payload if dh groups are not set in child session params.
1780         // Use the same groups as that of IKE session.
1781         if (IwlanCarrierConfig.getConfigBoolean(
1782                 mContext,
1783                 mSlotId,
1784                 CarrierConfigManager.Iwlan.KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL)) {
1785             int[] dhGroups =
1786                     IwlanCarrierConfig.getConfigIntArray(
1787                             mContext,
1788                             mSlotId,
1789                             CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY);
1790             for (int dhGroup : dhGroups) {
1791                 if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
1792                     saProposalBuilder.addDhGroup(dhGroup);
1793                 }
1794             }
1795         }
1796 
1797         int[] encryptionAlgos =
1798                 IwlanCarrierConfig.getConfigIntArray(
1799                         mContext,
1800                         mSlotId,
1801                         CarrierConfigManager.Iwlan
1802                                 .KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY);
1803         for (int encryptionAlgo : encryptionAlgos) {
1804             if (validateConfig(encryptionAlgo, VALID_ENCRYPTION_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1805                 if (ChildSaProposal.getSupportedEncryptionAlgorithms().contains(encryptionAlgo)) {
1806                     if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CBC) {
1807                         int[] aesCbcKeyLens =
1808                                 IwlanCarrierConfig.getConfigIntArray(
1809                                         mContext,
1810                                         mSlotId,
1811                                         CarrierConfigManager.Iwlan
1812                                                 .KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY);
1813                         for (int aesCbcKeyLen : aesCbcKeyLens) {
1814                             if (validateConfig(
1815                                     aesCbcKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
1816                                 saProposalBuilder.addEncryptionAlgorithm(
1817                                         encryptionAlgo, aesCbcKeyLen);
1818                             }
1819                         }
1820                     }
1821 
1822                     if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CTR) {
1823                         int[] aesCtrKeyLens =
1824                                 IwlanCarrierConfig.getConfigIntArray(
1825                                         mContext,
1826                                         mSlotId,
1827                                         CarrierConfigManager.Iwlan
1828                                                 .KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY);
1829                         for (int aesCtrKeyLen : aesCtrKeyLens) {
1830                             if (validateConfig(
1831                                     aesCtrKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
1832                                 saProposalBuilder.addEncryptionAlgorithm(
1833                                         encryptionAlgo, aesCtrKeyLen);
1834                             }
1835                         }
1836                     }
1837                 } else {
1838                     Log.w(TAG, "Device does not support encryption algo:  " + encryptionAlgo);
1839                 }
1840             }
1841         }
1842 
1843         int[] integrityAlgos =
1844                 IwlanCarrierConfig.getConfigIntArray(
1845                         mContext,
1846                         mSlotId,
1847                         CarrierConfigManager.Iwlan.KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY);
1848         for (int integrityAlgo : integrityAlgos) {
1849             if (validateConfig(integrityAlgo, VALID_INTEGRITY_ALGOS, CONFIG_TYPE_INTEGRITY_ALGO)) {
1850                 if (ChildSaProposal.getSupportedIntegrityAlgorithms().contains(integrityAlgo)) {
1851                     saProposalBuilder.addIntegrityAlgorithm(integrityAlgo);
1852                 } else {
1853                     Log.w(TAG, "Device does not support integrity algo:  " + integrityAlgo);
1854                 }
1855             }
1856         }
1857 
1858         return saProposalBuilder.build();
1859     }
1860 
buildAeadChildSaProposal()1861     private ChildSaProposal buildAeadChildSaProposal() {
1862         ChildSaProposal.Builder saProposalBuilder = new ChildSaProposal.Builder();
1863 
1864         int[] dhGroups =
1865                 IwlanCarrierConfig.getConfigIntArray(
1866                         mContext,
1867                         mSlotId,
1868                         CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY);
1869         for (int dhGroup : dhGroups) {
1870             if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
1871                 saProposalBuilder.addDhGroup(dhGroup);
1872             }
1873         }
1874 
1875         int[] encryptionAlgos =
1876                 IwlanCarrierConfig.getConfigIntArray(
1877                         mContext,
1878                         mSlotId,
1879                         CarrierConfigManager.Iwlan
1880                                 .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
1881         for (int encryptionAlgo : encryptionAlgos) {
1882             if (!validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
1883                 continue;
1884             }
1885             if ((encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)
1886                     || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12)
1887                     || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) {
1888                 int[] aesGcmKeyLens =
1889                         IwlanCarrierConfig.getConfigIntArray(
1890                                 mContext,
1891                                 mSlotId,
1892                                 CarrierConfigManager.Iwlan
1893                                         .KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY);
1894                 for (int aesGcmKeyLen : aesGcmKeyLens) {
1895                     if (validateConfig(aesGcmKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
1896                         saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesGcmKeyLen);
1897                     }
1898                 }
1899             }
1900         }
1901 
1902         return saProposalBuilder.build();
1903     }
1904 
getLocalIdentification()1905     private IkeIdentification getLocalIdentification() throws IwlanSimNotReadyException {
1906         String nai;
1907 
1908         nai = IwlanHelper.getNai(mContext, mSlotId, mNextReauthId);
1909 
1910         if (nai == null) {
1911             throw new IwlanSimNotReadyException("Nai is null.");
1912         }
1913 
1914         Log.d(TAG, "getLocalIdentification: Nai: " + nai);
1915         return getId(nai, true);
1916     }
1917 
getId(String id, boolean isLocal)1918     private IkeIdentification getId(String id, boolean isLocal) {
1919         String idTypeConfig =
1920                 isLocal
1921                         ? CarrierConfigManager.Iwlan.KEY_IKE_LOCAL_ID_TYPE_INT
1922                         : CarrierConfigManager.Iwlan.KEY_IKE_REMOTE_ID_TYPE_INT;
1923         int idType = IwlanCarrierConfig.getConfigInt(mContext, mSlotId, idTypeConfig);
1924         return switch (idType) {
1925             case CarrierConfigManager.Iwlan.ID_TYPE_FQDN -> new IkeFqdnIdentification(id);
1926             case CarrierConfigManager.Iwlan.ID_TYPE_KEY_ID ->
1927                     new IkeKeyIdIdentification(id.getBytes(StandardCharsets.US_ASCII));
1928             case CarrierConfigManager.Iwlan.ID_TYPE_RFC822_ADDR ->
1929                     new IkeRfc822AddrIdentification(id);
1930             default -> throw new IllegalArgumentException("Invalid local Identity type: " + idType);
1931         };
1932     }
1933 
1934     private EapSessionConfig getEapConfig() throws IwlanSimNotReadyException {
1935         int subId = IwlanHelper.getSubId(mContext, mSlotId);
1936         String nai = IwlanHelper.getNai(mContext, mSlotId, null);
1937 
1938         if (nai == null) {
1939             throw new IwlanSimNotReadyException("Nai is null.");
1940         }
1941 
1942         EapSessionConfig.EapAkaOption option = null;
1943         if (mNextReauthId != null) {
1944             option = new EapSessionConfig.EapAkaOption.Builder().setReauthId(mNextReauthId).build();
1945         }
1946 
1947         Log.d(TAG, "getEapConfig: Nai: " + nai);
1948         return new EapSessionConfig.Builder()
1949                 .setEapAkaConfig(subId, TelephonyManager.APPTYPE_USIM, option)
1950                 .setEapIdentity(nai.getBytes(StandardCharsets.US_ASCII))
1951                 .build();
1952     }
1953 
1954     private void onSessionClosedWithException(
1955             IkeException exception, String apnName, int token, int sessionType) {
1956         Log.e(
1957                 TAG,
1958                 "Closing tunnel with exception for apn: "
1959                         + apnName
1960                         + " with token: "
1961                         + token
1962                         + " sessionType:"
1963                         + sessionType);
1964         exception.printStackTrace();
1965 
1966         mHandler.obtainMessage(sessionType, new SessionClosedData(apnName, token, exception))
1967                 .sendToTarget();
1968     }
1969 
1970     private boolean isEpdgSelectionOrFirstTunnelBringUpInProgress() {
1971         // Tunnel config is created but not connected to an ePDG. i.e., The first bring-up request
1972         // in progress.
1973         // No bring-up request in progress but pending queue is not empty. i.e. ePDG selection in
1974         // progress
1975         return (!mHasConnectedToEpdg && !mApnNameToTunnelConfig.isEmpty())
1976                 || !mPendingBringUpRequests.isEmpty();
1977     }
1978 
1979     private IwlanError getErrorFromIkeException(
1980             IkeException ikeException, IkeSessionState ikeSessionState) {
1981         IwlanError error;
1982         if (ikeException instanceof IkeIOException) {
1983             error = new IwlanError(ikeSessionState.getErrorType(), ikeException);
1984         } else {
1985             error = new IwlanError(ikeException);
1986         }
1987         Log.e(TAG, "Closing tunnel: error: " + error + " state: " + ikeSessionState);
1988         return error;
1989     }
1990 
1991     private final class TmHandler extends Handler {
1992 
1993         @Override
1994         public void handleMessage(Message msg) {
1995             Log.d(TAG, "msg.what = " + eventToString(msg.what));
1996 
1997             String apnName;
1998             TunnelConfig tunnelConfig;
1999             OnClosedMetrics.Builder onClosedMetricsBuilder;
2000             TunnelRequestWrapper tunnelRequestWrapper;
2001             ConnectivityManager connectivityManager;
2002             boolean isNetworkValidated;
2003             switch (msg.what) {
2004                 case EVENT_CHILD_SESSION_OPENED:
2005                 case EVENT_IKE_SESSION_CLOSED:
2006                 case EVENT_IPSEC_TRANSFORM_CREATED:
2007                 case EVENT_IPSEC_TRANSFORM_DELETED:
2008                 case EVENT_CHILD_SESSION_CLOSED:
2009                 case EVENT_IKE_SESSION_OPENED:
2010                 case EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED:
2011                 case EVENT_IKE_3GPP_DATA_RECEIVED:
2012                 case EVENT_IKE_LIVENESS_STATUS_CHANGED:
2013                     IkeEventData ikeEventData = (IkeEventData) msg.obj;
2014                     if (isObsoleteToken(ikeEventData.mApnName, ikeEventData.mToken)) {
2015                         Log.d(
2016                                 TAG,
2017                                 eventToString(msg.what)
2018                                         + " for obsolete token "
2019                                         + ikeEventData.mToken);
2020                         return;
2021                     }
2022             }
2023 
2024             long mIkeTunnelEstablishmentDuration;
2025             switch (msg.what) {
2026                 case EVENT_TUNNEL_BRINGUP_REQUEST:
2027                     handleTunnelBringUpRequest((TunnelRequestWrapper) msg.obj);
2028                     break;
2029 
2030                 case EVENT_EPDG_ADDRESS_SELECTION_REQUEST_COMPLETE:
2031                     EpdgSelectorResult selectorResult = (EpdgSelectorResult) msg.obj;
2032                     printRequestQueue("EVENT_EPDG_ADDRESS_SELECTION_REQUEST_COMPLETE");
2033 
2034                     if (selectorResult.getTransactionId() != mTransactionId) {
2035                         Log.e(TAG, "Mismatched transactionId");
2036                         break;
2037                     }
2038 
2039                     if (mPendingBringUpRequests.isEmpty()) {
2040                         Log.d(TAG, "Empty request queue");
2041                         break;
2042                     }
2043 
2044                     if (selectorResult.getEpdgError().getErrorType() == IwlanError.NO_ERROR
2045                             && selectorResult.getValidIpList() != null) {
2046                         tunnelRequestWrapper = mPendingBringUpRequests.remove();
2047                         onBringUpTunnel(
2048                                 tunnelRequestWrapper,
2049                                 validateAndSetEpdgAddress(selectorResult.getValidIpList()));
2050                     } else {
2051                         IwlanError error =
2052                                 (selectorResult.getEpdgError().getErrorType()
2053                                                 == IwlanError.NO_ERROR)
2054                                         ? new IwlanError(
2055                                                 IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED)
2056                                         : selectorResult.getEpdgError();
2057                         failAllPendingRequests(error);
2058                     }
2059                     break;
2060 
2061                 case EVENT_CHILD_SESSION_OPENED:
2062                     TunnelOpenedData tunnelOpenedData = (TunnelOpenedData) msg.obj;
2063                     apnName = tunnelOpenedData.mApnName;
2064                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2065 
2066                     tunnelConfig.setDnsAddrList(tunnelOpenedData.mInternalDnsServers);
2067                     tunnelConfig.setInternalAddrList(tunnelOpenedData.mInternalAddresses);
2068 
2069                     IpSecManager.IpSecTunnelInterface tunnelInterface = tunnelConfig.getIface();
2070 
2071                     for (LinkAddress address : tunnelConfig.getInternalAddrList()) {
2072                         try {
2073                             tunnelInterface.addAddress(
2074                                     address.getAddress(), address.getPrefixLength());
2075                         } catch (IOException e) {
2076                             Log.e(TAG, "Adding internal addresses to interface failed.");
2077                         }
2078                     }
2079 
2080                     TunnelLinkProperties linkProperties =
2081                             TunnelLinkProperties.builder()
2082                                     .setInternalAddresses(tunnelConfig.getInternalAddrList())
2083                                     .setDnsAddresses(tunnelConfig.getDnsAddrList())
2084                                     .setPcscfAddresses(tunnelConfig.getPcscfAddrList())
2085                                     .setIfaceName(tunnelConfig.getIface().getInterfaceName())
2086                                     .setSliceInfo(tunnelConfig.getSliceInfo())
2087                                     .build();
2088 
2089                     mIkeTunnelEstablishmentDuration =
2090                             System.currentTimeMillis() - mIkeTunnelEstablishmentStartTime;
2091                     mIkeTunnelEstablishmentStartTime = 0;
2092                     isNetworkValidated = isUnderlyingNetworkValidated(mIkeSessionNetwork);
2093                     OnOpenedMetrics onOpenedMetrics =
2094                             new OnOpenedMetrics.Builder()
2095                                     .setApnName(apnName)
2096                                     .setEpdgServerAddress(tunnelConfig.getEpdgAddress())
2097                                     .setEpdgServerSelectionDuration(
2098                                             (int) mEpdgServerSelectionDuration)
2099                                     .setIkeTunnelEstablishmentDuration(
2100                                             (int) mIkeTunnelEstablishmentDuration)
2101                                     .setIsNetworkValidated(isNetworkValidated)
2102                                     .build();
2103                     tunnelConfig
2104                             .getTunnelCallback()
2105                             .onOpened(apnName, linkProperties, onOpenedMetrics);
2106 
2107                     reportIwlanError(apnName, new IwlanError(IwlanError.NO_ERROR));
2108                     mEpdgSelector.onEpdgConnectedSuccessfully();
2109 
2110                     mEpdgMonitor.onApnConnectToEpdg(apnName, tunnelConfig.getEpdgAddress());
2111                     onConnectedToEpdg(true);
2112                     mValidEpdgInfo.resetIndex();
2113                     printRequestQueue("EVENT_CHILD_SESSION_OPENED");
2114                     serviceAllPendingRequests();
2115                     tunnelConfig.setIkeSessionState(IkeSessionState.CHILD_SESSION_OPENED);
2116                     break;
2117 
2118                 case EVENT_IKE_SESSION_CLOSED:
2119                     printRequestQueue("EVENT_IKE_SESSION_CLOSED");
2120                     SessionClosedData sessionClosedData = (SessionClosedData) msg.obj;
2121                     apnName = sessionClosedData.mApnName;
2122 
2123                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2124                     if (tunnelConfig == null) {
2125                         Log.e(TAG, "No callback found for apn: " + apnName);
2126                         return;
2127                     }
2128 
2129                     // If IKE session closed exceptionally, we retrieve IwlanError directly from the
2130                     // exception; otherwise, it is still possible that we triggered an IKE session
2131                     // close due to an error (e.g. IwlanError.TUNNEL_TRANSFORM_FAILED), or because
2132                     // the Child session closed exceptionally; in which case, we attempt to retrieve
2133                     // the stored error (if any) from TunnelConfig.
2134                     IwlanError iwlanError;
2135                     if (sessionClosedData.mIkeException != null) {
2136                         iwlanError =
2137                                 getErrorFromIkeException(
2138                                         sessionClosedData.mIkeException,
2139                                         tunnelConfig.getIkeSessionState());
2140                     } else {
2141                         // If IKE session opened, then closed before child session (and IWLAN
2142                         // tunnel) opened.
2143                         // Iwlan reports IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED
2144                         // instead of NO_ERROR
2145                         if (!tunnelConfig.hasTunnelOpened()) {
2146                             int errorType =
2147                                     IwlanError.IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED;
2148                             iwlanError = new IwlanError(errorType);
2149                         } else {
2150                             iwlanError = tunnelConfig.getError();
2151                         }
2152                     }
2153 
2154                     IpSecManager.IpSecTunnelInterface iface = tunnelConfig.getIface();
2155                     if (iface != null) {
2156                         iface.close();
2157                     }
2158 
2159                     if (!tunnelConfig.hasTunnelOpened()) {
2160                         if (tunnelConfig.isBackoffTimeValid()) {
2161                             reportIwlanError(apnName, iwlanError, tunnelConfig.getBackoffTime());
2162                         } else {
2163                             reportIwlanError(apnName, iwlanError);
2164                         }
2165                         mEpdgMonitor.onEpdgConnectionFailed(
2166                                 tunnelConfig.isEmergency(), tunnelConfig.getEpdgAddress());
2167                         if (sessionClosedData.mIkeException != null) {
2168                             mEpdgSelector.onEpdgConnectionFailed(
2169                                     tunnelConfig.getEpdgAddress(), sessionClosedData.mIkeException);
2170                         }
2171                     } else {
2172                         /* PDN disconnected case */
2173                         triggerUnderlyingNetworkValidationOnError(iwlanError);
2174                     }
2175 
2176                     Log.d(TAG, "Tunnel Closed: " + iwlanError);
2177                     tunnelConfig.setIkeSessionState(IkeSessionState.NO_IKE_SESSION);
2178 
2179                     onClosedMetricsBuilder = new OnClosedMetrics.Builder().setApnName(apnName);
2180                     if (!mEpdgMonitor.hasEpdgConnected()) {
2181                         failAllPendingRequests(iwlanError);
2182                     } else {
2183                         mIkeTunnelEstablishmentDuration =
2184                                 mIkeTunnelEstablishmentStartTime > 0
2185                                         ? System.currentTimeMillis()
2186                                                 - mIkeTunnelEstablishmentStartTime
2187                                         : 0;
2188                         mIkeTunnelEstablishmentStartTime = 0;
2189 
2190                         isNetworkValidated = isUnderlyingNetworkValidated(mIkeSessionNetwork);
2191                         onClosedMetricsBuilder
2192                                 .setEpdgServerAddress(tunnelConfig.getEpdgAddress())
2193                                 .setEpdgServerSelectionDuration((int) mEpdgServerSelectionDuration)
2194                                 .setIkeTunnelEstablishmentDuration(
2195                                         (int) mIkeTunnelEstablishmentDuration)
2196                                 .setIsNetworkValidated(isNetworkValidated);
2197                     }
2198                     tunnelConfig
2199                             .getTunnelCallback()
2200                             .onClosed(apnName, iwlanError, onClosedMetricsBuilder.build());
2201 
2202                     mApnNameToTunnelConfig.remove(apnName);
2203                     mEpdgMonitor.onApnDisconnectFromEpdg(apnName);
2204                     if (mApnNameToTunnelConfig.isEmpty() && mPendingBringUpRequests.isEmpty()) {
2205                         onConnectedToEpdg(false);
2206                     }
2207                     break;
2208 
2209                 case EVENT_UPDATE_NETWORK:
2210                     UpdateNetworkWrapper updatedNetwork = (UpdateNetworkWrapper) msg.obj;
2211                     mDefaultNetwork = updatedNetwork.getNetwork();
2212                     LinkProperties defaultLinkProperties = updatedNetwork.getLinkProperties();
2213                     String paraString = "Network: " + mDefaultNetwork;
2214 
2215                     if (mEpdgMonitor.hasEpdgConnected()) {
2216                         if (Objects.isNull(mDefaultNetwork)) {
2217                             Log.w(TAG, "The default network has been removed.");
2218                         } else if (Objects.isNull(defaultLinkProperties)) {
2219                             Log.w(
2220                                     TAG,
2221                                     "The default network's LinkProperties is not ready ."
2222                                             + paraString);
2223                         } else if (Objects.equals(mDefaultNetwork, mIkeSessionNetwork)) {
2224                             Log.w(
2225                                     TAG,
2226                                     "The default network has not changed from the IKE session"
2227                                             + " network. "
2228                                             + paraString);
2229                         } else {
2230                             for (var entry : mApnNameToTunnelConfig.entrySet()) {
2231                                 String apn = entry.getKey();
2232                                 TunnelConfig config = entry.getValue();
2233                                 if (!defaultLinkProperties.isReachable(config.getEpdgAddress())) {
2234                                     Log.w(
2235                                             TAG,
2236                                             "The default network link "
2237                                                     + defaultLinkProperties
2238                                                     + " doesn't have a route to the ePDG "
2239                                                     + config.getEpdgAddress()
2240                                                     + paraString);
2241                                 } else {
2242                                     Log.d(
2243                                             TAG,
2244                                             "The Underlying Network is updating for APN (+"
2245                                                     + apn
2246                                                     + "). "
2247                                                     + paraString);
2248                                     config.getIkeSession().setNetwork(mDefaultNetwork);
2249                                     config.setIkeSessionState(
2250                                             IkeSessionState.IKE_MOBILITY_IN_PROGRESS);
2251                                     mIkeSessionNetwork = mDefaultNetwork;
2252                                 }
2253                             }
2254                         }
2255                     }
2256                     break;
2257 
2258                 case EVENT_TUNNEL_BRINGDOWN_REQUEST:
2259                     TunnelBringdownRequest bringdownRequest = (TunnelBringdownRequest) msg.obj;
2260                     apnName = bringdownRequest.mApnName;
2261                     boolean forceClose = bringdownRequest.mForceClose;
2262                     int reason = bringdownRequest.mBringDownReason;
2263                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2264                     if (tunnelConfig == null) {
2265                         Log.w(
2266                                 TAG,
2267                                 "Bringdown request: No tunnel exists for apn: "
2268                                         + apnName
2269                                         + ", forced: "
2270                                         + forceClose
2271                                         + ", bringdown reason: "
2272                                         + bringdownReasonToString(reason));
2273                     } else {
2274                         if (forceClose) {
2275                             tunnelConfig.getIkeSession().kill();
2276                         } else {
2277                             tunnelConfig.getIkeSession().close();
2278                         }
2279                     }
2280                     // TODO(b/309867892): Include tunnel bring down reason in metrics.
2281                     int numClosed = closePendingRequestsForApn(apnName);
2282                     if (numClosed > 0) {
2283                         Log.d(
2284                                 TAG,
2285                                 "Closed "
2286                                         + numClosed
2287                                         + " pending requests for apn: "
2288                                         + apnName
2289                                         + ", bringdown reason: "
2290                                         + bringdownReasonToString(reason));
2291                     }
2292                     if (tunnelConfig == null && numClosed == 0) {
2293                         // IwlanDataService expected to close a (pending or up) tunnel but was not
2294                         // found. Recovers state in IwlanDataService through TunnelCallback.
2295                         iwlanError = new IwlanError(IwlanError.TUNNEL_NOT_FOUND);
2296                         reportIwlanError(apnName, iwlanError);
2297                         bringdownRequest.mTunnelCallback.onClosed(
2298                                 apnName,
2299                                 iwlanError,
2300                                 new OnClosedMetrics.Builder().setApnName(apnName).build());
2301                     }
2302                     break;
2303 
2304                 case EVENT_IPSEC_TRANSFORM_CREATED:
2305                     IpsecTransformData transformData = (IpsecTransformData) msg.obj;
2306                     apnName = transformData.getApnName();
2307                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2308 
2309                     try {
2310                         mIpSecManager.applyTunnelModeTransform(
2311                                 tunnelConfig.getIface(),
2312                                 transformData.getDirection(),
2313                                 transformData.getTransform());
2314                     } catch (IOException | IllegalArgumentException e) {
2315                         // If the IKE session was closed before the transform could be applied, the
2316                         // IpSecService will throw an IAE on processing the IpSecTunnelInterface id.
2317                         Log.e(TAG, "Failed to apply tunnel transform." + e);
2318                         closeIkeSession(
2319                                 apnName, new IwlanError(IwlanError.TUNNEL_TRANSFORM_FAILED));
2320                     }
2321                     mApnNameToIpsecTransform.put(apnName, transformData);
2322                     if (tunnelConfig.getIkeSessionState()
2323                             == IkeSessionState.IKE_MOBILITY_IN_PROGRESS) {
2324                         tunnelConfig.setIkeSessionState(IkeSessionState.CHILD_SESSION_OPENED);
2325                     }
2326                     break;
2327 
2328                 case EVENT_IPSEC_TRANSFORM_DELETED:
2329                     transformData = (IpsecTransformData) msg.obj;
2330                     IpSecTransform transform = transformData.getTransform();
2331                     transform.close();
2332                     mApnNameToIpsecTransform.remove(transformData.getApnName());
2333                     break;
2334 
2335                 case EVENT_CHILD_SESSION_CLOSED:
2336                     sessionClosedData = (SessionClosedData) msg.obj;
2337                     apnName = sessionClosedData.mApnName;
2338 
2339                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2340                     if (tunnelConfig == null) {
2341                         Log.d(TAG, "No tunnel callback for apn: " + apnName);
2342                         return;
2343                     }
2344                     if (sessionClosedData.mIkeException != null) {
2345                         tunnelConfig.setError(
2346                                 getErrorFromIkeException(
2347                                         sessionClosedData.mIkeException,
2348                                         tunnelConfig.getIkeSessionState()));
2349                     }
2350                     tunnelConfig.getIkeSession().close();
2351                     break;
2352 
2353                 case EVENT_IKE_SESSION_OPENED:
2354                     IkeSessionOpenedData ikeSessionOpenedData = (IkeSessionOpenedData) msg.obj;
2355                     apnName = ikeSessionOpenedData.mApnName;
2356                     IkeSessionConfiguration sessionConfiguration =
2357                             ikeSessionOpenedData.mIkeSessionConfiguration;
2358 
2359                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2360                     tunnelConfig.setPcscfAddrList(sessionConfiguration.getPcscfServers());
2361 
2362                     boolean enabledFastReauth =
2363                             IwlanCarrierConfig.getConfigBoolean(
2364                                     mContext,
2365                                     mSlotId,
2366                                     CarrierConfigManager.Iwlan
2367                                             .KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL);
2368                     Log.d(
2369                             TAG,
2370                             "CarrierConfigManager.Iwlan.KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL "
2371                                     + enabledFastReauth);
2372 
2373                     if (enabledFastReauth) {
2374                         EapInfo eapInfo = sessionConfiguration.getEapInfo();
2375                         if (eapInfo instanceof EapAkaInfo eapAkaInfo) {
2376                             mNextReauthId = eapAkaInfo.getReauthId();
2377                             Log.d(TAG, "Update ReauthId: " + Arrays.toString(mNextReauthId));
2378                         } else {
2379                             mNextReauthId = null;
2380                         }
2381                     }
2382                     break;
2383 
2384                 case EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED:
2385                     IkeSessionConnectionInfoData ikeSessionConnectionInfoData =
2386                             (IkeSessionConnectionInfoData) msg.obj;
2387                     Network network =
2388                             ikeSessionConnectionInfoData.mIkeSessionConnectionInfo.getNetwork();
2389                     apnName = ikeSessionConnectionInfoData.mApnName;
2390 
2391                     connectivityManager = mContext.getSystemService(ConnectivityManager.class);
2392                     if (Objects.requireNonNull(connectivityManager).getLinkProperties(network)
2393                             == null) {
2394                         Log.e(TAG, "Network " + network + " has null LinkProperties!");
2395                         return;
2396                     }
2397 
2398                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2399                     tunnelInterface = tunnelConfig.getIface();
2400                     try {
2401                         tunnelInterface.setUnderlyingNetwork(network);
2402                     } catch (IOException | IllegalArgumentException e) {
2403                         Log.e(
2404                                 TAG,
2405                                 "Failed to update underlying network for apn: "
2406                                         + apnName
2407                                         + " exception: "
2408                                         + e);
2409                     }
2410                     break;
2411 
2412                 case EVENT_IKE_3GPP_DATA_RECEIVED:
2413                     Ike3gppDataReceived ike3gppDataReceived = (Ike3gppDataReceived) msg.obj;
2414                     apnName = ike3gppDataReceived.mApnName;
2415                     List<Ike3gppData> ike3gppData = ike3gppDataReceived.mIke3gppData;
2416                     if (ike3gppData != null && !ike3gppData.isEmpty()) {
2417                         tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2418                         for (Ike3gppData payload : ike3gppData) {
2419                             if (payload.getDataType() == DATA_TYPE_NOTIFY_N1_MODE_INFORMATION) {
2420                                 Log.d(TAG, "Got payload DATA_TYPE_NOTIFY_N1_MODE_INFORMATION");
2421                                 NetworkSliceInfo si =
2422                                         NetworkSliceSelectionAssistanceInformation.getSliceInfo(
2423                                                 ((Ike3gppN1ModeInformation) payload).getSnssai());
2424                                 if (si != null) {
2425                                     tunnelConfig.setSliceInfo(si);
2426                                     Log.d(TAG, "SliceInfo: " + si);
2427                                 }
2428                             } else if (payload.getDataType() == DATA_TYPE_NOTIFY_BACKOFF_TIMER) {
2429                                 Log.d(TAG, "Got payload DATA_TYPE_NOTIFY_BACKOFF_TIMER");
2430                                 long backoffTime =
2431                                         decodeBackoffTime(
2432                                                 ((Ike3gppBackoffTimer) payload).getBackoffTimer());
2433                                 if (backoffTime > 0) {
2434                                     tunnelConfig.setBackoffTime(backoffTime);
2435                                     Log.d(TAG, "Backoff Timer: " + backoffTime);
2436                                 }
2437                             }
2438                         }
2439                     } else {
2440                         Log.e(TAG, "Null or empty payloads received:");
2441                     }
2442                     break;
2443 
2444                 case EVENT_IKE_LIVENESS_STATUS_CHANGED:
2445                     IkeSessionValidationStatusData ikeLivenessData =
2446                             (IkeSessionValidationStatusData) msg.obj;
2447                     @NetworkValidationStatus int validationStatus = ikeLivenessData.mStatus;
2448                     apnName = ikeLivenessData.mApnName;
2449                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2450                     if (tunnelConfig == null) {
2451                         Log.e(TAG, "No tunnel config found for apn: " + apnName);
2452                         return;
2453                     }
2454                     tunnelConfig
2455                             .getTunnelCallback()
2456                             .onNetworkValidationStatusChanged(apnName, validationStatus);
2457                     break;
2458 
2459                 case EVENT_REQUEST_NETWORK_VALIDATION_CHECK:
2460                     apnName = (String) msg.obj;
2461                     tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2462                     if (tunnelConfig == null) {
2463                         Log.e(TAG, "No tunnel config found for apn: " + apnName);
2464                         return;
2465                     }
2466                     tunnelConfig.getIkeSession().requestLivenessCheck();
2467                     break;
2468 
2469                 default:
2470                     throw new IllegalStateException("Unexpected value: " + msg.what);
2471             }
2472         }
2473 
2474         private void handleTunnelBringUpRequest(TunnelRequestWrapper tunnelRequestWrapper) {
2475             TunnelSetupRequest setupRequest = tunnelRequestWrapper.getSetupRequest();
2476             String apnName = setupRequest.apnName();
2477 
2478             IwlanError bringUpError = canBringUpTunnel(apnName, setupRequest.isEmergency());
2479             if (Objects.nonNull(bringUpError)) {
2480                 tunnelRequestWrapper
2481                         .getTunnelCallback()
2482                         .onClosed(
2483                                 apnName,
2484                                 bringUpError,
2485                                 new OnClosedMetrics.Builder().setApnName(apnName).build());
2486                 return;
2487             }
2488             serviceTunnelBringUpRequest(tunnelRequestWrapper);
2489         }
2490 
2491         private void serviceTunnelBringUpRequest(TunnelRequestWrapper tunnelRequestWrapper) {
2492             if (mEpdgMonitor.hasEpdgConnected()) {
2493                 InetAddress epdgAddress = selectConnectedEpdgForTunnelBringUp(tunnelRequestWrapper);
2494                 if (epdgAddress != null) {
2495                     onBringUpTunnel(tunnelRequestWrapper, epdgAddress);
2496                     return;
2497                 }
2498             }
2499 
2500             if (!isEpdgSelectionOrFirstTunnelBringUpInProgress()) {
2501                 // No tunnel bring-up in progress Or emergency request has attempted ePDG for normal
2502                 // session but failed, select the ePDG address.
2503                 selectEpdgAddress(tunnelRequestWrapper.getSetupRequest());
2504             }
2505 
2506             // Another bring-up or ePDG selection is in progress, pending this request.
2507             mPendingBringUpRequests.add(tunnelRequestWrapper);
2508         }
2509 
2510         private InetAddress selectConnectedEpdgForTunnelBringUp(
2511                 TunnelRequestWrapper tunnelRequestWrapper) {
2512             if (!mFeatureFlags.distinctEpdgSelectionForEmergencySessions()
2513                     || !IwlanCarrierConfig.getConfigBoolean(
2514                             mContext,
2515                             mSlotId,
2516                             IwlanCarrierConfig.KEY_DISTINCT_EPDG_FOR_EMERGENCY_ALLOWED_BOOL)) {
2517                 // Attempt on ePDG for normal session since feature not enabled
2518                 return mEpdgMonitor.getEpdgAddressForNormalSession();
2519             }
2520 
2521             if (!tunnelRequestWrapper.getSetupRequest().isEmergency()) {
2522                 if (mEpdgMonitor.hasSeparateEpdgConnectedForEmergencySession()) {
2523                     // Attempt on ePDG for emergency session
2524                     return mEpdgMonitor.getEpdgAddressForEmergencySession();
2525                 } else {
2526                     // Attempt on ePDG for normal session.
2527                     return mEpdgMonitor.getEpdgAddressForNormalSession();
2528                 }
2529             }
2530 
2531             if (!mEpdgMonitor.hasEmergencyPdnFailedWithConnectedEpdg()) {
2532                 // First emergnecy attempt on ePDG for normal session.
2533                 return mEpdgMonitor.getEpdgAddressForNormalSession();
2534             }
2535             return null; // no suitable ePDG address found. Select new ePDG address needed.
2536         }
2537 
2538         TmHandler(Looper looper) {
2539             super(looper);
2540         }
2541     }
2542 
2543     private void closeIkeSession(String apnName, IwlanError error) {
2544         TunnelConfig tunnelConfig = mApnNameToTunnelConfig.get(apnName);
2545         tunnelConfig.setError(error);
2546         tunnelConfig.getIkeSession().close();
2547     }
2548 
2549     private void selectEpdgAddress(TunnelSetupRequest setupRequest) {
2550         ++mTransactionId;
2551         mEpdgServerSelectionStartTime = System.currentTimeMillis();
2552 
2553         final int ipPreference =
2554                 IwlanCarrierConfig.getConfigInt(
2555                         mContext,
2556                         mSlotId,
2557                         CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_IP_TYPE_PREFERENCE_INT);
2558 
2559         IpPreferenceConflict ipPreferenceConflict =
2560                 isIpPreferenceConflictsWithNetwork(ipPreference);
2561         if (ipPreferenceConflict.mIsConflict) {
2562             sendSelectionRequestComplete(
2563                     null, new IwlanError(ipPreferenceConflict.mErrorType), mTransactionId);
2564             return;
2565         }
2566 
2567         int protoFilter = EpdgSelector.PROTO_FILTER_IPV4V6;
2568         int epdgAddressOrder = EpdgSelector.SYSTEM_PREFERRED;
2569         switch (ipPreference) {
2570             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_IPV4_PREFERRED:
2571                 epdgAddressOrder = EpdgSelector.IPV4_PREFERRED;
2572                 break;
2573             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_IPV6_PREFERRED:
2574                 epdgAddressOrder = EpdgSelector.IPV6_PREFERRED;
2575                 break;
2576             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_IPV4_ONLY:
2577                 protoFilter = EpdgSelector.PROTO_FILTER_IPV4;
2578                 break;
2579             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_IPV6_ONLY:
2580                 protoFilter = EpdgSelector.PROTO_FILTER_IPV6;
2581                 break;
2582             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_SYSTEM_PREFERRED:
2583                 break;
2584             default:
2585                 Log.w(TAG, "Invalid Ip preference : " + ipPreference);
2586         }
2587 
2588         IwlanError epdgError =
2589                 mEpdgSelector.getValidatedServerList(
2590                         mTransactionId,
2591                         protoFilter,
2592                         epdgAddressOrder,
2593                         setupRequest.isRoaming(),
2594                         setupRequest.isEmergency(),
2595                         mDefaultNetwork,
2596                         mSelectorCallback);
2597 
2598         if (epdgError.getErrorType() != IwlanError.NO_ERROR) {
2599             Log.e(TAG, "Epdg address selection failed with error:" + epdgError);
2600             sendSelectionRequestComplete(null, epdgError, mTransactionId);
2601         }
2602     }
2603 
2604     @VisibleForTesting
2605     int closePendingRequestsForApn(String apnName) {
2606         int numRequestsClosed = 0;
2607         int queueSize = mPendingBringUpRequests.size();
2608         if (queueSize == 0) {
2609             return numRequestsClosed;
2610         }
2611 
2612         for (int count = 0; count < queueSize; count++) {
2613             TunnelRequestWrapper requestWrapper = mPendingBringUpRequests.remove();
2614             if (requestWrapper.getSetupRequest().apnName().equals(apnName)) {
2615                 requestWrapper
2616                         .getTunnelCallback()
2617                         .onClosed(
2618                                 apnName,
2619                                 new IwlanError(IwlanError.NO_ERROR),
2620                                 new OnClosedMetrics.Builder()
2621                                         .setApnName(apnName)
2622                                         .setEpdgServerAddress(null)
2623                                         .build());
2624                 numRequestsClosed++;
2625             } else {
2626                 mPendingBringUpRequests.add(requestWrapper);
2627             }
2628         }
2629         return numRequestsClosed;
2630     }
2631 
2632     InetAddress validateAndSetEpdgAddressLegacy(List<InetAddress> selectorResultList) {
2633         List<InetAddress> addrList = mValidEpdgInfo.getAddrList();
2634         if (addrList == null || !addrList.equals(selectorResultList)) {
2635             Log.d(TAG, "Update ePDG address list.");
2636             mValidEpdgInfo.setAddrList(selectorResultList);
2637             addrList = mValidEpdgInfo.getAddrList();
2638         }
2639 
2640         int index = mValidEpdgInfo.getIndex();
2641         Log.d(
2642                 TAG,
2643                 "Valid ePDG Address List: "
2644                         + Arrays.toString(addrList.toArray())
2645                         + ", index = "
2646                         + index);
2647         mValidEpdgInfo.incrementIndex();
2648         return addrList.get(index);
2649     }
2650 
2651     @VisibleForTesting
2652     InetAddress validateAndSetEpdgAddress(List<InetAddress> selectorResultList) {
2653         if (!mFeatureFlags.epdgSelectionExcludeFailedIpAddress()) {
2654             return validateAndSetEpdgAddressLegacy(selectorResultList);
2655         }
2656 
2657         if (mEpdgMonitor.hasEmergencyPdnFailedWithConnectedEpdg()
2658                 && selectorResultList
2659                         .get(0)
2660                         .equals(mEpdgMonitor.getEpdgAddressForNormalSession())) {
2661             List<InetAddress> sublist = selectorResultList.subList(1, selectorResultList.size());
2662             Log.d(
2663                     TAG,
2664                     "Selected separate ePDG address for emergency session "
2665                             + sublist.get(0)
2666                             + " from available ePDG address list: "
2667                             + Arrays.toString(selectorResultList.toArray()));
2668             mValidEpdgInfo.setAddrList(sublist);
2669             return sublist.get(0);
2670         }
2671 
2672         Log.d(
2673                 TAG,
2674                 "Selected first ePDG address "
2675                         + selectorResultList.get(0)
2676                         + " from available ePDG address list: "
2677                         + Arrays.toString(selectorResultList.toArray()));
2678         mValidEpdgInfo.setAddrList(selectorResultList);
2679         return selectorResultList.get(0);
2680     }
2681 
2682     private void serviceAllPendingRequests() {
2683         while (!mPendingBringUpRequests.isEmpty()) {
2684             Log.d(TAG, "serviceAllPendingRequests");
2685             TunnelRequestWrapper requestWrapper = mPendingBringUpRequests.remove();
2686             onBringUpTunnel(requestWrapper, mEpdgMonitor.getEpdgAddressForNormalSession());
2687         }
2688     }
2689 
2690     private void failAllPendingRequests(IwlanError error) {
2691         while (!mPendingBringUpRequests.isEmpty()) {
2692             Log.d(TAG, "failAllPendingRequests");
2693             TunnelRequestWrapper request = mPendingBringUpRequests.remove();
2694             TunnelSetupRequest setupRequest = request.getSetupRequest();
2695             String apnName = setupRequest.apnName();
2696             reportIwlanError(apnName, error);
2697             request.getTunnelCallback()
2698                     .onClosed(
2699                             apnName,
2700                             error,
2701                             new OnClosedMetrics.Builder()
2702                                     .setApnName(apnName)
2703                                     .setEpdgServerAddress(null)
2704                                     .build());
2705         }
2706     }
2707 
2708     // Prints mPendingBringUpRequests
2709     private void printRequestQueue(String info) {
2710         Log.d(TAG, info);
2711         Log.d(
2712                 TAG,
2713                 "mPendingBringUpRequests: " + Arrays.toString(mPendingBringUpRequests.toArray()));
2714     }
2715 
2716     // Update Network wrapper
2717     private static final class UpdateNetworkWrapper {
2718         private final Network mNetwork;
2719         private final LinkProperties mLinkProperties;
2720 
2721         private UpdateNetworkWrapper(Network network, LinkProperties linkProperties) {
2722             mNetwork = network;
2723             mLinkProperties = linkProperties;
2724         }
2725 
2726         public Network getNetwork() {
2727             return mNetwork;
2728         }
2729 
2730         public LinkProperties getLinkProperties() {
2731             return mLinkProperties;
2732         }
2733     }
2734 
2735     // Tunnel request + tunnel callback
2736     private static final class TunnelRequestWrapper {
2737         private final TunnelSetupRequest mSetupRequest;
2738         private final TunnelCallback mTunnelCallback;
2739 
2740         private TunnelRequestWrapper(
2741                 TunnelSetupRequest setupRequest, TunnelCallback tunnelCallback) {
2742             mTunnelCallback = tunnelCallback;
2743             mSetupRequest = setupRequest;
2744         }
2745 
2746         public TunnelSetupRequest getSetupRequest() {
2747             return mSetupRequest;
2748         }
2749 
2750         public TunnelCallback getTunnelCallback() {
2751             return mTunnelCallback;
2752         }
2753     }
2754 
2755     private static final class TunnelBringdownRequest {
2756         final String mApnName;
2757         final boolean mForceClose;
2758         final TunnelCallback mTunnelCallback;
2759         final int mBringDownReason;
2760 
2761         private TunnelBringdownRequest(
2762                 String apnName,
2763                 boolean forceClose,
2764                 TunnelCallback tunnelCallback,
2765                 @TunnelBringDownReason int reason) {
2766             mApnName = apnName;
2767             mForceClose = forceClose;
2768             mTunnelCallback = tunnelCallback;
2769             mBringDownReason = reason;
2770         }
2771     }
2772 
2773     private static final class EpdgSelectorResult {
2774         private final List<InetAddress> mValidIpList;
2775 
2776         public List<InetAddress> getValidIpList() {
2777             return mValidIpList;
2778         }
2779 
2780         public IwlanError getEpdgError() {
2781             return mEpdgError;
2782         }
2783 
2784         public int getTransactionId() {
2785             return mTransactionId;
2786         }
2787 
2788         private final IwlanError mEpdgError;
2789         private final int mTransactionId;
2790 
2791         private EpdgSelectorResult(
2792                 List<InetAddress> validIpList, IwlanError epdgError, int transactionId) {
2793             mValidIpList = validIpList;
2794             mEpdgError = epdgError;
2795             mTransactionId = transactionId;
2796         }
2797     }
2798 
2799     // Data received from IkeSessionStateMachine on successful EVENT_CHILD_SESSION_OPENED.
2800     private static final class TunnelOpenedData extends IkeEventData {
2801         final List<InetAddress> mInternalDnsServers;
2802         final List<LinkAddress> mInternalAddresses;
2803 
2804         private TunnelOpenedData(
2805                 String apnName,
2806                 int token,
2807                 List<InetAddress> internalDnsServers,
2808                 List<LinkAddress> internalAddresses) {
2809             super(apnName, token);
2810             mInternalDnsServers = internalDnsServers;
2811             mInternalAddresses = internalAddresses;
2812         }
2813     }
2814 
2815     // Data received from IkeSessionStateMachine on successful EVENT_IKE_SESSION_OPENED.
2816     private static final class IkeSessionOpenedData extends IkeEventData {
2817         final IkeSessionConfiguration mIkeSessionConfiguration;
2818 
2819         private IkeSessionOpenedData(
2820                 String apnName, int token, IkeSessionConfiguration ikeSessionConfiguration) {
2821             super(apnName, token);
2822             mIkeSessionConfiguration = ikeSessionConfiguration;
2823         }
2824     }
2825 
2826     private static final class IkeSessionConnectionInfoData extends IkeEventData {
2827         final IkeSessionConnectionInfo mIkeSessionConnectionInfo;
2828 
2829         private IkeSessionConnectionInfoData(
2830                 String apnName, int token, IkeSessionConnectionInfo ikeSessionConnectionInfo) {
2831             super(apnName, token);
2832             mIkeSessionConnectionInfo = ikeSessionConnectionInfo;
2833         }
2834     }
2835 
2836     private static final class Ike3gppDataReceived extends IkeEventData {
2837         final List<Ike3gppData> mIke3gppData;
2838 
2839         private Ike3gppDataReceived(String apnName, int token, List<Ike3gppData> ike3gppData) {
2840             super(apnName, token);
2841             mIke3gppData = ike3gppData;
2842         }
2843     }
2844 
2845     // Data received from IkeSessionStateMachine if either IKE session or Child session have been
2846     // closed, normally or exceptionally.
2847     private static final class SessionClosedData extends IkeEventData {
2848         final IkeException mIkeException;
2849 
2850         private SessionClosedData(String apnName, int token, IkeException ikeException) {
2851             super(apnName, token);
2852             mIkeException = ikeException;
2853         }
2854     }
2855 
2856     private static final class IkeSessionValidationStatusData extends IkeEventData {
2857         @NetworkValidationStatus final int mStatus;
2858 
2859         private IkeSessionValidationStatusData(String apnName, int token, int status) {
2860             super(apnName, token);
2861             mStatus = status;
2862         }
2863     }
2864 
2865     private static final class IpsecTransformData extends IkeEventData {
2866         private final IpSecTransform mTransform;
2867         private final int mDirection;
2868 
2869         private IpsecTransformData(
2870                 IpSecTransform transform, int direction, String apnName, int token) {
2871             super(apnName, token);
2872             mTransform = transform;
2873             mDirection = direction;
2874         }
2875 
2876         public IpSecTransform getTransform() {
2877             return mTransform;
2878         }
2879 
2880         public int getDirection() {
2881             return mDirection;
2882         }
2883 
2884         public String getApnName() {
2885             return super.mApnName;
2886         }
2887     }
2888 
2889     private abstract static class IkeEventData {
2890         final String mApnName;
2891         final int mToken;
2892 
2893         private IkeEventData(String apnName, int token) {
2894             mApnName = apnName;
2895             mToken = token;
2896         }
2897     }
2898 
2899     private static final class EpdgInfo {
2900         private List<InetAddress> mAddrList;
2901         private int mIndex;
2902 
2903         private EpdgInfo() {
2904             mAddrList = null;
2905             mIndex = 0;
2906         }
2907 
2908         public List<InetAddress> getAddrList() {
2909             return mAddrList;
2910         }
2911 
2912         public void setAddrList(@NonNull List<InetAddress> AddrList) {
2913             mAddrList = AddrList;
2914             resetIndex();
2915         }
2916 
2917         public int getIndex() {
2918             return mIndex;
2919         }
2920 
2921         public void incrementIndex() {
2922             if (getIndex() >= getAddrList().size() - 1) {
2923                 resetIndex();
2924             } else {
2925                 mIndex++;
2926             }
2927         }
2928 
2929         public void resetIndex() {
2930             mIndex = 0;
2931         }
2932     }
2933 
2934     private static class IpPreferenceConflict {
2935         final boolean mIsConflict;
2936         final int mErrorType;
2937 
2938         private IpPreferenceConflict(boolean isConflict, int errorType) {
2939             mIsConflict = isConflict;
2940             mErrorType = errorType;
2941         }
2942 
2943         private IpPreferenceConflict() {
2944             mIsConflict = false;
2945             mErrorType = IwlanError.NO_ERROR;
2946         }
2947     }
2948 
2949     private int[] getRetransmissionTimeoutsFromConfig() {
2950         int[] timeList =
2951                 IwlanCarrierConfig.getConfigIntArray(
2952                         mContext,
2953                         mSlotId,
2954                         CarrierConfigManager.Iwlan.KEY_RETRANSMIT_TIMER_MSEC_INT_ARRAY);
2955         boolean isValid =
2956                 timeList != null
2957                         && timeList.length != 0
2958                         && timeList.length <= IKE_RETRANS_MAX_ATTEMPTS_MAX;
2959         for (int time : Objects.requireNonNull(timeList)) {
2960             if (time < IKE_RETRANS_TIMEOUT_MS_MIN || time > IKE_RETRANS_TIMEOUT_MS_MAX) {
2961                 isValid = false;
2962                 break;
2963             }
2964         }
2965         if (!isValid) {
2966             timeList =
2967                     IwlanCarrierConfig.getDefaultConfigIntArray(
2968                             CarrierConfigManager.Iwlan.KEY_RETRANSMIT_TIMER_MSEC_INT_ARRAY);
2969         }
2970         Log.d(TAG, "getRetransmissionTimeoutsFromConfig: " + Arrays.toString(timeList));
2971         return timeList;
2972     }
2973 
2974     private int getDpdDelayFromConfig() {
2975         int dpdDelay =
2976                 IwlanCarrierConfig.getConfigInt(
2977                         mContext, mSlotId, CarrierConfigManager.Iwlan.KEY_DPD_TIMER_SEC_INT);
2978         if (dpdDelay < IKE_DPD_DELAY_SEC_MIN || dpdDelay > IKE_DPD_DELAY_SEC_MAX) {
2979             dpdDelay =
2980                     IwlanCarrierConfig.getDefaultConfigInt(
2981                             CarrierConfigManager.Iwlan.KEY_DPD_TIMER_SEC_INT);
2982         }
2983         return dpdDelay;
2984     }
2985 
2986     /**
2987      * Decodes backoff time as per TS 124 008 10.5.7.4a Bits 5 to 1 represent the binary coded timer
2988      * value
2989      *
2990      * <p>Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: Bits 8 7 6 0 0 0
2991      * value is incremented in multiples of 10 minutes 0 0 1 value is incremented in multiples of 1
2992      * hour 0 1 0 value is incremented in multiples of 10 hours 0 1 1 value is incremented in
2993      * multiples of 2 seconds 1 0 0 value is incremented in multiples of 30 seconds 1 0 1 value is
2994      * incremented in multiples of 1 minute 1 1 0 value is incremented in multiples of 1 hour 1 1 1
2995      * value indicates that the timer is deactivated.
2996      *
2997      * @param backoffTimeByte Byte value obtained from ike
2998      * @return long time value in seconds. -1 if the timer needs to be deactivated.
2999      */
3000     private static long decodeBackoffTime(byte backoffTimeByte) {
3001         final int BACKOFF_TIME_VALUE_MASK = 0x1F;
3002         final int BACKOFF_TIMER_UNIT_MASK = 0xE0;
3003         final Long[] BACKOFF_TIMER_UNIT_INCREMENT_SECS = {
3004             10L * 60L, // 10 minutes
3005             60L * 60L, // 1 hour
3006             10L * 60L * 60L, // 10 hours
3007             2L, // 2 seconds
3008             30L, // 30 seconds
3009             60L, // 1 minute
3010             60L * 60L, // 1 hour
3011         };
3012 
3013         long time = backoffTimeByte & BACKOFF_TIME_VALUE_MASK;
3014         int timerUnit = (backoffTimeByte & BACKOFF_TIMER_UNIT_MASK) >> 5;
3015         if (timerUnit >= BACKOFF_TIMER_UNIT_INCREMENT_SECS.length) {
3016             return -1;
3017         }
3018         time *= BACKOFF_TIMER_UNIT_INCREMENT_SECS[timerUnit];
3019         return time;
3020     }
3021 
3022     @VisibleForTesting
3023     String getTunnelSetupRequestApnName(TunnelSetupRequest setupRequest) {
3024         return setupRequest.apnName();
3025     }
3026 
3027     @VisibleForTesting
3028     void putApnNameToTunnelConfig(
3029             String apnName,
3030             IkeSession ikeSession,
3031             TunnelCallback tunnelCallback,
3032             IpSecManager.IpSecTunnelInterface iface,
3033             InetAddress srcIpv6Addr,
3034             int srcIPv6AddrPrefixLen,
3035             boolean isEmergency,
3036             InetAddress epdgAddress) {
3037         mApnNameToTunnelConfig.put(
3038                 apnName,
3039                 new TunnelConfig(
3040                         ikeSession,
3041                         tunnelCallback,
3042                         iface,
3043                         srcIpv6Addr,
3044                         srcIPv6AddrPrefixLen,
3045                         isEmergency,
3046                         epdgAddress));
3047         Log.d(TAG, "Added APN: " + apnName + " to TunnelConfig");
3048     }
3049 
3050     @VisibleForTesting
3051     int incrementAndGetCurrentTokenForApn(String apnName) {
3052         final int currentToken =
3053                 mApnNameToCurrentToken.compute(
3054                         apnName, (apn, token) -> token == null ? 0 : token + 1);
3055         Log.d(TAG, "Added token: " + currentToken + " for apn: " + apnName);
3056         return currentToken;
3057     }
3058 
3059     @VisibleForTesting
3060     boolean isTunnelConfigContainExistApn(String apnName) {
3061         return mApnNameToTunnelConfig.containsKey(apnName);
3062     }
3063 
3064     @VisibleForTesting
3065     List<InetAddress> getAddressForNetwork(Network network) {
3066         return IwlanHelper.getAllAddressesForNetwork(mContext, network);
3067     }
3068 
3069     @VisibleForTesting
3070     IkeSessionCreator getIkeSessionCreator() {
3071         return mIkeSessionCreator;
3072     }
3073 
3074     @VisibleForTesting
3075     void sendSelectionRequestComplete(
3076             List<InetAddress> validIPList, IwlanError result, int transactionId) {
3077         mEpdgServerSelectionDuration = System.currentTimeMillis() - mEpdgServerSelectionStartTime;
3078         mEpdgServerSelectionStartTime = 0;
3079         EpdgSelectorResult epdgSelectorResult =
3080                 new EpdgSelectorResult(validIPList, result, transactionId);
3081         mHandler.obtainMessage(EVENT_EPDG_ADDRESS_SELECTION_REQUEST_COMPLETE, epdgSelectorResult)
3082                 .sendToTarget();
3083     }
3084 
3085     static boolean isValidApnProtocol(int proto) {
3086         return (proto == ApnSetting.PROTOCOL_IP
3087                 || proto == ApnSetting.PROTOCOL_IPV4V6
3088                 || proto == ApnSetting.PROTOCOL_IPV6);
3089     }
3090 
3091     boolean isObsoleteToken(String apnName, int token) {
3092         if (!mApnNameToCurrentToken.containsKey(apnName)) {
3093             return true;
3094         }
3095         return token != mApnNameToCurrentToken.get(apnName);
3096     }
3097 
3098     private static String eventToString(int event) {
3099         return switch (event) {
3100             case EVENT_TUNNEL_BRINGUP_REQUEST -> "EVENT_TUNNEL_BRINGUP_REQUEST";
3101             case EVENT_TUNNEL_BRINGDOWN_REQUEST -> "EVENT_TUNNEL_BRINGDOWN_REQUEST";
3102             case EVENT_CHILD_SESSION_OPENED -> "EVENT_CHILD_SESSION_OPENED";
3103             case EVENT_CHILD_SESSION_CLOSED -> "EVENT_CHILD_SESSION_CLOSED";
3104             case EVENT_IKE_SESSION_CLOSED -> "EVENT_IKE_SESSION_CLOSED";
3105             case EVENT_EPDG_ADDRESS_SELECTION_REQUEST_COMPLETE ->
3106                     "EVENT_EPDG_ADDRESS_SELECTION_REQUEST_COMPLETE";
3107             case EVENT_IPSEC_TRANSFORM_CREATED -> "EVENT_IPSEC_TRANSFORM_CREATED";
3108             case EVENT_IPSEC_TRANSFORM_DELETED -> "EVENT_IPSEC_TRANSFORM_DELETED";
3109             case EVENT_UPDATE_NETWORK -> "EVENT_UPDATE_NETWORK";
3110             case EVENT_IKE_SESSION_OPENED -> "EVENT_IKE_SESSION_OPENED";
3111             case EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED ->
3112                     "EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED";
3113             case EVENT_IKE_3GPP_DATA_RECEIVED -> "EVENT_IKE_3GPP_DATA_RECEIVED";
3114             case EVENT_IKE_LIVENESS_STATUS_CHANGED -> "EVENT_IKE_LIVENESS_STATUS_CHANGED";
3115             case EVENT_REQUEST_NETWORK_VALIDATION_CHECK -> "EVENT_REQUEST_NETWORK_VALIDATION_CHECK";
3116             default -> "Unknown(" + event + ")";
3117         };
3118     }
3119 
3120     @VisibleForTesting
3121     TmIkeSessionCallback getTmIkeSessionCallback(String apnName, int token) {
3122         return new TmIkeSessionCallback(apnName, token);
3123     }
3124 
3125     @VisibleForTesting
3126     void onConnectedToEpdg(boolean hasConnected) {
3127         mHasConnectedToEpdg = hasConnected;
3128         if (mHasConnectedToEpdg) {
3129             mIkeSessionNetwork = mDefaultNetwork;
3130         } else {
3131             mIkeSessionNetwork = null;
3132         }
3133     }
3134 
3135     @VisibleForTesting
3136     TunnelConfig getTunnelConfigForApn(String apnName) {
3137         return mApnNameToTunnelConfig.get(apnName);
3138     }
3139 
3140     @VisibleForTesting
3141     int getCurrentTokenForApn(String apnName) {
3142         if (!mApnNameToCurrentToken.containsKey(apnName)) {
3143             throw new IllegalArgumentException("There is no token for apn: " + apnName);
3144         }
3145         return mApnNameToCurrentToken.get(apnName);
3146     }
3147 
3148     @VisibleForTesting
3149     long reportIwlanError(String apnName, IwlanError error) {
3150         triggerUnderlyingNetworkValidationOnError(error);
3151         return ErrorPolicyManager.getInstance(mContext, mSlotId).reportIwlanError(apnName, error);
3152     }
3153 
3154     @VisibleForTesting
3155     long reportIwlanError(String apnName, IwlanError error, long backOffTime) {
3156         triggerUnderlyingNetworkValidationOnError(error);
3157         return ErrorPolicyManager.getInstance(mContext, mSlotId)
3158                 .reportIwlanError(apnName, error, backOffTime);
3159     }
3160 
3161     @VisibleForTesting
3162     IwlanError getLastError(String apnName) {
3163         return ErrorPolicyManager.getInstance(mContext, mSlotId).getLastError(apnName);
3164     }
3165 
3166     @VisibleForTesting
3167     IwlanError canBringUpTunnel(String apnName, boolean isEmergency) {
3168         IwlanError bringUpError = null;
3169         if (IwlanHelper.getSubId(mContext, mSlotId)
3170                 == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
3171             Log.e(TAG, "SIM isn't ready");
3172             bringUpError = new IwlanError(IwlanError.SIM_NOT_READY_EXCEPTION);
3173             reportIwlanError(apnName, bringUpError);
3174         } else if (Objects.isNull(mDefaultNetwork)) {
3175             Log.e(TAG, "The default network is not ready");
3176             bringUpError = new IwlanError(IwlanError.IKE_INTERNAL_IO_EXCEPTION);
3177             reportIwlanError(apnName, bringUpError);
3178         } else if (!isEmergency
3179                 && !ErrorPolicyManager.getInstance(mContext, mSlotId).canBringUpTunnel(apnName)) {
3180             // TODO(b/343962773): Need to refactor emergency condition into ErrorPolicyManager
3181             Log.d(TAG, "Cannot bring up tunnel as retry time has not passed");
3182             bringUpError = getLastError(apnName);
3183         }
3184         return bringUpError;
3185     }
3186 
3187     @VisibleForTesting
3188     IpPreferenceConflict isIpPreferenceConflictsWithNetwork(
3189             @CarrierConfigManager.Iwlan.EpdgAddressIpPreference int ipPreference) {
3190         List<InetAddress> localAddresses = getAddressForNetwork(mDefaultNetwork);
3191         if (localAddresses == null || localAddresses.size() == 0) {
3192             Log.e(TAG, "No local addresses available for Network " + mDefaultNetwork);
3193             return new IpPreferenceConflict(true, IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED);
3194         } else if (!IwlanHelper.hasIpv6Address(localAddresses)
3195                 && ipPreference == CarrierConfigManager.Iwlan.EPDG_ADDRESS_IPV6_ONLY) {
3196             Log.e(
3197                     TAG,
3198                     "ePDG IP preference: "
3199                             + ipPreference
3200                             + " conflicts with source IP type: "
3201                             + EpdgSelector.PROTO_FILTER_IPV4);
3202             return new IpPreferenceConflict(true, IwlanError.EPDG_ADDRESS_ONLY_IPV6_ALLOWED);
3203         } else if (!IwlanHelper.hasIpv4Address(localAddresses)
3204                 && ipPreference == CarrierConfigManager.Iwlan.EPDG_ADDRESS_IPV4_ONLY) {
3205             // b/209938719 allows Iwlan to support VoWiFi for IPv4 ePDG server while on IPv6 WiFi.
3206             // Iwlan will receive a IPv4 address which is embedded in stacked IPv6 address. By using
3207             // this IPv4 address, UE will connect to IPv4 ePDG server through XLAT. However, there
3208             // are issues on connecting ePDG server through XLAT. Will allow IPV4_ONLY on IPv6 WiFi
3209             // after the issues are resolved.
3210             Log.e(
3211                     TAG,
3212                     "ePDG IP preference: "
3213                             + ipPreference
3214                             + " conflicts with source IP type: "
3215                             + EpdgSelector.PROTO_FILTER_IPV6);
3216             return new IpPreferenceConflict(true, IwlanError.EPDG_ADDRESS_ONLY_IPV4_ALLOWED);
3217         }
3218         return new IpPreferenceConflict();
3219     }
3220 
3221     private boolean isUnderlyingNetworkValidated(Network network) {
3222         if (network == null) return false;
3223 
3224         ConnectivityManager connectivityManager =
3225                 Objects.requireNonNull(mContext).getSystemService(ConnectivityManager.class);
3226         NetworkCapabilities networkCapabilities =
3227                 connectivityManager.getNetworkCapabilities(network);
3228         return (networkCapabilities != null)
3229                 && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
3230     }
3231 
3232     /**
3233      * Trigger network validation on the underlying network if needed to possibly update validation
3234      * status and cause system switch default network.
3235      */
3236     void triggerUnderlyingNetworkValidationOnError(IwlanError error) {
3237         if (!isUnderlyingNetworkValidationRequired(error.getErrorType())) {
3238             return;
3239         }
3240 
3241         Log.d(TAG, "On triggering underlying network validation. Cause: " + error);
3242         validateUnderlyingNetwork(IwlanCarrierConfig.NETWORK_VALIDATION_EVENT_NO_RESPONSE);
3243     }
3244 
3245     public void validateUnderlyingNetwork(@IwlanCarrierConfig.NetworkValidationEvent int event) {
3246         int[] networkValidationEvents =
3247                 IwlanCarrierConfig.getConfigIntArray(
3248                         mContext,
3249                         mSlotId,
3250                         IwlanCarrierConfig.KEY_UNDERLYING_NETWORK_VALIDATION_EVENTS_INT_ARRAY);
3251         if (Arrays.stream(networkValidationEvents)
3252                 .noneMatch(validationEvent -> validationEvent == event)) {
3253             return;
3254         }
3255         synchronized (sLastUnderlyingNetworkValidationLock) {
3256             long now = IwlanHelper.elapsedRealtime();
3257             // TODO (b/356791418): Consolidate underlying network handling into a single centralized
3258             //  subcomponent to prevent duplicate processing across different threads and classes
3259             //  . Until then, we will prevent sending duplicate network validations by checking
3260             //  the recent trigger time.
3261             if (now - sLastUnderlyingNetworkValidationMs > NETWORK_VALIDATION_MIN_INTERVAL_MS) {
3262                 sLastUnderlyingNetworkValidationMs = now;
3263                 Log.d(
3264                         TAG,
3265                         "On triggering underlying network validation. Event: "
3266                                 + IwlanCarrierConfig.getUnderlyingNetworkValidationEventString(
3267                                         event));
3268                 mHandler.post(() -> onTriggerUnderlyingNetworkValidation(event));
3269             }
3270         }
3271     }
3272 
3273     private void onTriggerUnderlyingNetworkValidation(int event) {
3274         if (mDefaultNetwork == null) return;
3275 
3276         setupValidationMetricsAtom(mDefaultNetwork, event);
3277 
3278         if (!isUnderlyingNetworkValidated(mDefaultNetwork)) {
3279             Log.d(TAG, "Network " + mDefaultNetwork + " is already not validated.");
3280             reportValidationMetricsAtom(
3281                     mDefaultNetwork,
3282                     NETWORK_VALIDATION_RESULT_INVALID,
3283                     /* validationTriggered */ false);
3284             return;
3285         }
3286 
3287         ConnectivityManager connectivityManager =
3288                 Objects.requireNonNull(mContext).getSystemService(ConnectivityManager.class);
3289         Log.d(TAG, "Trigger underlying network validation on network: " + mDefaultNetwork);
3290         Objects.requireNonNull(connectivityManager)
3291                 .reportNetworkConnectivity(mDefaultNetwork, false);
3292     }
3293 
3294     private void setupValidationMetricsAtom(@NonNull Network network, int event) {
3295         MetricsAtom metricsAtom = new MetricsAtom();
3296         metricsAtom.setMessageId(IwlanStatsLog.IWLAN_UNDERLYING_NETWORK_VALIDATION_RESULT_REPORTED);
3297         metricsAtom.setTriggerReason(getMetricsTriggerReason(event));
3298 
3299         ConnectivityManager connectivityManager =
3300                 Objects.requireNonNull(mContext).getSystemService(ConnectivityManager.class);
3301         NetworkCapabilities networkCapabilities =
3302                 Objects.requireNonNull(connectivityManager).getNetworkCapabilities(mDefaultNetwork);
3303         int validationTransportType = NETWORK_VALIDATION_TRANSPORT_TYPE_UNSPECIFIED;
3304         if (networkCapabilities != null) {
3305             if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
3306                 validationTransportType = NETWORK_VALIDATION_TRANSPORT_TYPE_CELLULAR;
3307             } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
3308                 validationTransportType = NETWORK_VALIDATION_TRANSPORT_TYPE_WIFI;
3309             }
3310         }
3311         metricsAtom.setValidationTransportType(validationTransportType);
3312 
3313         metricsAtom.setValidationStartTimeMills(IwlanHelper.elapsedRealtime());
3314         mMetricsAtomForNetwork.put(network, metricsAtom);
3315     }
3316 
3317     boolean isUnderlyingNetworkValidationRequired(int error) {
3318         return switch (error) {
3319             case IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED,
3320                             IwlanError.IKE_NETWORK_LOST_EXCEPTION,
3321                             IwlanError.IKE_INIT_TIMEOUT,
3322                             IwlanError.IKE_MOBILITY_TIMEOUT,
3323                             IwlanError.IKE_DPD_TIMEOUT ->
3324                     true;
3325             default -> false;
3326         };
3327     }
3328 
3329     private int getMetricsValidationResult(int validationResult) {
3330         return switch (validationResult) {
3331             case ConnectivityReport.NETWORK_VALIDATION_RESULT_INVALID ->
3332                     NETWORK_VALIDATION_RESULT_INVALID;
3333             case ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID ->
3334                     NETWORK_VALIDATION_RESULT_VALID;
3335             case ConnectivityReport.NETWORK_VALIDATION_RESULT_PARTIALLY_VALID ->
3336                     NETWORK_VALIDATION_RESULT_PARTIALLY_VALID;
3337             case ConnectivityReport.NETWORK_VALIDATION_RESULT_SKIPPED ->
3338                     NETWORK_VALIDATION_RESULT_SKIPPED;
3339             default -> NETWORK_VALIDATION_RESULT_UNSPECIFIED;
3340         };
3341     }
3342 
3343     private int getMetricsTriggerReason(int reason) {
3344         return switch (reason) {
3345             case IwlanCarrierConfig.NETWORK_VALIDATION_EVENT_MAKING_CALL ->
3346                     NETWORK_VALIDATION_EVENT_MAKING_CALL;
3347             case IwlanCarrierConfig.NETWORK_VALIDATION_EVENT_SCREEN_ON ->
3348                     NETWORK_VALIDATION_EVENT_SCREEN_ON;
3349             case IwlanCarrierConfig.NETWORK_VALIDATION_EVENT_NO_RESPONSE ->
3350                     NETWORK_VALIDATION_EVENT_NO_RESPONSE;
3351             default -> NETWORK_VALIDATION_EVENT_UNSPECIFIED;
3352         };
3353     }
3354 
3355     /**
3356      * Performs network validation check
3357      *
3358      * @param apnName APN for which to perform validation check
3359      */
3360     public void requestNetworkValidationForApn(String apnName) {
3361         mHandler.obtainMessage(EVENT_REQUEST_NETWORK_VALIDATION_CHECK, apnName).sendToTarget();
3362     }
3363 
3364     @VisibleForTesting
3365     protected void removeApnNameInTunnelConfig(String apnName) {
3366         mApnNameToTunnelConfig.remove(apnName);
3367     }
3368 
3369     public void prefetchEpdgServerList(Network network, boolean isRoaming) {
3370         mEpdgSelector.getValidatedServerList(
3371                 0 /* transactionId */,
3372                 EpdgSelector.PROTO_FILTER_IPV4V6,
3373                 EpdgSelector.SYSTEM_PREFERRED,
3374                 isRoaming,
3375                 false /* isEmergency */,
3376                 network,
3377                 null /* selectorCallback */);
3378         mEpdgSelector.getValidatedServerList(
3379                 0 /* transactionId */,
3380                 EpdgSelector.PROTO_FILTER_IPV4V6,
3381                 EpdgSelector.SYSTEM_PREFERRED,
3382                 isRoaming,
3383                 true /* isEmergency */,
3384                 network,
3385                 null /* selectorCallback */);
3386     }
3387 
3388     public void close() {
3389         mTunnelManagerInstances.remove(mSlotId);
3390         unregisterConnectivityDiagnosticsCallback();
3391     }
3392 
3393     public void dump(PrintWriter pw) {
3394         pw.println("---- EpdgTunnelManager ----");
3395         pw.println(
3396                 "Has ePDG connected for normal session: "
3397                         + mEpdgMonitor.hasEpdgConnectedForNormalSession());
3398         pw.println(
3399                 "Has Separate ePDG connected for emergency session: "
3400                         + mEpdgMonitor.hasSeparateEpdgConnectedForEmergencySession());
3401         pw.println("mIkeSessionNetwork: " + mIkeSessionNetwork);
3402         if (mEpdgMonitor.getEpdgAddressForNormalSession() != null) {
3403             pw.println(
3404                     "EpdgAddressForNormalSession: "
3405                             + mEpdgMonitor.getEpdgAddressForNormalSession());
3406         }
3407         if (mEpdgMonitor.getEpdgAddressForEmergencySession() != null) {
3408             pw.println(
3409                     "SeparateEpdgAddressForEmergencySession: "
3410                             + mEpdgMonitor.getEpdgAddressForEmergencySession());
3411         }
3412         pw.println("mApnNameToTunnelConfig:\n");
3413         for (Map.Entry<String, TunnelConfig> entry : mApnNameToTunnelConfig.entrySet()) {
3414             pw.println("APN: " + entry.getKey());
3415             pw.println("TunnelConfig: " + entry.getValue());
3416             pw.println();
3417         }
3418         pw.println("---------------------------");
3419     }
3420 }
3421