• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.net.ipsec.ike.net;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
21 import static android.net.ipsec.ike.IkeManager.getIkeLog;
22 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_NONE;
23 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_UDP;
24 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
25 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV4;
26 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV6;
27 import static android.net.ipsec.ike.IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MAX;
28 import static android.net.ipsec.ike.IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MIN;
29 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION;
30 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES;
31 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_FORCE_PORT_4500;
32 import static android.net.ipsec.ike.exceptions.IkeException.wrapAsIkeException;
33 
34 import static com.android.internal.net.ipsec.ike.IkeContext.CONFIG_AUTO_NATT_KEEPALIVES_CELLULAR_TIMEOUT_OVERRIDE_SECONDS;
35 import static com.android.internal.net.ipsec.ike.utils.IkeAlarm.IkeAlarmConfig;
36 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_KEEPALIVE;
37 
38 import android.annotation.IntDef;
39 import android.app.PendingIntent;
40 import android.net.ConnectivityManager;
41 import android.net.IpSecManager;
42 import android.net.IpSecManager.ResourceUnavailableException;
43 import android.net.LinkAddress;
44 import android.net.LinkProperties;
45 import android.net.Network;
46 import android.net.NetworkCapabilities;
47 import android.net.NetworkRequest;
48 import android.net.ipsec.ike.IkeSessionConnectionInfo;
49 import android.net.ipsec.ike.IkeSessionParams;
50 import android.net.ipsec.ike.exceptions.IkeException;
51 import android.os.Handler;
52 import android.os.Message;
53 import android.system.ErrnoException;
54 
55 import com.android.internal.annotations.VisibleForTesting;
56 import com.android.internal.net.ipsec.ike.IkeContext;
57 import com.android.internal.net.ipsec.ike.IkeSocket;
58 import com.android.internal.net.ipsec.ike.IkeSocketConfig;
59 import com.android.internal.net.ipsec.ike.IkeUdp4Socket;
60 import com.android.internal.net.ipsec.ike.IkeUdp6Socket;
61 import com.android.internal.net.ipsec.ike.IkeUdp6WithEncapPortSocket;
62 import com.android.internal.net.ipsec.ike.IkeUdpEncapSocket;
63 import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
64 import com.android.internal.net.ipsec.ike.keepalive.IkeNattKeepalive;
65 import com.android.internal.net.ipsec.ike.keepalive.IkeNattKeepalive.KeepaliveConfig;
66 import com.android.internal.net.ipsec.ike.message.IkeHeader;
67 import com.android.internal.net.ipsec.ike.shim.ShimUtils;
68 import com.android.internal.net.ipsec.ike.utils.IkeAlarm;
69 
70 import java.io.IOException;
71 import java.lang.annotation.Retention;
72 import java.lang.annotation.RetentionPolicy;
73 import java.net.Inet4Address;
74 import java.net.Inet6Address;
75 import java.net.InetAddress;
76 import java.net.UnknownHostException;
77 import java.util.ArrayList;
78 import java.util.Arrays;
79 import java.util.Collections;
80 import java.util.HashSet;
81 import java.util.List;
82 import java.util.Set;
83 import java.util.concurrent.TimeUnit;
84 
85 /**
86  * IkeConnectionController manages all connectivity events for an IKE Session
87  *
88  * <p>IkeConnectionController's responsibilities include:
89  *
90  * <ul>
91  *   <li>Manage IkeSocket for sending and receiving IKE packets
92  *   <li>Monitor and handle network and addresses changes
93  *   <li>Schedule NAT-T keepalive
94  * </ul>
95  *
96  * An IkeConnectionController should be set up when IKE Session is being established and should be
97  * torn down when the IKE Session is terminated.
98  */
99 public class IkeConnectionController implements IkeNetworkUpdater, IkeSocket.Callback {
100     private static final String TAG = IkeConnectionController.class.getSimpleName();
101 
102     // The maximum number of attempts allowed for a single DNS resolution.
103     private static final int MAX_DNS_RESOLUTION_ATTEMPTS = 3;
104 
105     @VisibleForTesting public static final int AUTO_KEEPALIVE_DELAY_SEC_WIFI = 15;
106     @VisibleForTesting public static final int AUTO_KEEPALIVE_DELAY_SEC_CELL = 150;
107 
108     @Retention(RetentionPolicy.SOURCE)
109     @IntDef({
110         NAT_TRAVERSAL_SUPPORT_NOT_CHECKED,
111         NAT_TRAVERSAL_UNSUPPORTED,
112         NAT_NOT_DETECTED,
113         NAT_DETECTED
114     })
115     public @interface NatStatus {}
116 
117     /** The IKE client has not checked whether the server supports NAT-T */
118     public static final int NAT_TRAVERSAL_SUPPORT_NOT_CHECKED = 0;
119     /** The IKE server does not support NAT-T */
120     public static final int NAT_TRAVERSAL_UNSUPPORTED = 1;
121     /** There is no NAT between the IKE client and the server */
122     public static final int NAT_NOT_DETECTED = 2;
123     /** There is at least a NAT between the IKE client and the server */
124     public static final int NAT_DETECTED = 3;
125 
126     private final IkeContext mIkeContext;
127     private final Config mConfig;
128     private final ConnectivityManager mConnectivityManager;
129     private final IpSecManager mIpSecManager;
130     private final Dependencies mDependencies;
131     private final IkeLocalAddressGenerator mIkeLocalAddressGenerator;
132     private final Callback mCallback;
133 
134     private final boolean mForcePort4500;
135     private final boolean mUseCallerConfiguredNetwork;
136     private final String mRemoteHostname;
137     private final int mDscp = 0;
138     private final IkeSessionParams mIkeParams;
139     // Must only be touched on the IkeSessionStateMachine thread.
140     private IkeAlarmConfig mKeepaliveAlarmConfig;
141 
142     private IkeSocket mIkeSocket;
143 
144     /** Underlying network for this IKE Session. May change if mobility handling is enabled. */
145     private Network mNetwork;
146 
147     /** NetworkCapabilities of the underlying network */
148     private NetworkCapabilities mNc;
149 
150     /**
151      * Network callback used to keep IkeConnectionController aware of network changes when mobility
152      * handling is enabled.
153      */
154     private IkeNetworkCallbackBase mNetworkCallback;
155 
156     private boolean mMobilityEnabled = false;
157 
158     /** Local address assigned on device. */
159     private InetAddress mLocalAddress;
160     /** Remote address resolved from caller configured hostname. */
161     private InetAddress mRemoteAddress;
162     /** Available remote addresses that are v4. */
163     private final List<Inet4Address> mRemoteAddressesV4 = new ArrayList<>();
164     /** Available remote addresses that are v6. */
165     private final List<Inet6Address> mRemoteAddressesV6 = new ArrayList<>();
166 
167     private final Set<IkeSaRecord> mIkeSaRecords = new HashSet<>();
168 
169     @NatStatus private int mNatStatus;
170 
171     // Must only be touched on the IkeSessionStateMachine thread.
172     @IkeSessionParams.EspIpVersion private int mIpVersion;
173     @IkeSessionParams.EspEncapType private int mEncapType;
174 
175     //Must only be touched on the IkeSessionStateMachine thread.
176     private Network mUnderpinnedNetwork;
177 
178     private IkeNattKeepalive mIkeNattKeepalive;
179 
180     /** Constructor of IkeConnectionController */
181     @VisibleForTesting
IkeConnectionController( IkeContext ikeContext, Config config, Dependencies dependencies)182     public IkeConnectionController(
183             IkeContext ikeContext, Config config, Dependencies dependencies) {
184         mIkeContext = ikeContext;
185         mConfig = config;
186         mConnectivityManager = mIkeContext.getContext().getSystemService(ConnectivityManager.class);
187         mIpSecManager = mIkeContext.getContext().getSystemService(IpSecManager.class);
188         mDependencies = dependencies;
189         mIkeLocalAddressGenerator = dependencies.newIkeLocalAddressGenerator();
190         mCallback = config.callback;
191 
192         mIkeParams = config.ikeParams;
193         mForcePort4500 = config.ikeParams.hasIkeOption(IKE_OPTION_FORCE_PORT_4500);
194         mRemoteHostname = config.ikeParams.getServerHostname();
195         mUseCallerConfiguredNetwork = config.ikeParams.getConfiguredNetwork() != null;
196         mIpVersion = config.ikeParams.getIpVersion();
197         mEncapType = config.ikeParams.getEncapType();
198         mUnderpinnedNetwork = null;
199 
200         if (mUseCallerConfiguredNetwork) {
201             mNetwork = config.ikeParams.getConfiguredNetwork();
202         } else {
203             mNetwork = mConnectivityManager.getActiveNetwork();
204             if (mNetwork == null) {
205                 throw new IllegalStateException("No active default network found");
206             }
207         }
208 
209         getIkeLog().d(TAG, "Set up on Network " + mNetwork);
210 
211         mNatStatus = NAT_TRAVERSAL_SUPPORT_NOT_CHECKED;
212     }
213 
214     /** Constructor of IkeConnectionController */
IkeConnectionController(IkeContext ikeContext, Config config)215     public IkeConnectionController(IkeContext ikeContext, Config config) {
216         this(ikeContext, config, new Dependencies());
217     }
218 
219     /** Config includes all configurations to build an IkeConnectionController */
220     public static class Config {
221         public final IkeSessionParams ikeParams;
222         public final int ikeSessionId;
223         public final int alarmCmd;
224         public final int sendKeepaliveCmd;
225         public final Callback callback;
226 
227         /** Constructor for IkeConnectionController.Config */
Config( IkeSessionParams ikeParams, int ikeSessionId, int alarmCmd, int sendKeepaliveCmd, Callback callback)228         public Config(
229                 IkeSessionParams ikeParams,
230                 int ikeSessionId,
231                 int alarmCmd,
232                 int sendKeepaliveCmd,
233                 Callback callback) {
234             this.ikeParams = ikeParams;
235             this.ikeSessionId = ikeSessionId;
236             this.alarmCmd = alarmCmd;
237             this.sendKeepaliveCmd = sendKeepaliveCmd;
238             this.callback = callback;
239         }
240     }
241 
242     /** Callback to notify status changes of the connection */
243     public interface Callback {
244         /** Notify the IkeConnectionController caller the underlying network has changed */
onUnderlyingNetworkUpdated()245         void onUnderlyingNetworkUpdated();
246 
247         /** Notify the IkeConnectionController caller that the underlying network died */
onUnderlyingNetworkDied(Network network)248         void onUnderlyingNetworkDied(Network network);
249 
250         /** Notify the IkeConnectionController caller of the incoming IKE packet */
onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets)251         void onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets);
252 
253         /** Notify the IkeConnectionController caller of the IKE fatal error */
onError(IkeException exception)254         void onError(IkeException exception);
255     }
256 
257     /** External dependencies, for injection in tests */
258     @VisibleForTesting
259     public static class Dependencies {
260         /** Gets an IkeLocalAddressGenerator */
newIkeLocalAddressGenerator()261         public IkeLocalAddressGenerator newIkeLocalAddressGenerator() {
262             return new IkeLocalAddressGenerator();
263         }
264 
265         /** Builds and starts NATT keepalive */
newIkeNattKeepalive( IkeContext ikeContext, KeepaliveConfig keepaliveConfig)266         public IkeNattKeepalive newIkeNattKeepalive(
267                 IkeContext ikeContext, KeepaliveConfig keepaliveConfig) throws IOException {
268             IkeNattKeepalive keepalive =
269                     new IkeNattKeepalive(
270                             ikeContext,
271                             ikeContext.getContext().getSystemService(ConnectivityManager.class),
272                             keepaliveConfig);
273             keepalive.start();
274             return keepalive;
275         }
276 
277         /** Builds and returns a new IkeUdp4Socket */
newIkeUdp4Socket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)278         public IkeUdp4Socket newIkeUdp4Socket(
279                 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)
280                 throws ErrnoException, IOException {
281             return IkeUdp4Socket.getInstance(sockConfig, callback, handler);
282         }
283 
284         /** Builds and returns a new IkeUdp6Socket */
newIkeUdp6Socket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)285         public IkeUdp6Socket newIkeUdp6Socket(
286                 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)
287                 throws ErrnoException, IOException {
288             return IkeUdp6Socket.getInstance(sockConfig, callback, handler);
289         }
290 
291         /** Builds and returns a new IkeUdp6WithEncapPortSocket */
newIkeUdp6WithEncapPortSocket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)292         public IkeUdp6WithEncapPortSocket newIkeUdp6WithEncapPortSocket(
293                 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)
294                 throws ErrnoException, IOException {
295             return IkeUdp6WithEncapPortSocket.getIkeUdpEncapSocket(sockConfig, callback, handler);
296         }
297 
298         /** Builds and returns a new IkeUdpEncapSocket */
newIkeUdpEncapSocket( IkeSocketConfig sockConfig, IpSecManager ipSecManager, IkeSocket.Callback callback, Handler handler)299         public IkeUdpEncapSocket newIkeUdpEncapSocket(
300                 IkeSocketConfig sockConfig,
301                 IpSecManager ipSecManager,
302                 IkeSocket.Callback callback,
303                 Handler handler)
304                 throws ErrnoException, IOException, ResourceUnavailableException {
305             return IkeUdpEncapSocket.getIkeUdpEncapSocket(
306                     sockConfig, ipSecManager, callback, handler.getLooper());
307         }
308     }
309 
310     /**
311      * Get the keepalive delay from params, transports and device config.
312      *
313      * If the AUTOMATIC_NATT_KEEPALIVES option is set, look up the transport in the network
314      * capabilities ; if Wi-Fi use the fixed delay, if cell use the device property int
315      * (or a fixed delay in the absence of the permission to read device properties).
316      * For other transports, or if the AUTOMATIC_NATT_KEEPALIVES option is not set, use the
317      * delay from the session params.
318      *
319      * @param ikeContext Context to read the device config, if necessary.
320      * @param ikeParams the session params
321      * @param nc the capabilities of the underlying network
322      * @return the keepalive delay to use, in seconds.
323      */
324     @VisibleForTesting
getKeepaliveDelaySec( IkeContext ikeContext, IkeSessionParams ikeParams, NetworkCapabilities nc)325     public static int getKeepaliveDelaySec(
326             IkeContext ikeContext, IkeSessionParams ikeParams, NetworkCapabilities nc) {
327         int keepaliveDelaySeconds = ikeParams.getNattKeepAliveDelaySeconds();
328 
329         if (ikeParams.hasIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES)) {
330             if (nc.hasTransport(TRANSPORT_WIFI)) {
331                 // Most of the time, IKE Session will use shorter keepalive timer on WiFi. Thus
332                 // choose the Wifi timer as a more conservative value when the NetworkCapabilities
333                 // have both TRANSPORT_WIFI and TRANSPORT_CELLULAR
334                 final int autoDelaySeconds = AUTO_KEEPALIVE_DELAY_SEC_WIFI;
335                 keepaliveDelaySeconds = Math.min(keepaliveDelaySeconds, autoDelaySeconds);
336             } else if (nc.hasTransport(TRANSPORT_CELLULAR)) {
337                 final int autoDelaySeconds =
338                         ikeContext.getDeviceConfigPropertyInt(
339                                 CONFIG_AUTO_NATT_KEEPALIVES_CELLULAR_TIMEOUT_OVERRIDE_SECONDS,
340                                 IKE_NATT_KEEPALIVE_DELAY_SEC_MIN,
341                                 IKE_NATT_KEEPALIVE_DELAY_SEC_MAX,
342                                 AUTO_KEEPALIVE_DELAY_SEC_CELL);
343                 keepaliveDelaySeconds = Math.min(keepaliveDelaySeconds, autoDelaySeconds);
344             }
345         }
346 
347         return keepaliveDelaySeconds;
348     }
349 
buildInitialKeepaliveAlarmConfig( Handler handler, IkeContext ikeContext, Config config, IkeSessionParams ikeParams, NetworkCapabilities nc)350     private static IkeAlarmConfig buildInitialKeepaliveAlarmConfig(
351             Handler handler,
352             IkeContext ikeContext,
353             Config config,
354             IkeSessionParams ikeParams,
355             NetworkCapabilities nc) {
356         final Message keepaliveMsg = handler.obtainMessage(
357                 config.alarmCmd /* what */,
358                 config.ikeSessionId /* arg1 */,
359                 config.sendKeepaliveCmd /* arg2 */);
360         final PendingIntent keepaliveIntent = IkeAlarm.buildIkeAlarmIntent(ikeContext.getContext(),
361                 ACTION_KEEPALIVE, getIntentIdentifier(config.ikeSessionId), keepaliveMsg);
362 
363         return new IkeAlarmConfig(
364                 ikeContext.getContext(),
365                 ACTION_KEEPALIVE,
366                 TimeUnit.SECONDS.toMillis(getKeepaliveDelaySec(ikeContext, ikeParams, nc)),
367                 keepaliveIntent,
368                 keepaliveMsg);
369     }
370 
getIntentIdentifier(int ikeSessionId)371     private static String getIntentIdentifier(int ikeSessionId) {
372         return TAG + "_" + ikeSessionId;
373     }
374 
375     /** Update the IKE NATT keepalive */
setupOrUpdateNattKeeaplive(IkeSocket ikeSocket)376     private void setupOrUpdateNattKeeaplive(IkeSocket ikeSocket) throws IOException {
377         if (!(ikeSocket instanceof IkeUdpEncapSocket)) {
378             if (mIkeNattKeepalive != null) {
379                 mIkeNattKeepalive.stop();
380                 mIkeNattKeepalive = null;
381             }
382             return;
383         }
384 
385         final KeepaliveConfig keepaliveConfig =
386                 new KeepaliveConfig(
387                         (Inet4Address) mLocalAddress,
388                         (Inet4Address) mRemoteAddress,
389                         ((IkeUdpEncapSocket) ikeSocket).getUdpEncapsulationSocket(),
390                         mNetwork,
391                         mUnderpinnedNetwork,
392                         mKeepaliveAlarmConfig,
393                         mIkeParams);
394 
395         if (mIkeNattKeepalive != null) {
396             mIkeNattKeepalive.restart(keepaliveConfig);
397         } else {
398             mIkeNattKeepalive = mDependencies.newIkeNattKeepalive(mIkeContext, keepaliveConfig);
399         }
400     }
401 
getIkeSocket(boolean isIpv4, boolean useEncapPort)402     private IkeSocket getIkeSocket(boolean isIpv4, boolean useEncapPort) throws IkeException {
403         IkeSocketConfig sockConfig = new IkeSocketConfig(this, mDscp);
404         IkeSocket result = null;
405 
406         try {
407             if (useEncapPort) {
408                 if (isIpv4) {
409                     result = mDependencies.newIkeUdpEncapSocket(
410                             sockConfig, mIpSecManager, this, new Handler(mIkeContext.getLooper()));
411                 } else {
412                     result = mDependencies.newIkeUdp6WithEncapPortSocket(
413                             sockConfig, this, new Handler(mIkeContext.getLooper()));
414                 }
415             } else {
416                 if (isIpv4) {
417                     result = mDependencies.newIkeUdp4Socket(
418                             sockConfig, this, new Handler(mIkeContext.getLooper()));
419                 } else {
420                     result = mDependencies.newIkeUdp6Socket(
421                             sockConfig, this, new Handler(mIkeContext.getLooper()));
422                 }
423             }
424 
425             if (result == null) {
426                 throw new IOException("No socket created");
427             }
428 
429             result.bindToNetwork(mNetwork);
430             return result;
431         } catch (ErrnoException | IOException | ResourceUnavailableException e) {
432             throw wrapAsIkeException(e);
433         }
434     }
435 
migrateSpiToIkeSocket(long localSpi, IkeSocket oldSocket, IkeSocket newSocket)436     private void migrateSpiToIkeSocket(long localSpi, IkeSocket oldSocket, IkeSocket newSocket) {
437         newSocket.registerIke(localSpi, this);
438         oldSocket.unregisterIke(localSpi);
439     }
440 
getAndSwitchToIkeSocket(boolean isIpv4, boolean useEncapPort)441     private void getAndSwitchToIkeSocket(boolean isIpv4, boolean useEncapPort) throws IkeException {
442         IkeSocket newSocket = getIkeSocket(isIpv4, useEncapPort);
443 
444         try {
445             setupOrUpdateNattKeeaplive(newSocket);
446         } catch (IOException e) {
447             throw wrapAsIkeException(e);
448         }
449 
450         if (newSocket != mIkeSocket) {
451             for (IkeSaRecord saRecord : mIkeSaRecords) {
452                 migrateSpiToIkeSocket(saRecord.getLocalSpi(), mIkeSocket, newSocket);
453             }
454             mIkeSocket.releaseReference(this);
455             mIkeSocket = newSocket;
456         }
457     }
458 
459     /** Sets up the IkeConnectionController */
setUp()460     public void setUp() throws IkeException {
461         // Make sure all the resources, especially the NetworkCallback, is released before creating
462         // new one.
463         unregisterResources();
464 
465         // This is call is directly from the IkeSessionStateMachine, and thus cannot be
466         // accidentally called in a NetworkCallback. See
467         // ConnectivityManager.NetworkCallback#onLinkPropertiesChanged() and
468         // ConnectivityManager.NetworkCallback#onCapabilitiesChanged() for discussion of
469         // mixing callbacks and synchronous polling methods.
470         LinkProperties linkProperties = mConnectivityManager.getLinkProperties(mNetwork);
471         mNc = mConnectivityManager.getNetworkCapabilities(mNetwork);
472         mKeepaliveAlarmConfig = buildInitialKeepaliveAlarmConfig(
473                 new Handler(mIkeContext.getLooper()), mIkeContext, mConfig, mIkeParams, mNc);
474         try {
475             if (linkProperties == null || mNc == null) {
476                 // Throw NPE to preserve the existing behaviour for backward compatibility
477                 throw wrapAsIkeException(
478                         new NullPointerException(
479                                 "Attempt setup on network "
480                                         + mNetwork
481                                         + " with null LinkProperties or null NetworkCapabilities"));
482             }
483             resolveAndSetAvailableRemoteAddresses();
484             selectAndSetRemoteAddress(linkProperties);
485 
486             int remotePort =
487                     mForcePort4500
488                             ? IkeSocket.SERVER_PORT_UDP_ENCAPSULATED
489                             : IkeSocket.SERVER_PORT_NON_UDP_ENCAPSULATED;
490             boolean isIpv4 = mRemoteAddress instanceof Inet4Address;
491             mLocalAddress =
492                     mIkeLocalAddressGenerator.generateLocalAddress(
493                             mNetwork, isIpv4, mRemoteAddress, remotePort);
494             mIkeSocket = getIkeSocket(isIpv4, mForcePort4500);
495 
496             setupOrUpdateNattKeeaplive(mIkeSocket);
497         } catch (IOException | ErrnoException e) {
498             throw wrapAsIkeException(e);
499         }
500 
501         try {
502             if (mUseCallerConfiguredNetwork) {
503                 // Caller configured a specific Network - track it
504                 // ConnectivityManager does not provide a callback for tracking a specific
505                 // Network. In order to do so, create a NetworkRequest without any
506                 // capabilities so it will match all Networks. The NetworkCallback will then
507                 // filter for the correct (caller-specified) Network.
508                 NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
509                 mNetworkCallback =
510                         new IkeSpecificNetworkCallback(
511                                 this, mNetwork, mLocalAddress, linkProperties, mNc);
512                 mConnectivityManager.registerNetworkCallback(
513                         request, mNetworkCallback, new Handler(mIkeContext.getLooper()));
514             } else {
515                 // Caller did not configure a specific Network - track the default
516                 mNetworkCallback =
517                         new IkeDefaultNetworkCallback(
518                                 this, mNetwork, mLocalAddress, linkProperties, mNc);
519                 mConnectivityManager.registerDefaultNetworkCallback(
520                         mNetworkCallback, new Handler(mIkeContext.getLooper()));
521             }
522         } catch (RuntimeException e) {
523             mNetworkCallback = null;
524             throw wrapAsIkeException(e);
525         }
526     }
527 
unregisterResources()528     private void unregisterResources() {
529         if (mIkeNattKeepalive != null) {
530             mIkeNattKeepalive.stop();
531             mIkeNattKeepalive = null;
532         }
533 
534         if (mNetworkCallback != null) {
535             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
536             mNetworkCallback = null;
537         }
538 
539         if (mIkeSocket != null) {
540             for (IkeSaRecord saRecord : mIkeSaRecords) {
541                 mIkeSocket.unregisterIke(saRecord.getLocalSpi());
542             }
543 
544             mIkeSocket.releaseReference(this);
545             mIkeSocket = null;
546         }
547 
548         mIkeSaRecords.clear();
549     }
550 
551     /** Tears down the IkeConnectionController */
tearDown()552     public void tearDown() {
553         unregisterResources();
554     }
555 
556     /** Returns the IkeSocket */
getIkeSocket()557     public IkeSocket getIkeSocket() {
558         return mIkeSocket;
559     }
560 
561     /** Returns if the IkeSocket is a UDP encapsulation socket */
useUdpEncapSocket()562     public boolean useUdpEncapSocket() {
563         return mIkeSocket instanceof IkeUdpEncapSocket;
564     }
565 
566     /** Sends out an IKE packet */
sendIkePacket(byte[] ikePacket)567     public void sendIkePacket(byte[] ikePacket) {
568         mIkeSocket.sendIkePacket(ikePacket, mRemoteAddress);
569     }
570 
571     /** Registers the local SPI for an IKE SA waiting for the IKE INIT response */
registerIkeSpi(long ikeSpi)572     public void registerIkeSpi(long ikeSpi) {
573         mIkeSocket.registerIke(ikeSpi, this);
574     }
575 
576     /** Unregisters the local SPI for an IKE SA that failed IKE INIT exchange */
unregisterIkeSpi(long ikeSpi)577     public void unregisterIkeSpi(long ikeSpi) {
578         mIkeSocket.unregisterIke(ikeSpi);
579     }
580 
581     /** Registers a newly created IKE SA */
registerIkeSaRecord(IkeSaRecord saRecord)582     public void registerIkeSaRecord(IkeSaRecord saRecord) {
583         mIkeSaRecords.add(saRecord);
584         mIkeSocket.registerIke(saRecord.getLocalSpi(), this);
585     }
586 
587     /** Unregisters a deleted IKE SA */
unregisterIkeSaRecord(IkeSaRecord saRecord)588     public void unregisterIkeSaRecord(IkeSaRecord saRecord) {
589         mIkeSaRecords.remove(saRecord);
590         mIkeSocket.unregisterIke(saRecord.getLocalSpi());
591     }
592 
593     /** Returns all registered IKE SAs */
594     @VisibleForTesting
getIkeSaRecords()595     public Set<IkeSaRecord> getIkeSaRecords() {
596         return Collections.unmodifiableSet(mIkeSaRecords);
597     }
598 
599     /**
600      * Updates the underlying network
601      *
602      * <p>This call is always from IkeSessionStateMachine for migrating IKE to a caller configured
603      * network, or to update the protocol preference or keepalive delay.
604      */
onNetworkSetByUser( Network network, int ipVersion, int encapType, int keepaliveDelaySeconds)605     public void onNetworkSetByUser(
606             Network network,
607             int ipVersion,
608             int encapType,
609             int keepaliveDelaySeconds)
610             throws IkeException {
611         if (!mMobilityEnabled) {
612             // Program error. IkeSessionStateMachine should never call this method before enabling
613             // mobility.
614             getIkeLog().wtf(TAG, "Attempt to update network when mobility is disabled");
615             return;
616         }
617 
618         // This is call is directly from the IkeSessionStateMachine, and thus cannot be
619         // accidentally called in a NetworkCallback. See
620         // ConnectivityManager.NetworkCallback#onLinkPropertiesChanged() and
621         // ConnectivityManager.NetworkCallback#onCapabilitiesChanged() for discussion of
622         // mixing callbacks and synchronous polling methods.
623         final LinkProperties linkProperties = mConnectivityManager.getLinkProperties(network);
624         final NetworkCapabilities networkCapabilities =
625                 mConnectivityManager.getNetworkCapabilities(network);
626 
627         if (linkProperties == null || networkCapabilities == null) {
628             // Throw NPE to preserve the existing behaviour for backward compatibility
629             throw wrapAsIkeException(
630                     new NullPointerException(
631                             "Attempt migrating to network "
632                                     + network
633                                     + " with null LinkProperties or null NetworkCapabilities"));
634 
635             // TODO(b/224686889): Notify caller of failed mobility attempt and keep this IKE Session
636             // alive
637         }
638 
639         mIpVersion = ipVersion;
640         mEncapType = encapType;
641 
642         if (keepaliveDelaySeconds == IkeSessionParams.NATT_KEEPALIVE_INTERVAL_AUTO) {
643             keepaliveDelaySeconds = getKeepaliveDelaySec(mIkeContext, mIkeParams, mNc);
644         }
645         final long keepaliveDelayMs = TimeUnit.SECONDS.toMillis(keepaliveDelaySeconds);
646         if (keepaliveDelayMs != mKeepaliveAlarmConfig.delayMs) {
647             mKeepaliveAlarmConfig = mKeepaliveAlarmConfig.buildCopyWithDelayMs(keepaliveDelayMs);
648             restartKeepaliveIfRunning();
649         }
650 
651         // Switch to monitor a new network. This call is never expected to trigger a callback
652         mNetworkCallback.setNetwork(network, linkProperties, networkCapabilities);
653         handleUnderlyingNetworkUpdated(
654                 network, linkProperties, networkCapabilities, false /* skipIfSameNetwork */);
655     }
656 
657     /** Called when the underpinned network is set by the user */
onUnderpinnedNetworkSetByUser(final Network underpinnedNetwork)658     public void onUnderpinnedNetworkSetByUser(final Network underpinnedNetwork)
659             throws IkeException {
660         mUnderpinnedNetwork = underpinnedNetwork;
661         restartKeepaliveIfRunning();
662     }
663 
restartKeepaliveIfRunning()664     private void restartKeepaliveIfRunning() throws IkeException {
665         try {
666             setupOrUpdateNattKeeaplive(mIkeSocket);
667         } catch (IOException e) {
668             throw wrapAsIkeException(e);
669         }
670     }
671 
672     /** Gets the underlying network */
getNetwork()673     public Network getNetwork() {
674         return mNetwork;
675     }
676 
677     /** Gets the underpinned network */
getUnderpinnedNetwork()678     public Network getUnderpinnedNetwork() {
679         return mUnderpinnedNetwork;
680     }
681 
682     /** Check if mobility is enabled */
isMobilityEnabled()683     public boolean isMobilityEnabled() {
684         return mMobilityEnabled;
685     }
686 
687     /**
688      * Sets the local address.
689      *
690      * <p>This MUST only be called in a test.
691      */
692     @VisibleForTesting
setLocalAddress(InetAddress address)693     public void setLocalAddress(InetAddress address) {
694         mLocalAddress = address;
695     }
696 
697     /** Gets the local address */
getLocalAddress()698     public InetAddress getLocalAddress() {
699         return mLocalAddress;
700     }
701 
702     /**
703      * Sets the remote address.
704      *
705      * <p>This MUST only be called in a test.
706      */
707     @VisibleForTesting
setRemoteAddress(InetAddress address)708     public void setRemoteAddress(InetAddress address) {
709         mRemoteAddress = address;
710         addRemoteAddress(address);
711     }
712 
713     /**
714      * Adds a remote address.
715      *
716      * <p>This MUST only be called in a test.
717      */
718     @VisibleForTesting
addRemoteAddress(InetAddress address)719     public void addRemoteAddress(InetAddress address) {
720         if (address instanceof Inet4Address) {
721             mRemoteAddressesV4.add((Inet4Address) address);
722         } else {
723             mRemoteAddressesV6.add((Inet6Address) address);
724         }
725     }
726 
727     /** Gets the remote addresses */
getRemoteAddress()728     public InetAddress getRemoteAddress() {
729         return mRemoteAddress;
730     }
731 
732     /** Gets all the IPv4 remote addresses */
getAllRemoteIpv4Addresses()733     public List<Inet4Address> getAllRemoteIpv4Addresses() {
734         return new ArrayList<>(mRemoteAddressesV4);
735     }
736 
737     /** Gets all the IPv6 remote addresses */
getAllRemoteIpv6Addresses()738     public List<Inet6Address> getAllRemoteIpv6Addresses() {
739         return new ArrayList<>(mRemoteAddressesV6);
740     }
741 
742     /** Gets the local port */
getLocalPort()743     public int getLocalPort() {
744         try {
745             return mIkeSocket.getLocalPort();
746         } catch (ErrnoException e) {
747             throw new IllegalStateException("Fail to get local port", e);
748         }
749     }
750 
751     /** Gets the remote port */
getRemotePort()752     public int getRemotePort() {
753         return mIkeSocket.getIkeServerPort();
754     }
755 
756     /** Handles NAT detection result in IKE INIT */
handleNatDetectionResultInIkeInit(boolean isNatDetected, long localSpi)757     public void handleNatDetectionResultInIkeInit(boolean isNatDetected, long localSpi)
758             throws IkeException {
759         if (!isNatDetected) {
760             mNatStatus = NAT_NOT_DETECTED;
761             return;
762         }
763 
764         mNatStatus = NAT_DETECTED;
765         if (mRemoteAddress instanceof Inet6Address) {
766             throw wrapAsIkeException(new UnsupportedOperationException("IPv6 NAT-T not supported"));
767         }
768 
769         getIkeLog().d(TAG, "Switching to send to remote port 4500 if it's not already");
770 
771         IkeSocket newSocket = getIkeSocket(true /* isIpv4 */, true /* useEncapPort */);
772 
773         try {
774             setupOrUpdateNattKeeaplive(newSocket);
775         } catch (IOException e) {
776             throw wrapAsIkeException(e);
777         }
778 
779         if (newSocket != mIkeSocket) {
780             migrateSpiToIkeSocket(localSpi, mIkeSocket, newSocket);
781             mIkeSocket.releaseReference(this);
782             mIkeSocket = newSocket;
783         }
784     }
785 
786     /** Handles NAT detection result in the MOBIKE INFORMATIONAL exchange */
handleNatDetectionResultInMobike(boolean isNatDetected)787     public void handleNatDetectionResultInMobike(boolean isNatDetected) throws IkeException {
788         if (!isNatDetected) {
789             mNatStatus = NAT_NOT_DETECTED;
790             return;
791         }
792 
793         mNatStatus = NAT_DETECTED;
794         if (mRemoteAddress instanceof Inet6Address) {
795             throw wrapAsIkeException(new UnsupportedOperationException("IPv6 NAT-T not supported"));
796         }
797 
798         getIkeLog().d(TAG, "Switching to send to remote port 4500 if it's not already");
799         getAndSwitchToIkeSocket(true /* isIpv4 */, true /* useEncapPort */);
800     }
801 
802     /**
803      * Marks that the server does not support NAT-T
804      *
805      * <p>This is method should only be called at the first time IKE client sends NAT_DETECTION (in
806      * other words the first time IKE client is using IPv4 address since IKE does not support IPv6
807      * NAT-T)
808      */
markSeverNattUnsupported()809     public void markSeverNattUnsupported() {
810         mNatStatus = NAT_TRAVERSAL_UNSUPPORTED;
811     }
812 
813     /**
814      * Clears the knowledge of sever's NAT-T support
815      *
816      * <p>This MUST only be called in a test.
817      */
818     @VisibleForTesting
resetSeverNattSupport()819     public void resetSeverNattSupport() {
820         mNatStatus = NAT_TRAVERSAL_SUPPORT_NOT_CHECKED;
821     }
822 
823     /** This MUST only be called in a test. */
824     @VisibleForTesting
setNatDetected(boolean isNatDetected)825     public void setNatDetected(boolean isNatDetected) {
826         if (!isNatDetected) {
827             mNatStatus = NAT_NOT_DETECTED;
828             return;
829         }
830 
831         mNatStatus = NAT_DETECTED;
832     }
833 
834     /** Returns the NAT status */
835     @NatStatus
getNatStatus()836     public int getNatStatus() {
837         return mNatStatus;
838     }
839 
840     /** Returns the IkeNattKeepalive */
getIkeNattKeepalive()841     public IkeNattKeepalive getIkeNattKeepalive() {
842         return mIkeNattKeepalive;
843     }
844 
845     /** Fire software keepalive */
fireKeepAlive()846     public void fireKeepAlive() {
847         // Software keepalive alarm is fired. Ignore the alarm whe NAT-T keepalive is no
848         // longer needed (e.g. migrating from IPv4 to IPv6)
849         if (mIkeNattKeepalive != null) {
850             mIkeNattKeepalive.onAlarmFired();
851         }
852     }
853 
resolveAndSetAvailableRemoteAddresses()854     private void resolveAndSetAvailableRemoteAddresses() throws IOException {
855         // TODO(b/149954916): Do DNS resolution asynchronously
856         InetAddress[] allRemoteAddresses = null;
857 
858         for (int attempts = 0;
859                 attempts < MAX_DNS_RESOLUTION_ATTEMPTS
860                         && (allRemoteAddresses == null || allRemoteAddresses.length == 0);
861                 attempts++) {
862             try {
863                 allRemoteAddresses = mNetwork.getAllByName(mRemoteHostname);
864             } catch (UnknownHostException e) {
865                 final boolean willRetry = attempts + 1 < MAX_DNS_RESOLUTION_ATTEMPTS;
866                 getIkeLog()
867                         .d(
868                                 TAG,
869                                 "Failed to look up host for attempt "
870                                         + (attempts + 1)
871                                         + ": "
872                                         + mRemoteHostname
873                                         + " retrying? "
874                                         + willRetry,
875                                 e);
876             }
877         }
878         if (allRemoteAddresses == null || allRemoteAddresses.length == 0) {
879             final String errMsg =
880                     "DNS resolution for "
881                             + mRemoteHostname
882                             + " failed after "
883                             + MAX_DNS_RESOLUTION_ATTEMPTS
884                             + " attempts";
885 
886             throw ShimUtils.getInstance().getDnsFailedException(errMsg);
887         }
888 
889         getIkeLog()
890                 .d(
891                         TAG,
892                         "Resolved addresses for peer: "
893                                 + Arrays.toString(allRemoteAddresses)
894                                 + " to replace old addresses: v4="
895                                 + mRemoteAddressesV4
896                                 + " v6="
897                                 + mRemoteAddressesV6);
898 
899         mRemoteAddressesV4.clear();
900         mRemoteAddressesV6.clear();
901         for (InetAddress remoteAddress : allRemoteAddresses) {
902             if (remoteAddress instanceof Inet4Address) {
903                 mRemoteAddressesV4.add((Inet4Address) remoteAddress);
904             } else {
905                 mRemoteAddressesV6.add((Inet6Address) remoteAddress);
906             }
907         }
908     }
909 
hasLocalIpV4Address(LinkProperties linkProperties)910     private static boolean hasLocalIpV4Address(LinkProperties linkProperties) {
911         for (LinkAddress linkAddress : linkProperties.getAllLinkAddresses()) {
912             if (linkAddress.getAddress() instanceof Inet4Address) {
913                 return true;
914             }
915         }
916 
917         return false;
918     }
919 
920     /**
921      * Set the remote address for the peer.
922      *
923      * <p>The selection of IP address is as follows:
924      *
925      * <ul>
926      *   <li>If the caller passed in an IP address family, use that address family.
927      *   <li>Otherwise, always prefer IPv6 over IPv4.
928      * </ul>
929      *
930      * Otherwise, an IPv4 address will be used.
931      */
932     @VisibleForTesting
selectAndSetRemoteAddress(LinkProperties linkProperties)933     public void selectAndSetRemoteAddress(LinkProperties linkProperties) throws IOException {
934         // TODO(b/175348096): Randomly choose from available addresses when the IP family is
935         // decided.
936         final boolean canConnectWithIpv4 =
937                 !mRemoteAddressesV4.isEmpty() && hasLocalIpV4Address(linkProperties);
938         final boolean canConnectWithIpv6 =
939                 !mRemoteAddressesV6.isEmpty() && linkProperties.hasGlobalIpv6Address();
940 
941         adjustIpVersionPreference();
942 
943         if (isIpVersionRequired(ESP_IP_VERSION_IPV4)) {
944             if (!canConnectWithIpv4) {
945                 throw ShimUtils.getInstance().getDnsFailedException(
946                         "IPv4 required but no IPv4 address available");
947             }
948             mRemoteAddress = mRemoteAddressesV4.get(0);
949         } else if (isIpVersionRequired(ESP_IP_VERSION_IPV6)) {
950             if (!canConnectWithIpv6) {
951                 throw ShimUtils.getInstance().getDnsFailedException(
952                         "IPv6 required but no global IPv6 address available");
953             }
954             mRemoteAddress = mRemoteAddressesV6.get(0);
955         } else if (isIpV4Preferred(mIkeParams, mNc) && canConnectWithIpv4) {
956             mRemoteAddress = mRemoteAddressesV4.get(0);
957         } else if (canConnectWithIpv6) {
958             mRemoteAddress = mRemoteAddressesV6.get(0);
959         } else if (canConnectWithIpv4) {
960             mRemoteAddress = mRemoteAddressesV4.get(0);
961         } else {
962             // For backwards compatibility, synchronously throw IAE instead of triggering callback.
963             throw new IllegalArgumentException("No valid IPv4 or IPv6 addresses for peer");
964         }
965     }
966 
adjustIpVersionPreference()967     private void adjustIpVersionPreference() {
968         // As ESP isn't supported on v4 and UDP isn't supported on v6, a request for ENCAP_UDP
969         // should force v4 and a request for ENCAP_NONE should force v6 when the family is set
970         // to auto.
971         // TODO : instead of fudging the arguments here, this should actually be taken into
972         // account when figuring out whether to send the NAT detection packet.
973         int adjustedIpVersion = mIpVersion;
974         if (mIpVersion == ESP_IP_VERSION_AUTO) {
975             if (mEncapType == ESP_ENCAP_TYPE_NONE) {
976                 adjustedIpVersion = ESP_IP_VERSION_IPV6;
977             } else if (mEncapType == ESP_ENCAP_TYPE_UDP) {
978                 adjustedIpVersion = ESP_IP_VERSION_IPV4;
979             }
980 
981             if (adjustedIpVersion != mIpVersion) {
982                 getIkeLog().i(TAG, "IP version preference is overridden from "
983                         + mIpVersion  + " to " + adjustedIpVersion);
984                 mIpVersion = adjustedIpVersion;
985             }
986         }
987     }
988 
isIpVersionRequired(final int ipVersion)989     private boolean isIpVersionRequired(final int ipVersion) {
990         return ipVersion == mIpVersion;
991     }
992 
993     @VisibleForTesting
isIpV4Preferred(IkeSessionParams ikeParams, NetworkCapabilities nc)994     public boolean isIpV4Preferred(IkeSessionParams ikeParams, NetworkCapabilities nc) {
995         // Note that in production code mIpVersion can't be == ESP_IP_VERSION_IPV4 because the
996         // only caller, selectAndSetRemoteAddress, would never call this method because
997         // isIpVersionRequired(ESP_IP_VERSION_IPV4) would return true. Still, it makes sense in
998         // this method to accept ESP_IP_VERSION_IPV4.
999         return (mIpVersion == ESP_IP_VERSION_AUTO || mIpVersion == ESP_IP_VERSION_IPV4)
1000                 && ikeParams.hasIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION)
1001                 && nc.hasTransport(TRANSPORT_WIFI);
1002     }
1003 
1004     /**
1005      * Enables IkeConnectionController to handle mobility events
1006      *
1007      * <p>This method will enable IkeConnectionController to monitor and handle changes of the
1008      * underlying network and addresses.
1009      */
enableMobility()1010     public void enableMobility() throws IkeException {
1011         mMobilityEnabled = true;
1012 
1013         if (mNatStatus != NAT_TRAVERSAL_UNSUPPORTED
1014                 && mIkeSocket.getIkeServerPort() != IkeSocket.SERVER_PORT_UDP_ENCAPSULATED) {
1015             getAndSwitchToIkeSocket(
1016                     mRemoteAddress instanceof Inet4Address, true /* useEncapPort */);
1017         }
1018     }
1019 
1020     /** Creates a IkeSessionConnectionInfo */
buildIkeSessionConnectionInfo()1021     public IkeSessionConnectionInfo buildIkeSessionConnectionInfo() {
1022         return new IkeSessionConnectionInfo(mLocalAddress, mRemoteAddress, mNetwork);
1023     }
1024 
1025     /**
1026      * All the calls that are not initiated from the IkeSessionStateMachine MUST be run in this
1027      * method unless there are mechanisms to guarantee these calls will never crash the process.
1028      */
executeOrSendFatalError(Runnable r)1029     private void executeOrSendFatalError(Runnable r) {
1030         ShimUtils.getInstance().executeOrSendFatalError(r, mCallback);
1031     }
1032 
1033     // This method is never expected be called due to the capabilities change of the existing
1034     // underlying network. Only explicit user requests, network changes, addresses changes or
1035     // configuration changes (such as the protocol preference) will call into this method.
handleUnderlyingNetworkUpdated( Network network, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, boolean skipIfSameNetwork)1036     private void handleUnderlyingNetworkUpdated(
1037             Network network,
1038             LinkProperties linkProperties,
1039             NetworkCapabilities networkCapabilities,
1040             boolean skipIfSameNetwork) {
1041         if (!mMobilityEnabled) {
1042             getIkeLog().d(TAG, "onUnderlyingNetworkUpdated: Unable to handle network update");
1043             mCallback.onUnderlyingNetworkDied(mNetwork);
1044 
1045             return;
1046         }
1047 
1048         Network oldNetwork = mNetwork;
1049         InetAddress oldLocalAddress = mLocalAddress;
1050         InetAddress oldRemoteAddress = mRemoteAddress;
1051 
1052         mNetwork = network;
1053         mNc = networkCapabilities;
1054 
1055         // If the network changes, perform a new DNS lookup to ensure that the correct remote
1056         // address is used. This ensures that DNS returns addresses for the correct address families
1057         // (important if using a v4/v6-only network). This also ensures that DNS64 is handled
1058         // correctly when switching between networks that may have different IPv6 prefixes.
1059         if (!mNetwork.equals(oldNetwork)) {
1060             try {
1061                 resolveAndSetAvailableRemoteAddresses();
1062             } catch (IOException e) {
1063                 mCallback.onError(wrapAsIkeException(e));
1064                 return;
1065             }
1066         }
1067 
1068         try {
1069             selectAndSetRemoteAddress(linkProperties);
1070         } catch (IOException e) {
1071             mCallback.onError(wrapAsIkeException(e));
1072             return;
1073         }
1074 
1075         boolean isIpv4 = mRemoteAddress instanceof Inet4Address;
1076 
1077         // If it is known that the server supports NAT-T, use port 4500. Otherwise, use port 500.
1078         boolean nattSupported = mNatStatus != NAT_TRAVERSAL_UNSUPPORTED;
1079         int serverPort =
1080                 nattSupported
1081                         ? IkeSocket.SERVER_PORT_UDP_ENCAPSULATED
1082                         : IkeSocket.SERVER_PORT_NON_UDP_ENCAPSULATED;
1083 
1084         try {
1085             mLocalAddress =
1086                     mIkeLocalAddressGenerator.generateLocalAddress(
1087                             mNetwork, isIpv4, mRemoteAddress, serverPort);
1088 
1089             if (ShimUtils.getInstance().shouldSkipIfSameNetwork(skipIfSameNetwork)
1090                     && mNetwork.equals(oldNetwork)
1091                     && mLocalAddress.equals(oldLocalAddress)
1092                     && mRemoteAddress.equals(oldRemoteAddress)) {
1093                 getIkeLog()
1094                         .d(
1095                                 TAG,
1096                                 "onUnderlyingNetworkUpdated: None of network, local or remote"
1097                                     + " address has changed, and the update is skippable. No action"
1098                                     + " needed here.");
1099                 return;
1100             }
1101 
1102             if (!mNetwork.equals(oldNetwork)) {
1103                 boolean useEncapPort = mForcePort4500 || nattSupported;
1104                 getAndSwitchToIkeSocket(mLocalAddress instanceof Inet4Address, useEncapPort);
1105             }
1106 
1107             for (IkeSaRecord record : mIkeSaRecords) {
1108                 record.migrate(mLocalAddress, mRemoteAddress);
1109             }
1110         } catch (IkeException | ErrnoException | IOException e) {
1111             mCallback.onError(wrapAsIkeException(e));
1112             return;
1113         }
1114 
1115         mNetworkCallback.setAddress(mLocalAddress);
1116 
1117         mCallback.onUnderlyingNetworkUpdated();
1118     }
1119 
1120     @Override
onUnderlyingNetworkUpdated( Network network, LinkProperties linkProperties, NetworkCapabilities networkCapabilities)1121     public void onUnderlyingNetworkUpdated(
1122             Network network,
1123             LinkProperties linkProperties,
1124             NetworkCapabilities networkCapabilities) {
1125         executeOrSendFatalError(
1126                 () -> {
1127                     handleUnderlyingNetworkUpdated(
1128                             network,
1129                             linkProperties,
1130                             networkCapabilities,
1131                             true /* skipIfSameNetwork */);
1132                 });
1133     }
1134 
1135     @Override
onCapabilitiesUpdated(NetworkCapabilities networkCapabilities)1136     public void onCapabilitiesUpdated(NetworkCapabilities networkCapabilities) {
1137         executeOrSendFatalError(
1138                 () -> {
1139                     mNc = networkCapabilities;
1140 
1141                     // No action. There is no known use case to perform mobility or update keepalive
1142                     // timer when NetworkCapabilities changes.
1143                 });
1144     }
1145 
1146     @Override
onUnderlyingNetworkDied()1147     public void onUnderlyingNetworkDied() {
1148         executeOrSendFatalError(
1149                 () -> {
1150                     mCallback.onUnderlyingNetworkDied(mNetwork);
1151                 });
1152     }
1153 
1154     @Override
onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets)1155     public void onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets) {
1156         executeOrSendFatalError(
1157                 () -> {
1158                     mCallback.onIkePacketReceived(ikeHeader, ikePackets);
1159                 });
1160     }
1161 }
1162