• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.ip;
18 
19 import static android.net.RouteInfo.RTN_UNICAST;
20 import static android.net.dhcp.DhcpResultsParcelableUtil.toStableParcelable;
21 import static android.net.ip.IIpClient.PROV_IPV4_DISABLED;
22 import static android.net.ip.IIpClient.PROV_IPV6_DISABLED;
23 import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL;
24 import static android.net.ip.IpReachabilityMonitor.INVALID_REACHABILITY_LOSS_TYPE;
25 import static android.net.ip.IpReachabilityMonitor.nudEventTypeToInt;
26 import static android.net.util.NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION;
27 import static android.net.util.NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION;
28 import static android.net.util.NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION;
29 import static android.net.util.SocketUtils.makePacketSocketAddress;
30 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
31 import static android.system.OsConstants.AF_PACKET;
32 import static android.system.OsConstants.ETH_P_ARP;
33 import static android.system.OsConstants.ETH_P_IPV6;
34 import static android.system.OsConstants.SOCK_NONBLOCK;
35 import static android.system.OsConstants.SOCK_RAW;
36 
37 import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
38 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
39 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST;
40 import static com.android.net.module.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID;
41 import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingPermission;
42 
43 import android.annotation.SuppressLint;
44 import android.content.Context;
45 import android.content.res.Resources;
46 import android.net.ConnectivityManager;
47 import android.net.DhcpResults;
48 import android.net.INetd;
49 import android.net.IpPrefix;
50 import android.net.Layer2InformationParcelable;
51 import android.net.Layer2PacketParcelable;
52 import android.net.LinkAddress;
53 import android.net.LinkProperties;
54 import android.net.MacAddress;
55 import android.net.NattKeepalivePacketDataParcelable;
56 import android.net.NetworkStackIpMemoryStore;
57 import android.net.ProvisioningConfigurationParcelable;
58 import android.net.ProxyInfo;
59 import android.net.RouteInfo;
60 import android.net.TcpKeepalivePacketDataParcelable;
61 import android.net.Uri;
62 import android.net.apf.ApfCapabilities;
63 import android.net.apf.ApfFilter;
64 import android.net.dhcp.DhcpClient;
65 import android.net.dhcp.DhcpPacket;
66 import android.net.metrics.IpConnectivityLog;
67 import android.net.metrics.IpManagerEvent;
68 import android.net.networkstack.aidl.dhcp.DhcpOption;
69 import android.net.networkstack.aidl.ip.ReachabilityLossInfoParcelable;
70 import android.net.networkstack.aidl.ip.ReachabilityLossReason;
71 import android.net.shared.InitialConfiguration;
72 import android.net.shared.Layer2Information;
73 import android.net.shared.ProvisioningConfiguration;
74 import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
75 import android.net.shared.ProvisioningConfiguration.ScanResultInfo.InformationElement;
76 import android.net.util.NetworkStackUtils;
77 import android.net.util.SharedLog;
78 import android.os.Build;
79 import android.os.ConditionVariable;
80 import android.os.Handler;
81 import android.os.IBinder;
82 import android.os.Message;
83 import android.os.RemoteException;
84 import android.os.ServiceSpecificException;
85 import android.os.SystemClock;
86 import android.stats.connectivity.DisconnectCode;
87 import android.stats.connectivity.NetworkQuirkEvent;
88 import android.stats.connectivity.NudEventType;
89 import android.system.ErrnoException;
90 import android.system.Os;
91 import android.text.TextUtils;
92 import android.util.LocalLog;
93 import android.util.Log;
94 import android.util.Pair;
95 import android.util.SparseArray;
96 
97 import androidx.annotation.NonNull;
98 import androidx.annotation.Nullable;
99 
100 import com.android.internal.annotations.VisibleForTesting;
101 import com.android.internal.util.HexDump;
102 import com.android.internal.util.IState;
103 import com.android.internal.util.IndentingPrintWriter;
104 import com.android.internal.util.MessageUtils;
105 import com.android.internal.util.State;
106 import com.android.internal.util.StateMachine;
107 import com.android.internal.util.WakeupMessage;
108 import com.android.net.module.util.DeviceConfigUtils;
109 import com.android.net.module.util.InterfaceParams;
110 import com.android.networkstack.R;
111 import com.android.networkstack.apishim.NetworkInformationShimImpl;
112 import com.android.networkstack.apishim.SocketUtilsShimImpl;
113 import com.android.networkstack.apishim.common.NetworkInformationShim;
114 import com.android.networkstack.apishim.common.ShimUtils;
115 import com.android.networkstack.arp.ArpPacket;
116 import com.android.networkstack.metrics.IpProvisioningMetrics;
117 import com.android.networkstack.metrics.NetworkQuirkMetrics;
118 import com.android.networkstack.packets.NeighborAdvertisement;
119 import com.android.server.NetworkObserverRegistry;
120 import com.android.server.NetworkStackService.NetworkStackServiceManager;
121 
122 import java.io.FileDescriptor;
123 import java.io.PrintWriter;
124 import java.net.Inet4Address;
125 import java.net.Inet6Address;
126 import java.net.InetAddress;
127 import java.net.MalformedURLException;
128 import java.net.SocketAddress;
129 import java.net.SocketException;
130 import java.net.URL;
131 import java.nio.BufferUnderflowException;
132 import java.nio.ByteBuffer;
133 import java.util.ArrayList;
134 import java.util.Arrays;
135 import java.util.Collection;
136 import java.util.Collections;
137 import java.util.HashSet;
138 import java.util.List;
139 import java.util.Map;
140 import java.util.Objects;
141 import java.util.Set;
142 import java.util.concurrent.ConcurrentHashMap;
143 import java.util.concurrent.CountDownLatch;
144 import java.util.function.Predicate;
145 import java.util.stream.Collectors;
146 
147 /**
148  * IpClient
149  *
150  * This class provides the interface to IP-layer provisioning and maintenance
151  * functionality that can be used by transport layers like Wi-Fi, Ethernet,
152  * et cetera.
153  *
154  * [ Lifetime ]
155  * IpClient is designed to be instantiated as soon as the interface name is
156  * known and can be as long-lived as the class containing it (i.e. declaring
157  * it "private final" is okay).
158  *
159  * @hide
160  */
161 public class IpClient extends StateMachine {
162     private static final String TAG = IpClient.class.getSimpleName();
163     private static final boolean DBG = false;
164 
165     // For message logging.
166     private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
167     private static final SparseArray<String> sWhatToString =
168             MessageUtils.findMessageNames(sMessageClasses);
169     // Two static concurrent hashmaps of interface name to logging classes.
170     // One holds StateMachine logs and the other connectivity packet logs.
171     private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
172     private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
173     private final NetworkStackIpMemoryStore mIpMemoryStore;
174     private final NetworkInformationShim mShim = NetworkInformationShimImpl.newInstance();
175     private final IpProvisioningMetrics mIpProvisioningMetrics = new IpProvisioningMetrics();
176     private final NetworkQuirkMetrics mNetworkQuirkMetrics;
177 
178     /**
179      * Dump all state machine and connectivity packet logs to the specified writer.
180      * @param skippedIfaces Interfaces for which logs should not be dumped.
181      */
dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces)182     public static void dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces) {
183         for (String ifname : sSmLogs.keySet()) {
184             if (skippedIfaces.contains(ifname)) continue;
185 
186             writer.println(String.format("--- BEGIN %s ---", ifname));
187 
188             final SharedLog smLog = sSmLogs.get(ifname);
189             if (smLog != null) {
190                 writer.println("State machine log:");
191                 smLog.dump(null, writer, null);
192             }
193 
194             writer.println("");
195 
196             final LocalLog pktLog = sPktLogs.get(ifname);
197             if (pktLog != null) {
198                 writer.println("Connectivity packet log:");
199                 pktLog.readOnlyLocalLog().dump(null, writer, null);
200             }
201 
202             writer.println(String.format("--- END %s ---", ifname));
203         }
204     }
205 
206     // Use a wrapper class to log in order to ensure complete and detailed
207     // logging. This method is lighter weight than annotations/reflection
208     // and has the following benefits:
209     //
210     //     - No invoked method can be forgotten.
211     //       Any new method added to IpClient.Callback must be overridden
212     //       here or it will never be called.
213     //
214     //     - No invoking call site can be forgotten.
215     //       Centralized logging in this way means call sites don't need to
216     //       remember to log, and therefore no call site can be forgotten.
217     //
218     //     - No variation in log format among call sites.
219     //       Encourages logging of any available arguments, and all call sites
220     //       are necessarily logged identically.
221     //
222     // NOTE: Log first because passed objects may or may not be thread-safe and
223     // once passed on to the callback they may be modified by another thread.
224     //
225     // TODO: Find an lighter weight approach.
226     public static class IpClientCallbacksWrapper {
227         private static final String PREFIX = "INVOKE ";
228         private final IIpClientCallbacks mCallback;
229         private final SharedLog mLog;
230         @NonNull
231         private final NetworkInformationShim mShim;
232 
233         @VisibleForTesting
IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log, @NonNull NetworkInformationShim shim)234         protected IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log,
235                 @NonNull NetworkInformationShim shim) {
236             mCallback = callback;
237             mLog = log;
238             mShim = shim;
239         }
240 
log(String msg)241         private void log(String msg) {
242             mLog.log(PREFIX + msg);
243         }
244 
log(String msg, Throwable e)245         private void log(String msg, Throwable e) {
246             mLog.e(PREFIX + msg, e);
247         }
248 
249         /**
250          * Callback called prior to DHCP discovery/renewal only if the pre DHCP action
251          * is enabled.
252          */
onPreDhcpAction()253         public void onPreDhcpAction() {
254             log("onPreDhcpAction()");
255             try {
256                 mCallback.onPreDhcpAction();
257             } catch (RemoteException e) {
258                 log("Failed to call onPreDhcpAction", e);
259             }
260         }
261 
262         /**
263          * Callback called after DHCP discovery/renewal only if the pre DHCP action
264          * is enabled.
265          */
onPostDhcpAction()266         public void onPostDhcpAction() {
267             log("onPostDhcpAction()");
268             try {
269                 mCallback.onPostDhcpAction();
270             } catch (RemoteException e) {
271                 log("Failed to call onPostDhcpAction", e);
272             }
273         }
274 
275         /**
276          * Callback called when new DHCP results are available.
277          */
onNewDhcpResults(DhcpResults dhcpResults)278         public void onNewDhcpResults(DhcpResults dhcpResults) {
279             log("onNewDhcpResults({" + dhcpResults + "})");
280             try {
281                 mCallback.onNewDhcpResults(toStableParcelable(dhcpResults));
282             } catch (RemoteException e) {
283                 log("Failed to call onNewDhcpResults", e);
284             }
285         }
286 
287         /**
288          * Indicates that provisioning was successful.
289          */
onProvisioningSuccess(LinkProperties newLp)290         public void onProvisioningSuccess(LinkProperties newLp) {
291             log("onProvisioningSuccess({" + newLp + "})");
292             try {
293                 mCallback.onProvisioningSuccess(mShim.makeSensitiveFieldsParcelingCopy(newLp));
294             } catch (RemoteException e) {
295                 log("Failed to call onProvisioningSuccess", e);
296             }
297         }
298 
299         /**
300          * Indicates that provisioning failed.
301          */
onProvisioningFailure(LinkProperties newLp)302         public void onProvisioningFailure(LinkProperties newLp) {
303             log("onProvisioningFailure({" + newLp + "})");
304             try {
305                 mCallback.onProvisioningFailure(mShim.makeSensitiveFieldsParcelingCopy(newLp));
306             } catch (RemoteException e) {
307                 log("Failed to call onProvisioningFailure", e);
308             }
309         }
310 
311         /**
312          * Invoked on LinkProperties changes.
313          */
onLinkPropertiesChange(LinkProperties newLp)314         public void onLinkPropertiesChange(LinkProperties newLp) {
315             log("onLinkPropertiesChange({" + newLp + "})");
316             try {
317                 mCallback.onLinkPropertiesChange(mShim.makeSensitiveFieldsParcelingCopy(newLp));
318             } catch (RemoteException e) {
319                 log("Failed to call onLinkPropertiesChange", e);
320             }
321         }
322 
323         /**
324          * Called when the internal IpReachabilityMonitor (if enabled) has detected the loss of
325          * required neighbors (e.g. on-link default gw or dns servers) due to NUD_FAILED.
326          *
327          * Note this method is only supported on networkstack-aidl-interfaces-v12 or below.
328          * For above aidl versions, the caller should call {@link onReachabilityFailure} instead.
329          * For callbacks extending IpClientCallbacks, this method will be called iff the callback
330          * does not implement onReachabilityFailure.
331          */
onReachabilityLost(String logMsg)332         public void onReachabilityLost(String logMsg) {
333             log("onReachabilityLost(" + logMsg + ")");
334             try {
335                 mCallback.onReachabilityLost(logMsg);
336             } catch (RemoteException e) {
337                 log("Failed to call onReachabilityLost", e);
338             }
339         }
340 
341         /**
342          * Called when the IpClient state machine terminates.
343          */
onQuit()344         public void onQuit() {
345             log("onQuit()");
346             try {
347                 mCallback.onQuit();
348             } catch (RemoteException e) {
349                 log("Failed to call onQuit", e);
350             }
351         }
352 
353         /**
354          * Called to indicate that a new APF program must be installed to filter incoming packets.
355          */
installPacketFilter(byte[] filter)356         public void installPacketFilter(byte[] filter) {
357             log("installPacketFilter(byte[" + filter.length + "])");
358             try {
359                 mCallback.installPacketFilter(filter);
360             } catch (RemoteException e) {
361                 log("Failed to call installPacketFilter", e);
362             }
363         }
364 
365         /**
366          * Called to indicate that the APF Program & data buffer must be read asynchronously from
367          * the wifi driver.
368          */
startReadPacketFilter()369         public void startReadPacketFilter() {
370             log("startReadPacketFilter()");
371             try {
372                 mCallback.startReadPacketFilter();
373             } catch (RemoteException e) {
374                 log("Failed to call startReadPacketFilter", e);
375             }
376         }
377 
378         /**
379          * If multicast filtering cannot be accomplished with APF, this function will be called to
380          * actuate multicast filtering using another means.
381          */
setFallbackMulticastFilter(boolean enabled)382         public void setFallbackMulticastFilter(boolean enabled) {
383             log("setFallbackMulticastFilter(" + enabled + ")");
384             try {
385                 mCallback.setFallbackMulticastFilter(enabled);
386             } catch (RemoteException e) {
387                 log("Failed to call setFallbackMulticastFilter", e);
388             }
389         }
390 
391         /**
392          * Enabled/disable Neighbor Discover offload functionality. This is called, for example,
393          * whenever 464xlat is being started or stopped.
394          */
setNeighborDiscoveryOffload(boolean enable)395         public void setNeighborDiscoveryOffload(boolean enable) {
396             log("setNeighborDiscoveryOffload(" + enable + ")");
397             try {
398                 mCallback.setNeighborDiscoveryOffload(enable);
399             } catch (RemoteException e) {
400                 log("Failed to call setNeighborDiscoveryOffload", e);
401             }
402         }
403 
404         /**
405          * Invoked on starting preconnection process.
406          */
onPreconnectionStart(List<Layer2PacketParcelable> packets)407         public void onPreconnectionStart(List<Layer2PacketParcelable> packets) {
408             log("onPreconnectionStart(Layer2Packets[" + packets.size() + "])");
409             try {
410                 mCallback.onPreconnectionStart(packets);
411             } catch (RemoteException e) {
412                 log("Failed to call onPreconnectionStart", e);
413             }
414         }
415 
416         /**
417          * Called when Neighbor Unreachability Detection fails, that might be caused by the organic
418          * probe or probeAll from IpReachabilityMonitor (if enabled).
419          */
onReachabilityFailure(ReachabilityLossInfoParcelable lossInfo)420         public void onReachabilityFailure(ReachabilityLossInfoParcelable lossInfo) {
421             log("onReachabilityFailure(" + lossInfo.message + ", loss reason: "
422                     + reachabilityLossReasonToString(lossInfo.reason) + ")");
423             try {
424                 mCallback.onReachabilityFailure(lossInfo);
425             } catch (RemoteException e) {
426                 log("Failed to call onReachabilityFailure", e);
427             }
428         }
429 
430         /**
431          * Get the version of the IIpClientCallbacks AIDL interface.
432          */
getInterfaceVersion()433         public int getInterfaceVersion() {
434             log("getInterfaceVersion");
435             try {
436                 return mCallback.getInterfaceVersion();
437             } catch (RemoteException e) {
438                 // This can never happen for callers in the system server, because if the
439                 // system server crashes, then the networkstack will crash as well. But it can
440                 // happen for other callers such as bluetooth or telephony (if it starts to use
441                 // IpClient). 0 will generally work but will assume an old client and disable
442                 // all new features.
443                 log("Failed to call getInterfaceVersion", e);
444                 return 0;
445             }
446         }
447     }
448 
449     public static final String DUMP_ARG_CONFIRM = "confirm";
450 
451     // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
452     private static final int CMD_TERMINATE_AFTER_STOP             = 1;
453     private static final int CMD_STOP                             = 2;
454     private static final int CMD_START                            = 3;
455     private static final int CMD_CONFIRM                          = 4;
456     private static final int EVENT_PRE_DHCP_ACTION_COMPLETE       = 5;
457     // Triggered by NetlinkTracker to communicate netlink events.
458     private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
459     private static final int CMD_UPDATE_TCP_BUFFER_SIZES          = 7;
460     private static final int CMD_UPDATE_HTTP_PROXY                = 8;
461     private static final int CMD_SET_MULTICAST_FILTER             = 9;
462     private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
463     private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
464     private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
465     private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
466     private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
467     private static final int CMD_UPDATE_L2KEY_CLUSTER = 15;
468     private static final int CMD_COMPLETE_PRECONNECTION = 16;
469     private static final int CMD_UPDATE_L2INFORMATION = 17;
470 
471     private static final int ARG_LINKPROP_CHANGED_LINKSTATE_DOWN = 0;
472     private static final int ARG_LINKPROP_CHANGED_LINKSTATE_UP = 1;
473 
474     // Internal commands to use instead of trying to call transitionTo() inside
475     // a given State's enter() method. Calling transitionTo() from enter/exit
476     // encounters a Log.wtf() that can cause trouble on eng builds.
477     private static final int CMD_ADDRESSES_CLEARED                = 100;
478     private static final int CMD_JUMP_RUNNING_TO_STOPPING         = 101;
479     private static final int CMD_JUMP_STOPPING_TO_STOPPED         = 102;
480 
481     // IpClient shares a handler with DhcpClient: commands must not overlap
482     public static final int DHCPCLIENT_CMD_BASE = 1000;
483 
484     // Settings and default values.
485     private static final int MAX_LOG_RECORDS = 500;
486     private static final int MAX_PACKET_RECORDS = 100;
487 
488     @VisibleForTesting
489     static final String CONFIG_MIN_RDNSS_LIFETIME = "ipclient_min_rdnss_lifetime";
490     private static final int DEFAULT_MIN_RDNSS_LIFETIME =
491             ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q) ? 120 : 0;
492 
493     private static final boolean NO_CALLBACKS = false;
494     private static final boolean SEND_CALLBACKS = true;
495 
496     private static final int IMMEDIATE_FAILURE_DURATION = 0;
497 
498     private static final int PROV_CHANGE_STILL_NOT_PROVISIONED = 1;
499     private static final int PROV_CHANGE_LOST_PROVISIONING = 2;
500     private static final int PROV_CHANGE_GAINED_PROVISIONING = 3;
501     private static final int PROV_CHANGE_STILL_PROVISIONED = 4;
502 
503     // onReachabilityFailure callback is added since networkstack-aidl-interfaces-v13.
504     @VisibleForTesting
505     static final int VERSION_ADDED_REACHABILITY_FAILURE = 13;
506 
507     // Specific vendor OUI(3 bytes)/vendor specific type(1 byte) pattern for upstream hotspot
508     // device detection. Add new byte array pattern below in turn.
509     private static final List<byte[]> METERED_IE_PATTERN_LIST = Collections.unmodifiableList(
510             Arrays.asList(
511                     new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xf2, (byte) 0x06 }
512     ));
513 
514     // Allows Wi-Fi to pass in DHCP options when particular vendor-specific IEs are present.
515     // Maps each DHCP option code to a list of IEs, any of which will allow that option.
516     private static final Map<Byte, List<byte[]>> DHCP_OPTIONS_ALLOWED = Map.of(
517             (byte) 60, Arrays.asList(
518                     // KT OUI: 00:17:C3, type: 17. See b/170928882.
519                     new byte[]{ (byte) 0x00, (byte) 0x17, (byte) 0xc3, (byte) 0x17 }),
520             (byte) 77, Arrays.asList(
521                     // KT OUI: 00:17:C3, type: 17. See b/170928882.
522                     new byte[]{ (byte) 0x00, (byte) 0x17, (byte) 0xc3, (byte) 0x17 })
523     );
524 
525     // Initialize configurable particular SSID set supporting DHCP Roaming feature. See
526     // b/131797393 for more details.
527     private static final Set<String> DHCP_ROAMING_SSID_SET = new HashSet<>(
528             Arrays.asList(
529                     "0001docomo", "ollehWiFi", "olleh GiGa WiFi", "KT WiFi",
530                     "KT GiGA WiFi", "marente"
531     ));
532 
533     private final State mStoppedState = new StoppedState();
534     private final State mStoppingState = new StoppingState();
535     private final State mClearingIpAddressesState = new ClearingIpAddressesState();
536     private final State mStartedState = new StartedState();
537     private final State mRunningState = new RunningState();
538     private final State mPreconnectingState = new PreconnectingState();
539 
540     private final String mTag;
541     private final Context mContext;
542     private final String mInterfaceName;
543     @VisibleForTesting
544     protected final IpClientCallbacksWrapper mCallback;
545     private final Dependencies mDependencies;
546     private final CountDownLatch mShutdownLatch;
547     private final ConnectivityManager mCm;
548     private final INetd mNetd;
549     private final NetworkObserverRegistry mObserverRegistry;
550     private final IpClientLinkObserver mLinkObserver;
551     private final WakeupMessage mProvisioningTimeoutAlarm;
552     private final WakeupMessage mDhcpActionTimeoutAlarm;
553     private final SharedLog mLog;
554     private final LocalLog mConnectivityPacketLog;
555     private final MessageHandlingLogger mMsgStateLogger;
556     private final IpConnectivityLog mMetricsLog;
557     private final InterfaceController mInterfaceCtrl;
558     // Set of IPv6 addresses for which unsolicited gratuitous NA packets have been sent.
559     private final Set<Inet6Address> mGratuitousNaTargetAddresses = new HashSet<>();
560 
561     // Ignore nonzero RDNSS option lifetimes below this value. 0 = disabled.
562     private final int mMinRdnssLifetimeSec;
563 
564     private InterfaceParams mInterfaceParams;
565 
566     /**
567      * Non-final member variables accessed only from within our StateMachine.
568      */
569     private LinkProperties mLinkProperties;
570     private android.net.shared.ProvisioningConfiguration mConfiguration;
571     private IpReachabilityMonitor mIpReachabilityMonitor;
572     private DhcpClient mDhcpClient;
573     private DhcpResults mDhcpResults;
574     private String mTcpBufferSizes;
575     private ProxyInfo mHttpProxy;
576     private ApfFilter mApfFilter;
577     private String mL2Key; // The L2 key for this network, for writing into the memory store
578     private String mCluster; // The cluster for this network, for writing into the memory store
579     private boolean mMulticastFiltering;
580     private long mStartTimeMillis;
581     private MacAddress mCurrentBssid;
582     private boolean mHasDisabledIpv6OrAcceptRaOnProvLoss;
583 
584     /**
585      * Reading the snapshot is an asynchronous operation initiated by invoking
586      * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
587      * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
588      * signals when a new snapshot is ready.
589      */
590     private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
591 
592     public static class Dependencies {
593         /**
594          * Get interface parameters for the specified interface.
595          */
getInterfaceParams(String ifname)596         public InterfaceParams getInterfaceParams(String ifname) {
597             return InterfaceParams.getByName(ifname);
598         }
599 
600         /**
601          * Get a INetd connector.
602          */
getNetd(Context context)603         public INetd getNetd(Context context) {
604             return INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
605         }
606 
607         /**
608          * Get a IpMemoryStore instance.
609          */
getIpMemoryStore(Context context, NetworkStackServiceManager nssManager)610         public NetworkStackIpMemoryStore getIpMemoryStore(Context context,
611                 NetworkStackServiceManager nssManager) {
612             return new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
613         }
614 
615         /**
616          * Get a DhcpClient instance.
617          */
makeDhcpClient(Context context, StateMachine controller, InterfaceParams ifParams, DhcpClient.Dependencies deps)618         public DhcpClient makeDhcpClient(Context context, StateMachine controller,
619                 InterfaceParams ifParams, DhcpClient.Dependencies deps) {
620             return DhcpClient.makeDhcpClient(context, controller, ifParams, deps);
621         }
622 
623         /**
624          * Get a DhcpClient Dependencies instance.
625          */
getDhcpClientDependencies( NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics)626         public DhcpClient.Dependencies getDhcpClientDependencies(
627                 NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics) {
628             return new DhcpClient.Dependencies(ipMemoryStore, metrics);
629         }
630 
631         /**
632          * Read an integer DeviceConfig property.
633          */
getDeviceConfigPropertyInt(String name, int defaultValue)634         public int getDeviceConfigPropertyInt(String name, int defaultValue) {
635             return DeviceConfigUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name,
636                     defaultValue);
637         }
638 
639         /**
640          * Get a IpConnectivityLog instance.
641          */
getIpConnectivityLog()642         public IpConnectivityLog getIpConnectivityLog() {
643             return new IpConnectivityLog();
644         }
645 
646         /**
647          * Get a NetworkQuirkMetrics instance.
648          */
getNetworkQuirkMetrics()649         public NetworkQuirkMetrics getNetworkQuirkMetrics() {
650             return new NetworkQuirkMetrics();
651         }
652 
653         /**
654          * Get a IpReachabilityMonitor instance.
655          */
getIpReachabilityMonitor(Context context, InterfaceParams ifParams, Handler h, SharedLog log, IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker, IpReachabilityMonitor.Dependencies deps, final INetd netd)656         public IpReachabilityMonitor getIpReachabilityMonitor(Context context,
657                 InterfaceParams ifParams, Handler h, SharedLog log,
658                 IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker,
659                 IpReachabilityMonitor.Dependencies deps, final INetd netd) {
660             return new IpReachabilityMonitor(context, ifParams, h, log, callback,
661                     usingMultinetworkPolicyTracker, deps, netd);
662         }
663 
664         /**
665          * Get a IpReachabilityMonitor dependencies instance.
666          */
getIpReachabilityMonitorDeps(Context context, String name)667         public IpReachabilityMonitor.Dependencies getIpReachabilityMonitorDeps(Context context,
668                 String name) {
669             return IpReachabilityMonitor.Dependencies.makeDefault(context, name);
670         }
671 
672         /**
673          * Return whether a feature guarded by a feature flag is enabled.
674          * @see NetworkStackUtils#isFeatureEnabled(Context, String, String)
675          */
isFeatureEnabled(final Context context, final String name, boolean defaultEnabled)676         public boolean isFeatureEnabled(final Context context, final String name,
677                 boolean defaultEnabled) {
678             return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY, name,
679                     defaultEnabled);
680         }
681 
682         /**
683          * Create an APF filter if apfCapabilities indicates support for packet filtering using
684          * APF programs.
685          * @see ApfFilter#maybeCreate
686          */
maybeCreateApfFilter(Context context, ApfFilter.ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper cb)687         public ApfFilter maybeCreateApfFilter(Context context, ApfFilter.ApfConfiguration config,
688                 InterfaceParams ifParams, IpClientCallbacksWrapper cb) {
689             return ApfFilter.maybeCreate(context, config, ifParams, cb);
690         }
691     }
692 
IpClient(Context context, String ifName, IIpClientCallbacks callback, NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager)693     public IpClient(Context context, String ifName, IIpClientCallbacks callback,
694             NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
695         this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
696     }
697 
698     @VisibleForTesting
IpClient(Context context, String ifName, IIpClientCallbacks callback, NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager, Dependencies deps)699     IpClient(Context context, String ifName, IIpClientCallbacks callback,
700             NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
701             Dependencies deps) {
702         super(IpClient.class.getSimpleName() + "." + ifName);
703         Objects.requireNonNull(ifName);
704         Objects.requireNonNull(callback);
705 
706         mTag = getName();
707 
708         mContext = context;
709         mInterfaceName = ifName;
710         mDependencies = deps;
711         mMetricsLog = deps.getIpConnectivityLog();
712         mNetworkQuirkMetrics = deps.getNetworkQuirkMetrics();
713         mShutdownLatch = new CountDownLatch(1);
714         mCm = mContext.getSystemService(ConnectivityManager.class);
715         mObserverRegistry = observerRegistry;
716         mIpMemoryStore = deps.getIpMemoryStore(context, nssManager);
717 
718         sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
719         mLog = sSmLogs.get(mInterfaceName);
720         sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
721         mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
722         mMsgStateLogger = new MessageHandlingLogger();
723         mCallback = new IpClientCallbacksWrapper(callback, mLog, mShim);
724 
725         // TODO: Consider creating, constructing, and passing in some kind of
726         // InterfaceController.Dependencies class.
727         mNetd = deps.getNetd(mContext);
728         mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
729 
730         mMinRdnssLifetimeSec = mDependencies.getDeviceConfigPropertyInt(
731                 CONFIG_MIN_RDNSS_LIFETIME, DEFAULT_MIN_RDNSS_LIFETIME);
732 
733         IpClientLinkObserver.Configuration config = new IpClientLinkObserver.Configuration(
734                 mMinRdnssLifetimeSec);
735 
736         mLinkObserver = new IpClientLinkObserver(
737                 mContext, getHandler(),
738                 mInterfaceName,
739                 new IpClientLinkObserver.Callback() {
740                     @Override
741                     public void update(boolean linkState) {
742                         sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED, linkState
743                                 ? ARG_LINKPROP_CHANGED_LINKSTATE_UP
744                                 : ARG_LINKPROP_CHANGED_LINKSTATE_DOWN);
745                     }
746 
747                     @Override
748                     public void onIpv6AddressRemoved(final Inet6Address targetIp) {
749                         // The update of Gratuitous NA target addresses set should be only accessed
750                         // from the handler thread of IpClient StateMachine, keeping the behaviour
751                         // consistent with relying on the non-blocking NetworkObserver callbacks,
752                         // see {@link registerObserverForNonblockingCallback}. This can be done
753                         // by either sending a message to StateMachine or posting a handler.
754                         getHandler().post(() -> {
755                             if (!mGratuitousNaTargetAddresses.contains(targetIp)) return;
756                             updateGratuitousNaTargetSet(targetIp, false /* remove address */);
757                         });
758                     }
759 
760                     @Override
761                     public void onClatInterfaceStateUpdate(boolean add) {
762                         // TODO: when clat interface was removed, consider sending a message to
763                         // the IpClient main StateMachine thread, in case "NDO enabled" state
764                         // becomes tied to more things that 464xlat operation.
765                         getHandler().post(() -> {
766                             mCallback.setNeighborDiscoveryOffload(add ? false : true);
767                         });
768                     }
769                 },
770                 config, mLog, mDependencies
771         );
772 
773         mLinkProperties = new LinkProperties();
774         mLinkProperties.setInterfaceName(mInterfaceName);
775 
776         mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
777                 mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
778         mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
779                 mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
780 
781         // Anything the StateMachine may access must have been instantiated
782         // before this point.
783         configureAndStartStateMachine();
784 
785         // Anything that may send messages to the StateMachine must only be
786         // configured to do so after the StateMachine has started (above).
787         startStateMachineUpdaters();
788     }
789 
790     /**
791      * Make a IIpClient connector to communicate with this IpClient.
792      */
makeConnector()793     public IIpClient makeConnector() {
794         return new IpClientConnector();
795     }
796 
797     class IpClientConnector extends IIpClient.Stub {
798         @Override
completedPreDhcpAction()799         public void completedPreDhcpAction() {
800             enforceNetworkStackCallingPermission();
801             IpClient.this.completedPreDhcpAction();
802         }
803         @Override
confirmConfiguration()804         public void confirmConfiguration() {
805             enforceNetworkStackCallingPermission();
806             IpClient.this.confirmConfiguration();
807         }
808         @Override
readPacketFilterComplete(byte[] data)809         public void readPacketFilterComplete(byte[] data) {
810             enforceNetworkStackCallingPermission();
811             IpClient.this.readPacketFilterComplete(data);
812         }
813         @Override
shutdown()814         public void shutdown() {
815             enforceNetworkStackCallingPermission();
816             IpClient.this.shutdown();
817         }
818         @Override
startProvisioning(ProvisioningConfigurationParcelable req)819         public void startProvisioning(ProvisioningConfigurationParcelable req) {
820             enforceNetworkStackCallingPermission();
821             IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req,
822                     mCallback.getInterfaceVersion()));
823         }
824         @Override
stop()825         public void stop() {
826             enforceNetworkStackCallingPermission();
827             IpClient.this.stop();
828         }
829         @Override
setL2KeyAndGroupHint(String l2Key, String cluster)830         public void setL2KeyAndGroupHint(String l2Key, String cluster) {
831             enforceNetworkStackCallingPermission();
832             IpClient.this.setL2KeyAndCluster(l2Key, cluster);
833         }
834         @Override
setTcpBufferSizes(String tcpBufferSizes)835         public void setTcpBufferSizes(String tcpBufferSizes) {
836             enforceNetworkStackCallingPermission();
837             IpClient.this.setTcpBufferSizes(tcpBufferSizes);
838         }
839         @Override
setHttpProxy(ProxyInfo proxyInfo)840         public void setHttpProxy(ProxyInfo proxyInfo) {
841             enforceNetworkStackCallingPermission();
842             IpClient.this.setHttpProxy(proxyInfo);
843         }
844         @Override
setMulticastFilter(boolean enabled)845         public void setMulticastFilter(boolean enabled) {
846             enforceNetworkStackCallingPermission();
847             IpClient.this.setMulticastFilter(enabled);
848         }
849         @Override
addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt)850         public void addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) {
851             enforceNetworkStackCallingPermission();
852             IpClient.this.addKeepalivePacketFilter(slot, pkt);
853         }
854         @Override
addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt)855         public void addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt) {
856             enforceNetworkStackCallingPermission();
857             IpClient.this.addNattKeepalivePacketFilter(slot, pkt);
858         }
859         @Override
removeKeepalivePacketFilter(int slot)860         public void removeKeepalivePacketFilter(int slot) {
861             enforceNetworkStackCallingPermission();
862             IpClient.this.removeKeepalivePacketFilter(slot);
863         }
864         @Override
notifyPreconnectionComplete(boolean success)865         public void notifyPreconnectionComplete(boolean success) {
866             enforceNetworkStackCallingPermission();
867             IpClient.this.notifyPreconnectionComplete(success);
868         }
869         @Override
updateLayer2Information(Layer2InformationParcelable info)870         public void updateLayer2Information(Layer2InformationParcelable info) {
871             enforceNetworkStackCallingPermission();
872             IpClient.this.updateLayer2Information(info);
873         }
874 
875         @Override
getInterfaceVersion()876         public int getInterfaceVersion() {
877             return this.VERSION;
878         }
879 
880         @Override
getInterfaceHash()881         public String getInterfaceHash() {
882             return this.HASH;
883         }
884     }
885 
getInterfaceName()886     public String getInterfaceName() {
887         return mInterfaceName;
888     }
889 
configureAndStartStateMachine()890     private void configureAndStartStateMachine() {
891         // CHECKSTYLE:OFF IndentationCheck
892         addState(mStoppedState);
893         addState(mStartedState);
894             addState(mPreconnectingState, mStartedState);
895             addState(mClearingIpAddressesState, mStartedState);
896             addState(mRunningState, mStartedState);
897         addState(mStoppingState);
898         // CHECKSTYLE:ON IndentationCheck
899 
900         setInitialState(mStoppedState);
901 
902         super.start();
903     }
904 
startStateMachineUpdaters()905     private void startStateMachineUpdaters() {
906         mObserverRegistry.registerObserverForNonblockingCallback(mLinkObserver);
907     }
908 
stopStateMachineUpdaters()909     private void stopStateMachineUpdaters() {
910         mObserverRegistry.unregisterObserver(mLinkObserver);
911         mLinkObserver.clearInterfaceParams();
912         mLinkObserver.shutdown();
913     }
914 
isGratuitousNaEnabled()915     private boolean isGratuitousNaEnabled() {
916         return mDependencies.isFeatureEnabled(mContext, IPCLIENT_GRATUITOUS_NA_VERSION,
917                 false /* defaultEnabled */);
918     }
919 
isGratuitousArpNaRoamingEnabled()920     private boolean isGratuitousArpNaRoamingEnabled() {
921         return mDependencies.isFeatureEnabled(mContext, IPCLIENT_GARP_NA_ROAMING_VERSION,
922                 false /* defaultEnabled */);
923     }
924 
925     @VisibleForTesting
getInitialBssid(final Layer2Information layer2Info, final ScanResultInfo scanResultInfo, boolean isAtLeastS)926     static MacAddress getInitialBssid(final Layer2Information layer2Info,
927             final ScanResultInfo scanResultInfo, boolean isAtLeastS) {
928         MacAddress bssid = null;
929         // http://b/185202634
930         // ScanResultInfo is not populated in some situations.
931         // On S and above, prefer getting the BSSID from the Layer2Info.
932         // On R and below, get the BSSID from the ScanResultInfo and fall back to
933         // getting it from the Layer2Info. This ensures no regressions if any R
934         // devices pass in a null or meaningless BSSID in the Layer2Info.
935         if (!isAtLeastS && scanResultInfo != null) {
936             try {
937                 bssid = MacAddress.fromString(scanResultInfo.getBssid());
938             } catch (IllegalArgumentException e) {
939                 Log.wtf(TAG, "Invalid BSSID: " + scanResultInfo.getBssid()
940                         + " in provisioning configuration", e);
941             }
942         }
943         if (bssid == null && layer2Info != null) {
944             bssid = layer2Info.mBssid;
945         }
946         return bssid;
947     }
948 
shouldDisableAcceptRaOnProvisioningLoss()949     private boolean shouldDisableAcceptRaOnProvisioningLoss() {
950         return mDependencies.isFeatureEnabled(mContext, IPCLIENT_DISABLE_ACCEPT_RA_VERSION,
951                 true /* defaultEnabled */);
952     }
953 
954     @Override
onQuitting()955     protected void onQuitting() {
956         mCallback.onQuit();
957         mShutdownLatch.countDown();
958     }
959 
960     /**
961      * Shut down this IpClient instance altogether.
962      */
shutdown()963     public void shutdown() {
964         stop();
965         sendMessage(CMD_TERMINATE_AFTER_STOP);
966     }
967 
968     /**
969      * Start provisioning with the provided parameters.
970      */
startProvisioning(ProvisioningConfiguration req)971     public void startProvisioning(ProvisioningConfiguration req) {
972         if (!req.isValid()) {
973             doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
974             return;
975         }
976 
977         mCurrentBssid = getInitialBssid(req.mLayer2Info, req.mScanResultInfo,
978                 ShimUtils.isAtLeastS());
979         if (req.mLayer2Info != null) {
980             mL2Key = req.mLayer2Info.mL2Key;
981             mCluster = req.mLayer2Info.mCluster;
982         }
983         sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
984     }
985 
986     /**
987      * Stop this IpClient.
988      *
989      * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}.
990      *    The message "arg1" parameter is used to record the disconnect code metrics.
991      *    Usually this method is called by the peer (e.g. wifi) intentionally to stop IpClient,
992      *    consider that's the normal user termination.
993      */
stop()994     public void stop() {
995         sendMessage(CMD_STOP, DisconnectCode.DC_NORMAL_TERMINATION.getNumber());
996     }
997 
998     /**
999      * Confirm the provisioning configuration.
1000      */
confirmConfiguration()1001     public void confirmConfiguration() {
1002         sendMessage(CMD_CONFIRM);
1003     }
1004 
1005     /**
1006      * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be
1007      * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to
1008      * proceed.
1009      */
completedPreDhcpAction()1010     public void completedPreDhcpAction() {
1011         sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
1012     }
1013 
1014     /**
1015      * Indicate that packet filter read is complete.
1016      */
readPacketFilterComplete(byte[] data)1017     public void readPacketFilterComplete(byte[] data) {
1018         sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
1019     }
1020 
1021     /**
1022      * Set the TCP buffer sizes to use.
1023      *
1024      * This may be called, repeatedly, at any time before or after a call to
1025      * #startProvisioning(). The setting is cleared upon calling #stop().
1026      */
setTcpBufferSizes(String tcpBufferSizes)1027     public void setTcpBufferSizes(String tcpBufferSizes) {
1028         sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
1029     }
1030 
1031     /**
1032      * Set the L2 key and cluster for storing info into the memory store.
1033      *
1034      * This method is only supported on Q devices. For R or above releases,
1035      * caller should call #updateLayer2Information() instead.
1036      */
setL2KeyAndCluster(String l2Key, String cluster)1037     public void setL2KeyAndCluster(String l2Key, String cluster) {
1038         if (!ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) {
1039             sendMessage(CMD_UPDATE_L2KEY_CLUSTER, new Pair<>(l2Key, cluster));
1040         }
1041     }
1042 
1043     /**
1044      * Set the HTTP Proxy configuration to use.
1045      *
1046      * This may be called, repeatedly, at any time before or after a call to
1047      * #startProvisioning(). The setting is cleared upon calling #stop().
1048      */
setHttpProxy(ProxyInfo proxyInfo)1049     public void setHttpProxy(ProxyInfo proxyInfo) {
1050         sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
1051     }
1052 
1053     /**
1054      * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
1055      * if not, Callback.setFallbackMulticastFilter() is called.
1056      */
setMulticastFilter(boolean enabled)1057     public void setMulticastFilter(boolean enabled) {
1058         sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
1059     }
1060 
1061     /**
1062      * Called by WifiStateMachine to add TCP keepalive packet filter before setting up
1063      * keepalive offload.
1064      */
addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt)1065     public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
1066         sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
1067     }
1068 
1069     /**
1070      *  Called by WifiStateMachine to add NATT keepalive packet filter before setting up
1071      *  keepalive offload.
1072      */
addNattKeepalivePacketFilter(int slot, @NonNull NattKeepalivePacketDataParcelable pkt)1073     public void addNattKeepalivePacketFilter(int slot,
1074             @NonNull NattKeepalivePacketDataParcelable pkt) {
1075         sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */ , pkt);
1076     }
1077 
1078     /**
1079      * Called by WifiStateMachine to remove keepalive packet filter after stopping keepalive
1080      * offload.
1081      */
removeKeepalivePacketFilter(int slot)1082     public void removeKeepalivePacketFilter(int slot) {
1083         sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot, 0 /* Unused */);
1084     }
1085 
1086     /**
1087      * Notify IpClient that preconnection is complete and that the link is ready for use.
1088      * The success parameter indicates whether the packets passed in by onPreconnectionStart were
1089      * successfully sent to the network or not.
1090      */
notifyPreconnectionComplete(boolean success)1091     public void notifyPreconnectionComplete(boolean success) {
1092         sendMessage(CMD_COMPLETE_PRECONNECTION, success ? 1 : 0);
1093     }
1094 
1095     /**
1096      * Update the network bssid, L2Key and cluster on L2 roaming happened.
1097      */
updateLayer2Information(@onNull Layer2InformationParcelable info)1098     public void updateLayer2Information(@NonNull Layer2InformationParcelable info) {
1099         sendMessage(CMD_UPDATE_L2INFORMATION, info);
1100     }
1101 
1102     /**
1103      * Dump logs of this IpClient.
1104      */
dump(FileDescriptor fd, PrintWriter writer, String[] args)1105     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1106         if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
1107             // Execute confirmConfiguration() and take no further action.
1108             confirmConfiguration();
1109             return;
1110         }
1111 
1112         // Thread-unsafe access to mApfFilter but just used for debugging.
1113         final ApfFilter apfFilter = mApfFilter;
1114         final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration;
1115         final ApfCapabilities apfCapabilities = (provisioningConfig != null)
1116                 ? provisioningConfig.mApfCapabilities : null;
1117 
1118         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
1119         pw.println(mTag + " APF dump:");
1120         pw.increaseIndent();
1121         if (apfFilter != null) {
1122             if (apfCapabilities.hasDataAccess()) {
1123                 // Request a new snapshot, then wait for it.
1124                 mApfDataSnapshotComplete.close();
1125                 mCallback.startReadPacketFilter();
1126                 if (!mApfDataSnapshotComplete.block(1000)) {
1127                     pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
1128                 }
1129             }
1130             apfFilter.dump(pw);
1131 
1132         } else {
1133             pw.print("No active ApfFilter; ");
1134             if (provisioningConfig == null) {
1135                 pw.println("IpClient not yet started.");
1136             } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
1137                 pw.println("Hardware does not support APF.");
1138             } else {
1139                 pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
1140             }
1141         }
1142         pw.decreaseIndent();
1143         pw.println();
1144         pw.println(mTag + " current ProvisioningConfiguration:");
1145         pw.increaseIndent();
1146         pw.println(Objects.toString(provisioningConfig, "N/A"));
1147         pw.decreaseIndent();
1148 
1149         final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
1150         if (iprm != null) {
1151             pw.println();
1152             pw.println(mTag + " current IpReachabilityMonitor state:");
1153             pw.increaseIndent();
1154             iprm.dump(pw);
1155             pw.decreaseIndent();
1156         }
1157 
1158         pw.println();
1159         pw.println(mTag + " StateMachine dump:");
1160         pw.increaseIndent();
1161         mLog.dump(fd, pw, args);
1162         pw.decreaseIndent();
1163 
1164         pw.println();
1165         pw.println(mTag + " connectivity packet log:");
1166         pw.println();
1167         pw.println("Debug with python and scapy via:");
1168         pw.println("shell$ python");
1169         pw.println(">>> from scapy import all as scapy");
1170         pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
1171         pw.println();
1172 
1173         pw.increaseIndent();
1174         mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
1175         pw.decreaseIndent();
1176     }
1177 
1178 
1179     /**
1180      * Internals.
1181      */
1182 
1183     @Override
getWhatToString(int what)1184     protected String getWhatToString(int what) {
1185         return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
1186     }
1187 
1188     @Override
getLogRecString(Message msg)1189     protected String getLogRecString(Message msg) {
1190         final String logLine = String.format(
1191                 "%s/%d %d %d %s [%s]",
1192                 mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
1193                 msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
1194 
1195         final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
1196         mLog.log(richerLogLine);
1197         if (DBG) {
1198             Log.d(mTag, richerLogLine);
1199         }
1200 
1201         mMsgStateLogger.reset();
1202         return logLine;
1203     }
1204 
1205     @Override
recordLogRec(Message msg)1206     protected boolean recordLogRec(Message msg) {
1207         // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
1208         // and we already log any LinkProperties change that results in an
1209         // invocation of IpClient.Callback#onLinkPropertiesChange().
1210         final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
1211         if (!shouldLog) {
1212             mMsgStateLogger.reset();
1213         }
1214         return shouldLog;
1215     }
1216 
logError(String fmt, Throwable e, Object... args)1217     private void logError(String fmt, Throwable e, Object... args) {
1218         mLog.e(String.format(fmt, args), e);
1219     }
1220 
logError(String fmt, Object... args)1221     private void logError(String fmt, Object... args) {
1222         logError(fmt, null, args);
1223     }
1224 
1225     // This needs to be called with care to ensure that our LinkProperties
1226     // are in sync with the actual LinkProperties of the interface. For example,
1227     // we should only call this if we know for sure that there are no IP addresses
1228     // assigned to the interface, etc.
resetLinkProperties()1229     private void resetLinkProperties() {
1230         mLinkObserver.clearLinkProperties();
1231         mConfiguration = null;
1232         mDhcpResults = null;
1233         mTcpBufferSizes = "";
1234         mHttpProxy = null;
1235 
1236         mLinkProperties = new LinkProperties();
1237         mLinkProperties.setInterfaceName(mInterfaceName);
1238     }
1239 
recordMetric(final int type)1240     private void recordMetric(final int type) {
1241         // We may record error metrics prior to starting.
1242         // Map this to IMMEDIATE_FAILURE_DURATION.
1243         final long duration = (mStartTimeMillis > 0)
1244                 ? (SystemClock.elapsedRealtime() - mStartTimeMillis)
1245                 : IMMEDIATE_FAILURE_DURATION;
1246         mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
1247     }
1248 
1249     // Record the DisconnectCode and transition to StoppingState.
transitionToStoppingState(final DisconnectCode code)1250     private void transitionToStoppingState(final DisconnectCode code) {
1251         mIpProvisioningMetrics.setDisconnectCode(code);
1252         transitionTo(mStoppingState);
1253     }
1254 
1255     // Convert reachability loss reason enum to a string.
reachabilityLossReasonToString(int reason)1256     private static String reachabilityLossReasonToString(int reason) {
1257         switch (reason) {
1258             case ReachabilityLossReason.ROAM:
1259                 return "reachability_loss_after_roam";
1260             case ReachabilityLossReason.CONFIRM:
1261                 return "reachability_loss_after_confirm";
1262             case ReachabilityLossReason.ORGANIC:
1263                 return "reachability_loss_organic";
1264             default:
1265                 return "unknown";
1266         }
1267     }
1268 
hasIpv6LinkLocalInterfaceRoute(final LinkProperties lp)1269     private static boolean hasIpv6LinkLocalInterfaceRoute(final LinkProperties lp) {
1270         for (RouteInfo r : lp.getRoutes()) {
1271             if (r.getDestination().equals(new IpPrefix("fe80::/64"))
1272                     && r.getGateway().isAnyLocalAddress()) {
1273                 return true;
1274             }
1275         }
1276         return false;
1277     }
1278 
hasIpv6LinkLocalAddress(final LinkProperties lp)1279     private static boolean hasIpv6LinkLocalAddress(final LinkProperties lp) {
1280         for (LinkAddress address : lp.getLinkAddresses()) {
1281             if (address.isIpv6() && address.getAddress().isLinkLocalAddress()) {
1282                 return true;
1283             }
1284         }
1285         return false;
1286     }
1287 
1288     // LinkProperties has a link-local (fe80::xxx) IPv6 address and route to fe80::/64 destination.
isIpv6LinkLocalProvisioned(final LinkProperties lp)1289     private boolean isIpv6LinkLocalProvisioned(final LinkProperties lp) {
1290         if (mConfiguration == null
1291                 || mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_LINKLOCAL) return false;
1292         if (hasIpv6LinkLocalAddress(lp) && hasIpv6LinkLocalInterfaceRoute(lp)) return true;
1293         return false;
1294     }
1295 
1296     // For now: use WifiStateMachine's historical notion of provisioned.
1297     @VisibleForTesting
isProvisioned(final LinkProperties lp, final InitialConfiguration config)1298     boolean isProvisioned(final LinkProperties lp, final InitialConfiguration config) {
1299         // For historical reasons, we should connect even if all we have is an IPv4
1300         // address and nothing else. If IPv6 link-local only mode is enabled and
1301         // it's provisioned without IPv4, then still connecting once IPv6 link-local
1302         // address is ready to use and route to fe80::/64 destination is up.
1303         if (lp.hasIpv4Address() || lp.isProvisioned() || isIpv6LinkLocalProvisioned(lp)) {
1304             return true;
1305         }
1306         if (config == null) {
1307             return false;
1308         }
1309 
1310         // When an InitialConfiguration is specified, ignore any difference with previous
1311         // properties and instead check if properties observed match the desired properties.
1312         return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
1313     }
1314 
setIpv6AcceptRa(int acceptRa)1315     private void setIpv6AcceptRa(int acceptRa) {
1316         try {
1317             mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mInterfaceParams.name, "accept_ra",
1318                     Integer.toString(acceptRa));
1319         } catch (Exception e) {
1320             Log.e(mTag, "Failed to set accept_ra to " + acceptRa + ": " + e);
1321         }
1322     }
1323 
restartIpv6WithAcceptRaDisabled()1324     private void restartIpv6WithAcceptRaDisabled() {
1325         mInterfaceCtrl.disableIPv6();
1326         startIPv6(0 /* acceptRa */);
1327     }
1328 
1329     // TODO: Investigate folding all this into the existing static function
1330     // LinkProperties.compareProvisioning() or some other single function that
1331     // takes two LinkProperties objects and returns a ProvisioningChange
1332     // object that is a correct and complete assessment of what changed, taking
1333     // account of the asymmetries described in the comments in this function.
1334     // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
compareProvisioning(LinkProperties oldLp, LinkProperties newLp)1335     private int compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
1336         int delta;
1337         InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
1338         final boolean wasProvisioned = isProvisioned(oldLp, config);
1339         final boolean isProvisioned = isProvisioned(newLp, config);
1340 
1341         if (!wasProvisioned && isProvisioned) {
1342             delta = PROV_CHANGE_GAINED_PROVISIONING;
1343         } else if (wasProvisioned && isProvisioned) {
1344             delta = PROV_CHANGE_STILL_PROVISIONED;
1345         } else if (!wasProvisioned && !isProvisioned) {
1346             delta = PROV_CHANGE_STILL_NOT_PROVISIONED;
1347         } else {
1348             // (wasProvisioned && !isProvisioned)
1349             //
1350             // Note that this is true even if we lose a configuration element
1351             // (e.g., a default gateway) that would not be required to advance
1352             // into provisioned state. This is intended: if we have a default
1353             // router and we lose it, that's a sure sign of a problem, but if
1354             // we connect to a network with no IPv4 DNS servers, we consider
1355             // that to be a network without DNS servers and connect anyway.
1356             //
1357             // See the comment below.
1358             delta = PROV_CHANGE_LOST_PROVISIONING;
1359         }
1360 
1361         final boolean lostIPv6 = oldLp.isIpv6Provisioned() && !newLp.isIpv6Provisioned();
1362         final boolean lostIPv4Address = oldLp.hasIpv4Address() && !newLp.hasIpv4Address();
1363         final boolean lostIPv6Router = oldLp.hasIpv6DefaultRoute() && !newLp.hasIpv6DefaultRoute();
1364 
1365         // If bad wifi avoidance is disabled, then ignore IPv6 loss of
1366         // provisioning. Otherwise, when a hotspot that loses Internet
1367         // access sends out a 0-lifetime RA to its clients, the clients
1368         // will disconnect and then reconnect, avoiding the bad hotspot,
1369         // instead of getting stuck on the bad hotspot. http://b/31827713 .
1370         //
1371         // This is incorrect because if the hotspot then regains Internet
1372         // access with a different prefix, TCP connections on the
1373         // deprecated addresses will remain stuck.
1374         //
1375         // Note that we can still be disconnected by IpReachabilityMonitor
1376         // if the IPv6 default gateway (but not the IPv6 DNS servers; see
1377         // accompanying code in IpReachabilityMonitor) is unreachable.
1378         final boolean ignoreIPv6ProvisioningLoss = mHasDisabledIpv6OrAcceptRaOnProvLoss
1379                 || (mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
1380                         && !mCm.shouldAvoidBadWifi());
1381 
1382         // Additionally:
1383         //
1384         // Partial configurations (e.g., only an IPv4 address with no DNS
1385         // servers and no default route) are accepted as long as DHCPv4
1386         // succeeds. On such a network, isProvisioned() will always return
1387         // false, because the configuration is not complete, but we want to
1388         // connect anyway. It might be a disconnected network such as a
1389         // Chromecast or a wireless printer, for example.
1390         //
1391         // Because on such a network isProvisioned() will always return false,
1392         // delta will never be LOST_PROVISIONING. So check for loss of
1393         // provisioning here too.
1394         if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
1395             delta = PROV_CHANGE_LOST_PROVISIONING;
1396         }
1397 
1398         // Additionally:
1399         //
1400         // If the previous link properties had a global IPv6 address and an
1401         // IPv6 default route then also consider the loss of that default route
1402         // to be a loss of provisioning. See b/27962810.
1403         if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
1404             // Although link properties have lost IPv6 default route in this case, if IPv4 is still
1405             // working with appropriate routes and DNS servers, we can keep the current connection
1406             // without disconnecting from the network, just disable IPv6 or accept_ra parameter on
1407             // that given network until to the next provisioning.
1408             //
1409             // Disabling IPv6 stack will result in all IPv6 connectivity torn down and all IPv6
1410             // sockets being closed, the non-routable IPv6 DNS servers will be stripped out, so
1411             // applications will be able to reconnect immediately over IPv4. See b/131781810.
1412             //
1413             // Sometimes disabling IPv6 stack might introduce other issues(see b/179222860),
1414             // instead disabling accept_ra will result in only IPv4 provisioning and IPv6 link
1415             // local address left on the interface, so applications will be able to reconnect
1416             // immediately over IPv4 and keep IPv6 link-local capable.
1417             if (newLp.isIpv4Provisioned()) {
1418                 if (shouldDisableAcceptRaOnProvisioningLoss()) {
1419                     restartIpv6WithAcceptRaDisabled();
1420                 } else {
1421                     mInterfaceCtrl.disableIPv6();
1422                 }
1423                 mNetworkQuirkMetrics.setEvent(NetworkQuirkEvent.QE_IPV6_PROVISIONING_ROUTER_LOST);
1424                 mNetworkQuirkMetrics.statsWrite();
1425                 mHasDisabledIpv6OrAcceptRaOnProvLoss = true;
1426                 delta = PROV_CHANGE_STILL_PROVISIONED;
1427                 mLog.log(shouldDisableAcceptRaOnProvisioningLoss()
1428                         ? "Disabled accept_ra parameter "
1429                         : "Disabled IPv6 stack completely "
1430                         + "when the IPv6 default router has gone");
1431             } else {
1432                 delta = PROV_CHANGE_LOST_PROVISIONING;
1433             }
1434         }
1435 
1436         return delta;
1437     }
1438 
dispatchCallback(int delta, LinkProperties newLp)1439     private void dispatchCallback(int delta, LinkProperties newLp) {
1440         switch (delta) {
1441             case PROV_CHANGE_GAINED_PROVISIONING:
1442                 if (DBG) {
1443                     Log.d(mTag, "onProvisioningSuccess()");
1444                 }
1445                 recordMetric(IpManagerEvent.PROVISIONING_OK);
1446                 mCallback.onProvisioningSuccess(newLp);
1447                 break;
1448 
1449             case PROV_CHANGE_LOST_PROVISIONING:
1450                 if (DBG) {
1451                     Log.d(mTag, "onProvisioningFailure()");
1452                 }
1453                 recordMetric(IpManagerEvent.PROVISIONING_FAIL);
1454                 mCallback.onProvisioningFailure(newLp);
1455                 break;
1456 
1457             default:
1458                 if (DBG) {
1459                     Log.d(mTag, "onLinkPropertiesChange()");
1460                 }
1461                 mCallback.onLinkPropertiesChange(newLp);
1462                 break;
1463         }
1464     }
1465 
1466     // Updates all IpClient-related state concerned with LinkProperties.
1467     // Returns a ProvisioningChange for possibly notifying other interested
1468     // parties that are not fronted by IpClient.
setLinkProperties(LinkProperties newLp)1469     private int setLinkProperties(LinkProperties newLp) {
1470         if (mApfFilter != null) {
1471             mApfFilter.setLinkProperties(newLp);
1472         }
1473         if (mIpReachabilityMonitor != null) {
1474             mIpReachabilityMonitor.updateLinkProperties(newLp);
1475         }
1476 
1477         int delta = compareProvisioning(mLinkProperties, newLp);
1478         mLinkProperties = new LinkProperties(newLp);
1479 
1480         if (delta == PROV_CHANGE_GAINED_PROVISIONING) {
1481             // TODO: Add a proper ProvisionedState and cancel the alarm in
1482             // its enter() method.
1483             mProvisioningTimeoutAlarm.cancel();
1484         }
1485 
1486         return delta;
1487     }
1488 
assembleLinkProperties()1489     private LinkProperties assembleLinkProperties() {
1490         // [1] Create a new LinkProperties object to populate.
1491         LinkProperties newLp = new LinkProperties();
1492         newLp.setInterfaceName(mInterfaceName);
1493 
1494         // [2] Pull in data from netlink:
1495         //         - IPv4 addresses
1496         //         - IPv6 addresses
1497         //         - IPv6 routes
1498         //         - IPv6 DNS servers
1499         //
1500         // N.B.: this is fundamentally race-prone and should be fixed by
1501         // changing IpClientLinkObserver from a hybrid edge/level model to an
1502         // edge-only model, or by giving IpClient its own netlink socket(s)
1503         // so as to track all required information directly.
1504         LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties();
1505         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
1506         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
1507             newLp.addRoute(route);
1508         }
1509         addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
1510         mShim.setNat64Prefix(newLp, mShim.getNat64Prefix(netlinkLinkProperties));
1511 
1512         // [3] Add in data from DHCPv4, if available.
1513         //
1514         // mDhcpResults is never shared with any other owner so we don't have
1515         // to worry about concurrent modification.
1516         if (mDhcpResults != null) {
1517             final List<RouteInfo> routes =
1518                     mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName);
1519             for (RouteInfo route : routes) {
1520                 newLp.addRoute(route);
1521             }
1522             addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
1523             newLp.setDomains(mDhcpResults.domains);
1524 
1525             if (mDhcpResults.mtu != 0) {
1526                 newLp.setMtu(mDhcpResults.mtu);
1527             }
1528 
1529             if (mDhcpResults.serverAddress != null) {
1530                 mShim.setDhcpServerAddress(newLp, mDhcpResults.serverAddress);
1531             }
1532 
1533             final String capportUrl = mDhcpResults.captivePortalApiUrl;
1534             // Uri.parse does no syntax check; do a simple check to eliminate garbage.
1535             // If the URL is still incorrect data fetching will fail later, which is fine.
1536             if (isParseableUrl(capportUrl)) {
1537                 NetworkInformationShimImpl.newInstance()
1538                         .setCaptivePortalApiUrl(newLp, Uri.parse(capportUrl));
1539             }
1540             // TODO: also look at the IPv6 RA (netlink) for captive portal URL
1541         }
1542 
1543         // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
1544         if (!TextUtils.isEmpty(mTcpBufferSizes)) {
1545             newLp.setTcpBufferSizes(mTcpBufferSizes);
1546         }
1547         if (mHttpProxy != null) {
1548             newLp.setHttpProxy(mHttpProxy);
1549         }
1550 
1551         // [5] Add data from InitialConfiguration
1552         if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
1553             InitialConfiguration config = mConfiguration.mInitialConfig;
1554             // Add InitialConfiguration routes and dns server addresses once all addresses
1555             // specified in the InitialConfiguration have been observed with Netlink.
1556             if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
1557                 for (IpPrefix prefix : config.directlyConnectedRoutes) {
1558                     newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName, RTN_UNICAST));
1559                 }
1560             }
1561             addAllReachableDnsServers(newLp, config.dnsServers);
1562         }
1563         final LinkProperties oldLp = mLinkProperties;
1564         if (DBG) {
1565             Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
1566                     netlinkLinkProperties, newLp, oldLp));
1567         }
1568 
1569         // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
1570         // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
1571         return newLp;
1572     }
1573 
isParseableUrl(String url)1574     private static boolean isParseableUrl(String url) {
1575         // Verify that a URL has a reasonable format that can be parsed as per the URL constructor.
1576         // This does not use Patterns.WEB_URL as that pattern excludes URLs without TLDs, such as on
1577         // localhost.
1578         if (url == null) return false;
1579         try {
1580             new URL(url);
1581             return true;
1582         } catch (MalformedURLException e) {
1583             return false;
1584         }
1585     }
1586 
addAllReachableDnsServers( LinkProperties lp, Iterable<InetAddress> dnses)1587     private static void addAllReachableDnsServers(
1588             LinkProperties lp, Iterable<InetAddress> dnses) {
1589         // TODO: Investigate deleting this reachability check.  We should be
1590         // able to pass everything down to netd and let netd do evaluation
1591         // and RFC6724-style sorting.
1592         for (InetAddress dns : dnses) {
1593             if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
1594                 lp.addDnsServer(dns);
1595             }
1596         }
1597     }
1598 
transmitPacket(final ByteBuffer packet, final SocketAddress sockAddress, final String msg)1599     private void transmitPacket(final ByteBuffer packet, final SocketAddress sockAddress,
1600             final String msg) {
1601         FileDescriptor sock = null;
1602         try {
1603             sock = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0 /* protocol */);
1604             Os.sendto(sock, packet.array(), 0 /* byteOffset */, packet.limit() /* byteCount */,
1605                     0 /* flags */, sockAddress);
1606         } catch (SocketException | ErrnoException e) {
1607             logError(msg, e);
1608         } finally {
1609             NetworkStackUtils.closeSocketQuietly(sock);
1610         }
1611     }
1612 
sendGratuitousNA(final Inet6Address srcIp, final Inet6Address targetIp)1613     private void sendGratuitousNA(final Inet6Address srcIp, final Inet6Address targetIp) {
1614         final int flags = 0; // R=0, S=0, O=0
1615         final Inet6Address dstIp = IPV6_ADDR_ALL_ROUTERS_MULTICAST;
1616         // Ethernet multicast destination address: 33:33:00:00:00:02.
1617         final MacAddress dstMac = NetworkStackUtils.ipv6MulticastToEthernetMulticast(dstIp);
1618         final ByteBuffer packet = NeighborAdvertisement.build(mInterfaceParams.macAddr, dstMac,
1619                 srcIp, dstIp, flags, targetIp);
1620         final SocketAddress sockAddress =
1621                 SocketUtilsShimImpl.newInstance().makePacketSocketAddress(ETH_P_IPV6,
1622                         mInterfaceParams.index, dstMac.toByteArray());
1623 
1624         transmitPacket(packet, sockAddress, "Failed to send Gratuitous Neighbor Advertisement");
1625     }
1626 
sendGratuitousARP(final Inet4Address srcIp)1627     private void sendGratuitousARP(final Inet4Address srcIp) {
1628         final ByteBuffer packet = ArpPacket.buildArpPacket(ETHER_BROADCAST /* dstMac */,
1629                 mInterfaceParams.macAddr.toByteArray() /* srcMac */,
1630                 srcIp.getAddress() /* targetIp */,
1631                 ETHER_BROADCAST /* targetHwAddress */,
1632                 srcIp.getAddress() /* senderIp */, (short) ARP_REPLY);
1633         final SocketAddress sockAddress =
1634                 makePacketSocketAddress(ETH_P_ARP, mInterfaceParams.index);
1635 
1636         transmitPacket(packet, sockAddress, "Failed to send GARP");
1637     }
1638 
1639     @Nullable
getIpv6LinkLocalAddress(final LinkProperties newLp)1640     private static Inet6Address getIpv6LinkLocalAddress(final LinkProperties newLp) {
1641         for (LinkAddress la : newLp.getLinkAddresses()) {
1642             if (!la.isIpv6()) continue;
1643             final Inet6Address ip = (Inet6Address) la.getAddress();
1644             if (ip.isLinkLocalAddress()) return ip;
1645         }
1646         return null;
1647     }
1648 
updateGratuitousNaTargetSet(@onNull final Inet6Address targetIp, boolean add)1649     private void updateGratuitousNaTargetSet(@NonNull final Inet6Address targetIp, boolean add) {
1650         if (add) {
1651             mGratuitousNaTargetAddresses.add(targetIp);
1652         } else {
1653             mGratuitousNaTargetAddresses.remove(targetIp);
1654         }
1655         mLog.log((add ? "Add" : "Remove") + " global IPv6 address " + targetIp
1656                 + (add ? " to" : " from") + " the set of gratuitous NA target address.");
1657     }
1658 
maybeSendGratuitousNAs(final LinkProperties lp, boolean afterRoaming)1659     private void maybeSendGratuitousNAs(final LinkProperties lp, boolean afterRoaming) {
1660         if (!lp.hasGlobalIpv6Address()) return;
1661 
1662         final Inet6Address srcIp = getIpv6LinkLocalAddress(lp);
1663         if (srcIp == null) return;
1664 
1665         // TODO: add experiment with sending only one gratuitous NA packet instead of one
1666         // packet per address.
1667         for (LinkAddress la : lp.getLinkAddresses()) {
1668             if (!la.isIpv6() || !la.isGlobalPreferred()) continue;
1669             final Inet6Address targetIp = (Inet6Address) la.getAddress();
1670             // Already sent gratuitous NA with this target global IPv6 address. But for
1671             // the L2 roaming case, device should always (re)transmit Gratuitous NA for
1672             // each IPv6 global unicast address respectively after roaming.
1673             if (!afterRoaming && mGratuitousNaTargetAddresses.contains(targetIp)) continue;
1674             if (DBG) {
1675                 mLog.log("send Gratuitous NA from " + srcIp.getHostAddress() + " for "
1676                         + targetIp.getHostAddress() + (afterRoaming ? " after roaming" : ""));
1677             }
1678             sendGratuitousNA(srcIp, targetIp);
1679             if (!afterRoaming) updateGratuitousNaTargetSet(targetIp, true /* add address */);
1680         }
1681     }
1682 
maybeSendGratuitousARP(final LinkProperties lp)1683     private void maybeSendGratuitousARP(final LinkProperties lp) {
1684         for (LinkAddress address : lp.getLinkAddresses()) {
1685             if (address.getAddress() instanceof Inet4Address) {
1686                 final Inet4Address srcIp = (Inet4Address) address.getAddress();
1687                 if (DBG) {
1688                     mLog.log("send GARP for " + srcIp.getHostAddress() + " HW address: "
1689                             + mInterfaceParams.macAddr);
1690                 }
1691                 sendGratuitousARP(srcIp);
1692             }
1693         }
1694     }
1695 
1696     // Returns false if we have lost provisioning, true otherwise.
handleLinkPropertiesUpdate(boolean sendCallbacks)1697     private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
1698         final LinkProperties newLp = assembleLinkProperties();
1699         if (Objects.equals(newLp, mLinkProperties)) {
1700             return true;
1701         }
1702 
1703         // Check if new assigned IPv6 GUA is available in the LinkProperties now. If so, initiate
1704         // gratuitous multicast unsolicited Neighbor Advertisements as soon as possible to inform
1705         // first-hop routers that the new GUA host is goning to use.
1706         if (isGratuitousNaEnabled()) {
1707             maybeSendGratuitousNAs(newLp, false /* isGratuitousNaAfterRoaming */);
1708         }
1709 
1710         // Either success IPv4 or IPv6 provisioning triggers new LinkProperties update,
1711         // wait for the provisioning completion and record the latency.
1712         mIpProvisioningMetrics.setIPv4ProvisionedLatencyOnFirstTime(newLp.isIpv4Provisioned());
1713         mIpProvisioningMetrics.setIPv6ProvisionedLatencyOnFirstTime(newLp.isIpv6Provisioned());
1714 
1715         final int delta = setLinkProperties(newLp);
1716         // Most of the attributes stored in the memory store are deduced from
1717         // the link properties, therefore when the properties update the memory
1718         // store record should be updated too.
1719         maybeSaveNetworkToIpMemoryStore();
1720         if (sendCallbacks) {
1721             dispatchCallback(delta, newLp);
1722         }
1723         return (delta != PROV_CHANGE_LOST_PROVISIONING);
1724     }
1725 
1726     @VisibleForTesting
removeDoubleQuotes(@onNull String ssid)1727     static String removeDoubleQuotes(@NonNull String ssid) {
1728         final int length = ssid.length();
1729         if ((length > 1) && (ssid.charAt(0) == '"') && (ssid.charAt(length - 1) == '"')) {
1730             return ssid.substring(1, length - 1);
1731         }
1732         return ssid;
1733     }
1734 
getVendorSpecificIEs(@onNull ScanResultInfo scanResultInfo)1735     private static List<ByteBuffer> getVendorSpecificIEs(@NonNull ScanResultInfo scanResultInfo) {
1736         ArrayList<ByteBuffer> vendorSpecificPayloadList = new ArrayList<>();
1737         for (InformationElement ie : scanResultInfo.getInformationElements()) {
1738             if (ie.getId() == VENDOR_SPECIFIC_IE_ID) {
1739                 vendorSpecificPayloadList.add(ie.getPayload());
1740             }
1741         }
1742         return vendorSpecificPayloadList;
1743     }
1744 
checkIfOuiAndTypeMatched(@onNull ScanResultInfo scanResultInfo, @NonNull List<byte[]> patternList)1745     private boolean checkIfOuiAndTypeMatched(@NonNull ScanResultInfo scanResultInfo,
1746             @NonNull List<byte[]> patternList) {
1747         final List<ByteBuffer> vendorSpecificPayloadList = getVendorSpecificIEs(scanResultInfo);
1748 
1749         for (ByteBuffer payload : vendorSpecificPayloadList) {
1750             byte[] ouiAndType = new byte[4];
1751             try {
1752                 payload.get(ouiAndType);
1753             } catch (BufferUnderflowException e) {
1754                 Log.e(mTag, "Couldn't parse vendor specific IE, buffer underflow");
1755                 return false;
1756             }
1757             for (byte[] pattern : patternList) {
1758                 if (Arrays.equals(pattern, ouiAndType)) {
1759                     if (DBG) {
1760                         Log.d(mTag, "match pattern: " + HexDump.toHexString(ouiAndType));
1761                     }
1762                     return true;
1763                 }
1764             }
1765         }
1766         return false;
1767     }
1768 
detectUpstreamHotspotFromVendorIe()1769     private boolean detectUpstreamHotspotFromVendorIe() {
1770         final ScanResultInfo scanResultInfo = mConfiguration.mScanResultInfo;
1771         if (scanResultInfo == null) return false;
1772         final String ssid = scanResultInfo.getSsid();
1773 
1774         if (mConfiguration.mDisplayName == null
1775                 || !removeDoubleQuotes(mConfiguration.mDisplayName).equals(ssid)) {
1776             return false;
1777         }
1778         return checkIfOuiAndTypeMatched(scanResultInfo, METERED_IE_PATTERN_LIST);
1779     }
1780 
handleIPv4Success(DhcpResults dhcpResults)1781     private void handleIPv4Success(DhcpResults dhcpResults) {
1782         mDhcpResults = new DhcpResults(dhcpResults);
1783         final LinkProperties newLp = assembleLinkProperties();
1784         final int delta = setLinkProperties(newLp);
1785 
1786         if (mDhcpResults.vendorInfo == null && detectUpstreamHotspotFromVendorIe()) {
1787             mDhcpResults.vendorInfo = DhcpPacket.VENDOR_INFO_ANDROID_METERED;
1788         }
1789 
1790         if (DBG) {
1791             Log.d(mTag, "onNewDhcpResults(" + Objects.toString(mDhcpResults) + ")");
1792             Log.d(mTag, "handleIPv4Success newLp{" + newLp + "}");
1793         }
1794         mCallback.onNewDhcpResults(mDhcpResults);
1795         maybeSaveNetworkToIpMemoryStore();
1796 
1797         dispatchCallback(delta, newLp);
1798     }
1799 
handleIPv4Failure()1800     private void handleIPv4Failure() {
1801         // TODO: Investigate deleting this clearIPv4Address() call.
1802         //
1803         // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
1804         // that could trigger a call to this function. If we missed handling
1805         // that message in StartedState for some reason we would still clear
1806         // any addresses upon entry to StoppedState.
1807         mInterfaceCtrl.clearIPv4Address();
1808         mDhcpResults = null;
1809         if (DBG) {
1810             Log.d(mTag, "onNewDhcpResults(null)");
1811         }
1812         mCallback.onNewDhcpResults(null);
1813 
1814         handleProvisioningFailure(DisconnectCode.DC_PROVISIONING_FAIL);
1815     }
1816 
handleProvisioningFailure(final DisconnectCode code)1817     private void handleProvisioningFailure(final DisconnectCode code) {
1818         final LinkProperties newLp = assembleLinkProperties();
1819         int delta = setLinkProperties(newLp);
1820         // If we've gotten here and we're still not provisioned treat that as
1821         // a total loss of provisioning.
1822         //
1823         // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
1824         // there was no usable IPv6 obtained before a non-zero provisioning
1825         // timeout expired.
1826         //
1827         // Regardless: GAME OVER.
1828         if (delta == PROV_CHANGE_STILL_NOT_PROVISIONED) {
1829             delta = PROV_CHANGE_LOST_PROVISIONING;
1830         }
1831 
1832         dispatchCallback(delta, newLp);
1833         if (delta == PROV_CHANGE_LOST_PROVISIONING) {
1834             transitionToStoppingState(code);
1835         }
1836     }
1837 
doImmediateProvisioningFailure(int failureType)1838     private void doImmediateProvisioningFailure(int failureType) {
1839         logError("onProvisioningFailure(): %s", failureType);
1840         recordMetric(failureType);
1841         mCallback.onProvisioningFailure(mLinkProperties);
1842     }
1843 
1844     @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
startIPv4()1845     private boolean startIPv4() {
1846         // If we have a StaticIpConfiguration attempt to apply it and
1847         // handle the result accordingly.
1848         if (mConfiguration.mStaticIpConfig != null) {
1849             if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {
1850                 handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
1851             } else {
1852                 return false;
1853             }
1854         } else {
1855             if (mDhcpClient != null) {
1856                 Log.wtf(mTag, "DhcpClient should never be non-null in startIPv4()");
1857             }
1858             startDhcpClient();
1859         }
1860 
1861         return true;
1862     }
1863 
startIPv6(int acceptRa)1864     private boolean startIPv6(int acceptRa) {
1865         setIpv6AcceptRa(acceptRa);
1866         return mInterfaceCtrl.setIPv6PrivacyExtensions(true)
1867                 && mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode)
1868                 && mInterfaceCtrl.enableIPv6();
1869     }
1870 
applyInitialConfig(InitialConfiguration config)1871     private boolean applyInitialConfig(InitialConfiguration config) {
1872         // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
1873         for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIpv6)) {
1874             if (!mInterfaceCtrl.addAddress(addr)) return false;
1875         }
1876 
1877         return true;
1878     }
1879 
startIpReachabilityMonitor()1880     private boolean startIpReachabilityMonitor() {
1881         try {
1882             mIpReachabilityMonitor = mDependencies.getIpReachabilityMonitor(
1883                     mContext,
1884                     mInterfaceParams,
1885                     getHandler(),
1886                     mLog,
1887                     new IpReachabilityMonitor.Callback() {
1888                         @Override
1889                         public void notifyLost(InetAddress ip, String logMsg, NudEventType type) {
1890                             final int version = mCallback.getInterfaceVersion();
1891                             if (version >= VERSION_ADDED_REACHABILITY_FAILURE) {
1892                                 final int reason = nudEventTypeToInt(type);
1893                                 if (reason == INVALID_REACHABILITY_LOSS_TYPE) return;
1894                                 final ReachabilityLossInfoParcelable lossInfo =
1895                                         new ReachabilityLossInfoParcelable(logMsg, reason);
1896                                 mCallback.onReachabilityFailure(lossInfo);
1897                             } else {
1898                                 mCallback.onReachabilityLost(logMsg);
1899                             }
1900                         }
1901                     },
1902                     mConfiguration.mUsingMultinetworkPolicyTracker,
1903                     mDependencies.getIpReachabilityMonitorDeps(mContext, mInterfaceParams.name),
1904                     mNetd);
1905         } catch (IllegalArgumentException iae) {
1906             // Failed to start IpReachabilityMonitor. Log it and call
1907             // onProvisioningFailure() immediately.
1908             //
1909             // See http://b/31038971.
1910             logError("IpReachabilityMonitor failure: %s", iae);
1911             mIpReachabilityMonitor = null;
1912         }
1913 
1914         return (mIpReachabilityMonitor != null);
1915     }
1916 
stopAllIP()1917     private void stopAllIP() {
1918         // We don't need to worry about routes, just addresses, because:
1919         //     - disableIpv6() will clear autoconf IPv6 routes as well, and
1920         //     - we don't get IPv4 routes from netlink
1921         // so we neither react to nor need to wait for changes in either.
1922 
1923         mInterfaceCtrl.disableIPv6();
1924         mInterfaceCtrl.clearAllAddresses();
1925     }
1926 
maybeSaveNetworkToIpMemoryStore()1927     private void maybeSaveNetworkToIpMemoryStore() {
1928         // TODO : implement this
1929     }
1930 
maybeRestoreInterfaceMtu()1931     private void maybeRestoreInterfaceMtu() {
1932         InterfaceParams params = mDependencies.getInterfaceParams(mInterfaceName);
1933         if (params == null) {
1934             Log.w(mTag, "interface: " + mInterfaceName + " is gone");
1935             return;
1936         }
1937 
1938         // Check whether "mInterfaceParams" is null or not to prevent the potential NPE
1939         // introduced if the interface was initially not found, but came back before this
1940         // method was called. See b/162808916 for more details. TODO: query the new interface
1941         // parameters by the interface index instead and check that the index has not changed.
1942         if (mInterfaceParams == null || params.index != mInterfaceParams.index) {
1943             Log.w(mTag, "interface: " + mInterfaceName + " has a different index: " + params.index);
1944             return;
1945         }
1946 
1947         if (params.defaultMtu == mInterfaceParams.defaultMtu) return;
1948 
1949         try {
1950             mNetd.interfaceSetMtu(mInterfaceName, mInterfaceParams.defaultMtu);
1951         } catch (RemoteException | ServiceSpecificException e) {
1952             logError("Couldn't reset MTU on " + mInterfaceName + " from "
1953                     + params.defaultMtu + " to " + mInterfaceParams.defaultMtu, e);
1954         }
1955     }
1956 
handleUpdateL2Information(@onNull Layer2InformationParcelable info)1957     private void handleUpdateL2Information(@NonNull Layer2InformationParcelable info) {
1958         mL2Key = info.l2Key;
1959         mCluster = info.cluster;
1960 
1961         // Sometimes the wifi code passes in a null BSSID. Don't use Log.wtf in R because
1962         // it's a known bug that will not be fixed in R.
1963         if (info.bssid == null || mCurrentBssid == null) {
1964             final String msg = "bssid in the parcelable: " + info.bssid + " or "
1965                     + "current tracked bssid: " + mCurrentBssid + " is null";
1966             if (ShimUtils.isAtLeastS()) {
1967                 Log.wtf(mTag, msg);
1968             } else {
1969                 Log.w(mTag, msg);
1970             }
1971             return;
1972         }
1973 
1974         // If the BSSID has not changed, there is nothing to do.
1975         if (info.bssid.equals(mCurrentBssid)) return;
1976 
1977         // Before trigger probing to the critical neighbors, send Gratuitous ARP
1978         // and Neighbor Advertisment in advance to propgate host's IPv4/v6 addresses.
1979         if (isGratuitousArpNaRoamingEnabled()) {
1980             maybeSendGratuitousARP(mLinkProperties);
1981             maybeSendGratuitousNAs(mLinkProperties, true /* isGratuitousNaAfterRoaming */);
1982         }
1983 
1984         // Check whether attempting to refresh previous IP lease on specific networks or need to
1985         // probe the critical neighbors proactively on L2 roaming happened. The NUD probe on the
1986         // specific networks is cancelled because otherwise the probe will happen in parallel with
1987         // DHCP refresh, it will be difficult to understand what happened exactly and error-prone
1988         // to introduce race condition.
1989         final String ssid = removeDoubleQuotes(mConfiguration.mDisplayName);
1990         if (DHCP_ROAMING_SSID_SET.contains(ssid) && mDhcpClient != null) {
1991             if (DBG) {
1992                 Log.d(mTag, "L2 roaming happened from " + mCurrentBssid
1993                         + " to " + info.bssid
1994                         + " , SSID: " + ssid
1995                         + " , starting refresh leased IP address");
1996             }
1997             mDhcpClient.sendMessage(DhcpClient.CMD_REFRESH_LINKADDRESS);
1998         } else if (mIpReachabilityMonitor != null) {
1999             mIpReachabilityMonitor.probeAll(true /* dueToRoam */);
2000         }
2001         mCurrentBssid = info.bssid;
2002     }
2003 
2004     class StoppedState extends State {
2005         @Override
enter()2006         public void enter() {
2007             stopAllIP();
2008             mHasDisabledIpv6OrAcceptRaOnProvLoss = false;
2009             mGratuitousNaTargetAddresses.clear();
2010 
2011             resetLinkProperties();
2012             if (mStartTimeMillis > 0) {
2013                 // Completed a life-cycle; send a final empty LinkProperties
2014                 // (cleared in resetLinkProperties() above) and record an event.
2015                 mCallback.onLinkPropertiesChange(mLinkProperties);
2016                 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
2017                 mStartTimeMillis = 0;
2018             }
2019         }
2020 
2021         @Override
processMessage(Message msg)2022         public boolean processMessage(Message msg) {
2023             switch (msg.what) {
2024                 case CMD_TERMINATE_AFTER_STOP:
2025                     stopStateMachineUpdaters();
2026                     quit();
2027                     break;
2028 
2029                 case CMD_STOP:
2030                     break;
2031 
2032                 case CMD_START:
2033                     mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
2034                     transitionTo(mClearingIpAddressesState);
2035                     break;
2036 
2037                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
2038                     handleLinkPropertiesUpdate(NO_CALLBACKS);
2039                     break;
2040 
2041                 case CMD_UPDATE_TCP_BUFFER_SIZES:
2042                     mTcpBufferSizes = (String) msg.obj;
2043                     handleLinkPropertiesUpdate(NO_CALLBACKS);
2044                     break;
2045 
2046                 case CMD_UPDATE_HTTP_PROXY:
2047                     mHttpProxy = (ProxyInfo) msg.obj;
2048                     handleLinkPropertiesUpdate(NO_CALLBACKS);
2049                     break;
2050 
2051                 case CMD_UPDATE_L2KEY_CLUSTER: {
2052                     final Pair<String, String> args = (Pair<String, String>) msg.obj;
2053                     mL2Key = args.first;
2054                     mCluster = args.second;
2055                     break;
2056                 }
2057 
2058                 case CMD_SET_MULTICAST_FILTER:
2059                     mMulticastFiltering = (boolean) msg.obj;
2060                     break;
2061 
2062                 case DhcpClient.CMD_ON_QUIT:
2063                     // Everything is already stopped.
2064                     logError("Unexpected CMD_ON_QUIT (already stopped).");
2065                     break;
2066 
2067                 default:
2068                     return NOT_HANDLED;
2069             }
2070 
2071             mMsgStateLogger.handled(this, getCurrentState());
2072             return HANDLED;
2073         }
2074     }
2075 
2076     class StoppingState extends State {
2077         @Override
enter()2078         public void enter() {
2079             if (mDhcpClient == null) {
2080                 // There's no DHCPv4 for which to wait; proceed to stopped.
2081                 deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
2082             } else {
2083                 mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
2084                 mDhcpClient.doQuit();
2085             }
2086 
2087             // Restore the interface MTU to initial value if it has changed.
2088             maybeRestoreInterfaceMtu();
2089         }
2090 
2091         @Override
processMessage(Message msg)2092         public boolean processMessage(Message msg) {
2093             switch (msg.what) {
2094                 case CMD_JUMP_STOPPING_TO_STOPPED:
2095                     transitionTo(mStoppedState);
2096                     break;
2097 
2098                 case CMD_STOP:
2099                     break;
2100 
2101                 case DhcpClient.CMD_CLEAR_LINKADDRESS:
2102                     mInterfaceCtrl.clearIPv4Address();
2103                     break;
2104 
2105                 case DhcpClient.CMD_ON_QUIT:
2106                     mDhcpClient = null;
2107                     transitionTo(mStoppedState);
2108                     break;
2109 
2110                 default:
2111                     deferMessage(msg);
2112             }
2113 
2114             mMsgStateLogger.handled(this, getCurrentState());
2115             return HANDLED;
2116         }
2117     }
2118 
isUsingPreconnection()2119     private boolean isUsingPreconnection() {
2120         return mConfiguration.mEnablePreconnection && mConfiguration.mStaticIpConfig == null;
2121     }
2122 
2123     /**
2124      * Check if the customized DHCP client options passed from Wi-Fi are allowed to be put
2125      * in PRL or in the DHCP packet.
2126      */
maybeFilterCustomizedDhcpOptions()2127     private List<DhcpOption> maybeFilterCustomizedDhcpOptions() {
2128         final List<DhcpOption> options = new ArrayList<DhcpOption>();
2129         if (mConfiguration.mDhcpOptions == null
2130                 || mConfiguration.mScanResultInfo == null) return options; // empty DhcpOption list
2131 
2132         for (DhcpOption option : mConfiguration.mDhcpOptions) {
2133             final List<byte[]> patternList = DHCP_OPTIONS_ALLOWED.get(option.type);
2134             // requested option won't be added if no vendor-specific IE oui/type allows this option.
2135             if (patternList == null) continue;
2136             if (checkIfOuiAndTypeMatched(mConfiguration.mScanResultInfo, patternList)) {
2137                 options.add(option);
2138             }
2139         }
2140         Collections.sort(options, (o1, o2) ->
2141                 Integer.compare(Byte.toUnsignedInt(o1.type), Byte.toUnsignedInt(o2.type)));
2142         return options;
2143     }
2144 
startDhcpClient()2145     private void startDhcpClient() {
2146         // Start DHCPv4.
2147         mDhcpClient = mDependencies.makeDhcpClient(mContext, IpClient.this, mInterfaceParams,
2148                 mDependencies.getDhcpClientDependencies(mIpMemoryStore, mIpProvisioningMetrics));
2149 
2150         // Check if the vendor-specific IE oui/type matches and filters the customized DHCP options.
2151         final List<DhcpOption> options = maybeFilterCustomizedDhcpOptions();
2152 
2153         // If preconnection is enabled, there is no need to ask Wi-Fi to disable powersaving
2154         // during DHCP, because the DHCP handshake will happen during association. In order to
2155         // ensure that future renews still do the DHCP action (if configured),
2156         // registerForPreDhcpNotification is called later when processing the CMD_*_PRECONNECTION
2157         // messages.
2158         if (!isUsingPreconnection()) mDhcpClient.registerForPreDhcpNotification();
2159         mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP, new DhcpClient.Configuration(mL2Key,
2160                 isUsingPreconnection(), options));
2161     }
2162 
2163     class ClearingIpAddressesState extends State {
2164         @Override
enter()2165         public void enter() {
2166             // Ensure that interface parameters are fetched on the handler thread so they are
2167             // properly ordered with other events, such as restoring the interface MTU on teardown.
2168             mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
2169             if (mInterfaceParams == null) {
2170                 logError("Failed to find InterfaceParams for " + mInterfaceName);
2171                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
2172                 deferMessage(obtainMessage(CMD_STOP,
2173                         DisconnectCode.DC_INTERFACE_NOT_FOUND.getNumber()));
2174                 return;
2175             }
2176 
2177             mLinkObserver.setInterfaceParams(mInterfaceParams);
2178 
2179             if (readyToProceed()) {
2180                 deferMessage(obtainMessage(CMD_ADDRESSES_CLEARED));
2181             } else {
2182                 // Clear all IPv4 and IPv6 before proceeding to RunningState.
2183                 // Clean up any leftover state from an abnormal exit from
2184                 // tethering or during an IpClient restart.
2185                 stopAllIP();
2186             }
2187 
2188             mCallback.setNeighborDiscoveryOffload(true);
2189         }
2190 
2191         @Override
processMessage(Message msg)2192         public boolean processMessage(Message msg) {
2193             switch (msg.what) {
2194                 case CMD_ADDRESSES_CLEARED:
2195                     transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState);
2196                     break;
2197 
2198                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
2199                     handleLinkPropertiesUpdate(NO_CALLBACKS);
2200                     if (readyToProceed()) {
2201                         transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState);
2202                     }
2203                     break;
2204 
2205                 case CMD_STOP:
2206                 case EVENT_PROVISIONING_TIMEOUT:
2207                     // Fall through to StartedState.
2208                     return NOT_HANDLED;
2209 
2210                 default:
2211                     // It's safe to process messages out of order because the
2212                     // only message that can both
2213                     //     a) be received at this time and
2214                     //     b) affect provisioning state
2215                     // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
2216                     deferMessage(msg);
2217             }
2218             return HANDLED;
2219         }
2220 
readyToProceed()2221         private boolean readyToProceed() {
2222             return !mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address();
2223         }
2224     }
2225 
2226     class PreconnectingState extends State {
2227         @Override
enter()2228         public void enter() {
2229             startDhcpClient();
2230         }
2231 
2232         @Override
processMessage(Message msg)2233         public boolean processMessage(Message msg) {
2234             switch (msg.what) {
2235                 case CMD_COMPLETE_PRECONNECTION:
2236                     boolean success = (msg.arg1 == 1);
2237                     mDhcpClient.registerForPreDhcpNotification();
2238                     if (!success) {
2239                         mDhcpClient.sendMessage(DhcpClient.CMD_ABORT_PRECONNECTION);
2240                     }
2241                     // The link is ready for use. Advance to running state, start IPv6, etc.
2242                     transitionTo(mRunningState);
2243                     break;
2244 
2245                 case DhcpClient.CMD_START_PRECONNECTION:
2246                     final Layer2PacketParcelable l2Packet = (Layer2PacketParcelable) msg.obj;
2247                     mCallback.onPreconnectionStart(Collections.singletonList(l2Packet));
2248                     break;
2249 
2250                 case CMD_STOP:
2251                 case EVENT_PROVISIONING_TIMEOUT:
2252                     // Fall through to StartedState.
2253                     return NOT_HANDLED;
2254 
2255                 default:
2256                     deferMessage(msg);
2257             }
2258             return HANDLED;
2259         }
2260     }
2261 
2262     class StartedState extends State {
2263         @Override
enter()2264         public void enter() {
2265             mIpProvisioningMetrics.reset();
2266             mStartTimeMillis = SystemClock.elapsedRealtime();
2267             if (mConfiguration.mProvisioningTimeoutMs > 0) {
2268                 final long alarmTime = SystemClock.elapsedRealtime()
2269                         + mConfiguration.mProvisioningTimeoutMs;
2270                 mProvisioningTimeoutAlarm.schedule(alarmTime);
2271             }
2272         }
2273 
2274         @Override
exit()2275         public void exit() {
2276             mProvisioningTimeoutAlarm.cancel();
2277 
2278             // Record metrics information once this provisioning has completed due to certain
2279             // reason (normal termination, provisioning timeout, lost provisioning and etc).
2280             mIpProvisioningMetrics.statsWrite();
2281         }
2282 
2283         @Override
processMessage(Message msg)2284         public boolean processMessage(Message msg) {
2285             switch (msg.what) {
2286                 case CMD_STOP:
2287                     transitionToStoppingState(DisconnectCode.forNumber(msg.arg1));
2288                     break;
2289 
2290                 case CMD_UPDATE_L2KEY_CLUSTER: {
2291                     final Pair<String, String> args = (Pair<String, String>) msg.obj;
2292                     mL2Key = args.first;
2293                     mCluster = args.second;
2294                     // TODO : attributes should be saved to the memory store with
2295                     // these new values if they differ from the previous ones.
2296                     // If the state machine is in pure StartedState, then the values to input
2297                     // are not known yet and should be updated when the LinkProperties are updated.
2298                     // If the state machine is in RunningState (which is a child of StartedState)
2299                     // then the next NUD check should be used to store the new values to avoid
2300                     // inputting current values for what may be a different L3 network.
2301                     break;
2302                 }
2303 
2304                 case CMD_UPDATE_L2INFORMATION:
2305                     handleUpdateL2Information((Layer2InformationParcelable) msg.obj);
2306                     break;
2307 
2308                 case EVENT_PROVISIONING_TIMEOUT:
2309                     handleProvisioningFailure(DisconnectCode.DC_PROVISIONING_TIMEOUT);
2310                     break;
2311 
2312                 default:
2313                     return NOT_HANDLED;
2314             }
2315 
2316             mMsgStateLogger.handled(this, getCurrentState());
2317             return HANDLED;
2318         }
2319     }
2320 
isIpv6Enabled()2321     private boolean isIpv6Enabled() {
2322         return mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_DISABLED;
2323     }
2324 
isIpv4Enabled()2325     private boolean isIpv4Enabled() {
2326         return mConfiguration.mIPv4ProvisioningMode != PROV_IPV4_DISABLED;
2327     }
2328 
2329     class RunningState extends State {
2330         private ConnectivityPacketTracker mPacketTracker;
2331         private boolean mDhcpActionInFlight;
2332 
2333         @Override
enter()2334         public void enter() {
2335             ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
2336             apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
2337             apfConfig.multicastFilter = mMulticastFiltering;
2338             // Get the Configuration for ApfFilter from Context
2339             // Resource settings were moved from ApfCapabilities APIs to NetworkStack resources in S
2340             if (ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.R)) {
2341                 final Resources res = mContext.getResources();
2342                 apfConfig.ieee802_3Filter = res.getBoolean(R.bool.config_apfDrop802_3Frames);
2343                 apfConfig.ethTypeBlackList = res.getIntArray(R.array.config_apfEthTypeDenyList);
2344             } else {
2345                 apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
2346                 apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
2347             }
2348 
2349             apfConfig.minRdnssLifetimeSec = mMinRdnssLifetimeSec;
2350             mApfFilter = mDependencies.maybeCreateApfFilter(mContext, apfConfig, mInterfaceParams,
2351                     mCallback);
2352             // TODO: investigate the effects of any multicast filtering racing/interfering with the
2353             // rest of this IP configuration startup.
2354             if (mApfFilter == null) {
2355                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
2356             }
2357 
2358             mPacketTracker = createPacketTracker();
2359             if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
2360 
2361             final int acceptRa =
2362                     mConfiguration.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL ? 0 : 2;
2363             if (isIpv6Enabled() && !startIPv6(acceptRa)) {
2364                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
2365                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6);
2366                 return;
2367             }
2368 
2369             if (isIpv4Enabled() && !isUsingPreconnection() && !startIPv4()) {
2370                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
2371                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV4);
2372                 return;
2373             }
2374 
2375             final InitialConfiguration config = mConfiguration.mInitialConfig;
2376             if ((config != null) && !applyInitialConfig(config)) {
2377                 // TODO introduce a new IpManagerEvent constant to distinguish this error case.
2378                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
2379                 enqueueJumpToStoppingState(DisconnectCode.DC_INVALID_PROVISIONING);
2380                 return;
2381             }
2382 
2383             if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
2384                 doImmediateProvisioningFailure(
2385                         IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
2386                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPREACHABILITYMONITOR);
2387                 return;
2388             }
2389         }
2390 
2391         @Override
exit()2392         public void exit() {
2393             stopDhcpAction();
2394 
2395             if (mIpReachabilityMonitor != null) {
2396                 mIpReachabilityMonitor.stop();
2397                 mIpReachabilityMonitor = null;
2398             }
2399 
2400             if (mPacketTracker != null) {
2401                 mPacketTracker.stop();
2402                 mPacketTracker = null;
2403             }
2404 
2405             if (mApfFilter != null) {
2406                 mApfFilter.shutdown();
2407                 mApfFilter = null;
2408             }
2409 
2410             resetLinkProperties();
2411         }
2412 
enqueueJumpToStoppingState(final DisconnectCode code)2413         private void enqueueJumpToStoppingState(final DisconnectCode code) {
2414             deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING, code.getNumber()));
2415         }
2416 
createPacketTracker()2417         private ConnectivityPacketTracker createPacketTracker() {
2418             try {
2419                 return new ConnectivityPacketTracker(
2420                         getHandler(), mInterfaceParams, mConnectivityPacketLog);
2421             } catch (IllegalArgumentException e) {
2422                 return null;
2423             }
2424         }
2425 
ensureDhcpAction()2426         private void ensureDhcpAction() {
2427             if (!mDhcpActionInFlight) {
2428                 mCallback.onPreDhcpAction();
2429                 mDhcpActionInFlight = true;
2430                 final long alarmTime = SystemClock.elapsedRealtime()
2431                         + mConfiguration.mRequestedPreDhcpActionMs;
2432                 mDhcpActionTimeoutAlarm.schedule(alarmTime);
2433             }
2434         }
2435 
stopDhcpAction()2436         private void stopDhcpAction() {
2437             mDhcpActionTimeoutAlarm.cancel();
2438             if (mDhcpActionInFlight) {
2439                 mCallback.onPostDhcpAction();
2440                 mDhcpActionInFlight = false;
2441             }
2442         }
2443 
2444         @Override
processMessage(Message msg)2445         public boolean processMessage(Message msg) {
2446             switch (msg.what) {
2447                 case CMD_JUMP_RUNNING_TO_STOPPING:
2448                 case CMD_STOP:
2449                     transitionToStoppingState(DisconnectCode.forNumber(msg.arg1));
2450                     break;
2451 
2452                 case CMD_START:
2453                     logError("ALERT: START received in StartedState. Please fix caller.");
2454                     break;
2455 
2456                 case CMD_CONFIRM:
2457                     // TODO: Possibly introduce a second type of confirmation
2458                     // that both probes (a) on-link neighbors and (b) does
2459                     // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
2460                     // roams.
2461                     if (mIpReachabilityMonitor != null) {
2462                         mIpReachabilityMonitor.probeAll(false /* dueToRoam */);
2463                     }
2464                     break;
2465 
2466                 case EVENT_PRE_DHCP_ACTION_COMPLETE:
2467                     // It's possible to reach here if, for example, someone
2468                     // calls completedPreDhcpAction() after provisioning with
2469                     // a static IP configuration.
2470                     if (mDhcpClient != null) {
2471                         mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
2472                     }
2473                     break;
2474 
2475                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
2476                     // EVENT_NETLINK_LINKPROPERTIES_CHANGED message will be received in both of
2477                     // provisioning loss and normal user termination cases (e.g. turn off wifi or
2478                     // switch to another wifi ssid), hence, checking the current interface link
2479                     // state (down or up) helps distinguish the two cases: if the link state is
2480                     // down, provisioning is only lost because the link is being torn down (for
2481                     // example when turning off wifi), so treat it as a normal termination.
2482                     if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
2483                         final boolean linkStateUp = (msg.arg1 == ARG_LINKPROP_CHANGED_LINKSTATE_UP);
2484                         transitionToStoppingState(linkStateUp ? DisconnectCode.DC_PROVISIONING_FAIL
2485                                 : DisconnectCode.DC_NORMAL_TERMINATION);
2486                     }
2487                     break;
2488 
2489                 case CMD_UPDATE_TCP_BUFFER_SIZES:
2490                     mTcpBufferSizes = (String) msg.obj;
2491                     // This cannot possibly change provisioning state.
2492                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
2493                     break;
2494 
2495                 case CMD_UPDATE_HTTP_PROXY:
2496                     mHttpProxy = (ProxyInfo) msg.obj;
2497                     // This cannot possibly change provisioning state.
2498                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
2499                     break;
2500 
2501                 case CMD_SET_MULTICAST_FILTER: {
2502                     mMulticastFiltering = (boolean) msg.obj;
2503                     if (mApfFilter != null) {
2504                         mApfFilter.setMulticastFilter(mMulticastFiltering);
2505                     } else {
2506                         mCallback.setFallbackMulticastFilter(mMulticastFiltering);
2507                     }
2508                     break;
2509                 }
2510 
2511                 case EVENT_READ_PACKET_FILTER_COMPLETE: {
2512                     if (mApfFilter != null) {
2513                         mApfFilter.setDataSnapshot((byte[]) msg.obj);
2514                     }
2515                     mApfDataSnapshotComplete.open();
2516                     break;
2517                 }
2518 
2519                 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
2520                     final int slot = msg.arg1;
2521 
2522                     if (mApfFilter != null) {
2523                         if (msg.obj instanceof NattKeepalivePacketDataParcelable) {
2524                             mApfFilter.addNattKeepalivePacketFilter(slot,
2525                                     (NattKeepalivePacketDataParcelable) msg.obj);
2526                         } else if (msg.obj instanceof TcpKeepalivePacketDataParcelable) {
2527                             mApfFilter.addTcpKeepalivePacketFilter(slot,
2528                                     (TcpKeepalivePacketDataParcelable) msg.obj);
2529                         }
2530                     }
2531                     break;
2532                 }
2533 
2534                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
2535                     final int slot = msg.arg1;
2536                     if (mApfFilter != null) {
2537                         mApfFilter.removeKeepalivePacketFilter(slot);
2538                     }
2539                     break;
2540                 }
2541 
2542                 case EVENT_DHCPACTION_TIMEOUT:
2543                     stopDhcpAction();
2544                     break;
2545 
2546                 case DhcpClient.CMD_PRE_DHCP_ACTION:
2547                     if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
2548                         ensureDhcpAction();
2549                     } else {
2550                         sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
2551                     }
2552                     break;
2553 
2554                 case DhcpClient.CMD_CLEAR_LINKADDRESS:
2555                     mInterfaceCtrl.clearIPv4Address();
2556                     break;
2557 
2558                 case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
2559                     final LinkAddress ipAddress = (LinkAddress) msg.obj;
2560                     if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
2561                         mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
2562                     } else {
2563                         logError("Failed to set IPv4 address.");
2564                         dispatchCallback(PROV_CHANGE_LOST_PROVISIONING, mLinkProperties);
2565                         transitionToStoppingState(DisconnectCode.DC_PROVISIONING_FAIL);
2566                     }
2567                     break;
2568                 }
2569 
2570                 // This message is only received when:
2571                 //
2572                 //     a) initial address acquisition succeeds,
2573                 //     b) renew succeeds or is NAK'd,
2574                 //     c) rebind succeeds or is NAK'd, or
2575                 //     d) the lease expires, or
2576                 //     e) the IPv6-only preferred option is enabled and entering Ipv6OnlyWaitState.
2577                 //
2578                 // but never when initial address acquisition fails. The latter
2579                 // condition is now governed by the provisioning timeout.
2580                 case DhcpClient.CMD_POST_DHCP_ACTION:
2581                     stopDhcpAction();
2582 
2583                     switch (msg.arg1) {
2584                         case DhcpClient.DHCP_SUCCESS:
2585                             handleIPv4Success((DhcpResults) msg.obj);
2586                             break;
2587                         case DhcpClient.DHCP_FAILURE:
2588                             handleIPv4Failure();
2589                             break;
2590                         case DhcpClient.DHCP_IPV6_ONLY:
2591                             break;
2592                         case DhcpClient.DHCP_REFRESH_FAILURE:
2593                             // This case should only happen on the receipt of DHCPNAK when
2594                             // refreshing IP address post L2 roaming on some specific networks.
2595                             // WiFi should try to restart a new provisioning immediately without
2596                             // disconnecting L2 when it receives DHCP roaming failure event. IPv4
2597                             // link address still will be cleared when DhcpClient transits to
2598                             // StoppedState from RefreshingAddress State, although it will result
2599                             // in a following onProvisioningFailure then, WiFi should ignore this
2600                             // failure and start a new DHCP reconfiguration from INIT state.
2601                             final ReachabilityLossInfoParcelable lossInfo =
2602                                     new ReachabilityLossInfoParcelable("DHCP refresh failure",
2603                                             ReachabilityLossReason.ROAM);
2604                             mCallback.onReachabilityFailure(lossInfo);
2605                             break;
2606                         default:
2607                             logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
2608                     }
2609                     break;
2610 
2611                 case DhcpClient.CMD_ON_QUIT:
2612                     // DHCPv4 quit early for some reason.
2613                     logError("Unexpected CMD_ON_QUIT.");
2614                     mDhcpClient = null;
2615                     break;
2616 
2617                 default:
2618                     return NOT_HANDLED;
2619             }
2620 
2621             mMsgStateLogger.handled(this, getCurrentState());
2622             return HANDLED;
2623         }
2624     }
2625 
2626     private static class MessageHandlingLogger {
2627         public String processedInState;
2628         public String receivedInState;
2629 
reset()2630         public void reset() {
2631             processedInState = null;
2632             receivedInState = null;
2633         }
2634 
handled(State processedIn, IState receivedIn)2635         public void handled(State processedIn, IState receivedIn) {
2636             processedInState = processedIn.getClass().getSimpleName();
2637             receivedInState = receivedIn.getName();
2638         }
2639 
toString()2640         public String toString() {
2641             return String.format("rcvd_in=%s, proc_in=%s",
2642                                  receivedInState, processedInState);
2643         }
2644     }
2645 
2646     // TODO: extract out into CollectionUtils.
any(Iterable<T> coll, Predicate<T> fn)2647     static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
2648         for (T t : coll) {
2649             if (fn.test(t)) {
2650                 return true;
2651             }
2652         }
2653         return false;
2654     }
2655 
all(Iterable<T> coll, Predicate<T> fn)2656     static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
2657         return !any(coll, not(fn));
2658     }
2659 
not(Predicate<T> fn)2660     static <T> Predicate<T> not(Predicate<T> fn) {
2661         return (t) -> !fn.test(t);
2662     }
2663 
join(String delimiter, Collection<T> coll)2664     static <T> String join(String delimiter, Collection<T> coll) {
2665         return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
2666     }
2667 
find(Iterable<T> coll, Predicate<T> fn)2668     static <T> T find(Iterable<T> coll, Predicate<T> fn) {
2669         for (T t: coll) {
2670             if (fn.test(t)) {
2671                 return t;
2672             }
2673         }
2674         return null;
2675     }
2676 
findAll(Collection<T> coll, Predicate<T> fn)2677     static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
2678         return coll.stream().filter(fn).collect(Collectors.toList());
2679     }
2680 }
2681