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