• 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.content.pm.PackageManager.FEATURE_LEANBACK;
20 import static android.net.IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM;
21 import static android.net.IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_CONFIRM;
22 import static android.net.IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC;
23 import static android.net.IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_MAC_ADDRESS_CHANGED;
24 import static android.net.RouteInfo.RTN_UNICAST;
25 import static android.net.RouteInfo.RTN_UNREACHABLE;
26 import static android.net.dhcp.DhcpResultsParcelableUtil.toStableParcelable;
27 import static android.net.ip.IIpClient.PROV_IPV4_DISABLED;
28 import static android.net.ip.IIpClient.PROV_IPV6_DISABLED;
29 import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL;
30 import static android.net.ip.IIpClient.PROV_IPV6_SLAAC;
31 import static android.net.ip.IIpClientCallbacks.DTIM_MULTIPLIER_RESET;
32 import static android.net.ip.IpClient.IpClientCommands.CMD_ADDRESSES_CLEARED;
33 import static android.net.ip.IpClient.IpClientCommands.CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF;
34 import static android.net.ip.IpClient.IpClientCommands.CMD_COMPLETE_PRECONNECTION;
35 import static android.net.ip.IpClient.IpClientCommands.CMD_CONFIRM;
36 import static android.net.ip.IpClient.IpClientCommands.CMD_JUMP_RUNNING_TO_STOPPING;
37 import static android.net.ip.IpClient.IpClientCommands.CMD_JUMP_STOPPING_TO_STOPPED;
38 import static android.net.ip.IpClient.IpClientCommands.CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF;
39 import static android.net.ip.IpClient.IpClientCommands.CMD_SET_DTIM_MULTIPLIER_AFTER_DELAY;
40 import static android.net.ip.IpClient.IpClientCommands.CMD_SET_MULTICAST_FILTER;
41 import static android.net.ip.IpClient.IpClientCommands.CMD_START;
42 import static android.net.ip.IpClient.IpClientCommands.CMD_STOP;
43 import static android.net.ip.IpClient.IpClientCommands.CMD_TERMINATE_AFTER_STOP;
44 import static android.net.ip.IpClient.IpClientCommands.CMD_UPDATE_APF_CAPABILITIES;
45 import static android.net.ip.IpClient.IpClientCommands.CMD_UPDATE_APF_DATA_SNAPSHOT;
46 import static android.net.ip.IpClient.IpClientCommands.CMD_UPDATE_HTTP_PROXY;
47 import static android.net.ip.IpClient.IpClientCommands.CMD_UPDATE_L2INFORMATION;
48 import static android.net.ip.IpClient.IpClientCommands.CMD_UPDATE_TCP_BUFFER_SIZES;
49 import static android.net.ip.IpClient.IpClientCommands.EVENT_DHCPACTION_TIMEOUT;
50 import static android.net.ip.IpClient.IpClientCommands.EVENT_IPV6_AUTOCONF_TIMEOUT;
51 import static android.net.ip.IpClient.IpClientCommands.EVENT_NETLINK_LINKPROPERTIES_CHANGED;
52 import static android.net.ip.IpClient.IpClientCommands.EVENT_NUD_FAILURE_QUERY_FAILURE;
53 import static android.net.ip.IpClient.IpClientCommands.EVENT_NUD_FAILURE_QUERY_SUCCESS;
54 import static android.net.ip.IpClient.IpClientCommands.EVENT_NUD_FAILURE_QUERY_TIMEOUT;
55 import static android.net.ip.IpClient.IpClientCommands.EVENT_PIO_PREFIX_UPDATE;
56 import static android.net.ip.IpClient.IpClientCommands.EVENT_PRE_DHCP_ACTION_COMPLETE;
57 import static android.net.ip.IpClient.IpClientCommands.EVENT_PROVISIONING_TIMEOUT;
58 import static android.net.ip.IpClient.IpClientCommands.EVENT_READ_PACKET_FILTER_COMPLETE;
59 import static android.net.ip.IpClientLinkObserver.IpClientNetlinkMonitor;
60 import static android.net.ip.IpClientLinkObserver.IpClientNetlinkMonitor.INetlinkMessageProcessor;
61 import static android.net.ip.IpClientLinkObserver.PrefixInfo;
62 import static android.net.ip.IpReachabilityMonitor.INVALID_REACHABILITY_LOSS_TYPE;
63 import static android.net.ip.IpReachabilityMonitor.nudEventTypeToInt;
64 import static android.net.util.SocketUtils.makePacketSocketAddress;
65 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
66 import static android.stats.connectivity.NetworkQuirkEvent.QE_DHCP6_HEURISTIC_TRIGGERED;
67 import static android.stats.connectivity.NetworkQuirkEvent.QE_DHCP6_PD_PROVISIONED;
68 import static android.system.OsConstants.AF_PACKET;
69 import static android.system.OsConstants.ARPHRD_ETHER;
70 import static android.system.OsConstants.ETH_P_ARP;
71 import static android.system.OsConstants.ETH_P_IPV6;
72 import static android.system.OsConstants.IFA_F_NODAD;
73 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
74 import static android.system.OsConstants.SOCK_NONBLOCK;
75 import static android.system.OsConstants.SOCK_RAW;
76 
77 import static com.android.net.module.util.LinkPropertiesUtils.CompareResult;
78 import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
79 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
80 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST;
81 import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
82 import static com.android.net.module.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID;
83 import static com.android.networkstack.apishim.ConstantsShim.IFA_F_MANAGETEMPADDR;
84 import static com.android.networkstack.apishim.ConstantsShim.IFA_F_NOPREFIXROUTE;
85 import static com.android.networkstack.util.NetworkStackUtils.APF_ENABLE;
86 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_ARP_OFFLOAD;
87 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_IGMP_OFFLOAD;
88 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_IGMP_OFFLOAD_VERSION;
89 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_MLD_OFFLOAD;
90 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_MLD_OFFLOAD_VERSION;
91 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_ND_OFFLOAD;
92 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_PING4_OFFLOAD;
93 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_PING4_OFFLOAD_VERSION;
94 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_PING6_OFFLOAD;
95 import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_PING6_OFFLOAD_VERSION;
96 import static com.android.networkstack.util.NetworkStackUtils.APF_POLLING_COUNTERS_VERSION;
97 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_DHCPV6_PD_PREFERRED_FLAG_VERSION;
98 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_IGNORE_LOW_RA_LIFETIME_VERSION;
99 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION;
100 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_REPLACE_NETD_WITH_NETLINK_VERSION;
101 import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION;
102 import static com.android.networkstack.util.NetworkStackUtils.createInet6AddressFromEui64;
103 import static com.android.networkstack.util.NetworkStackUtils.isAtLeast25Q2;
104 import static com.android.networkstack.util.NetworkStackUtils.macAddressToEui64;
105 import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingPermission;
106 
107 import android.annotation.SuppressLint;
108 import android.app.admin.DevicePolicyManager;
109 import android.content.ComponentName;
110 import android.content.Context;
111 import android.content.pm.PackageManager;
112 import android.content.res.Resources;
113 import android.net.ConnectivityManager;
114 import android.net.DhcpResults;
115 import android.net.INetd;
116 import android.net.IpPrefix;
117 import android.net.Layer2InformationParcelable;
118 import android.net.Layer2PacketParcelable;
119 import android.net.LinkAddress;
120 import android.net.LinkProperties;
121 import android.net.MacAddress;
122 import android.net.NattKeepalivePacketDataParcelable;
123 import android.net.NetworkStackIpMemoryStore;
124 import android.net.ProvisioningConfigurationParcelable;
125 import android.net.ProxyInfo;
126 import android.net.RouteInfo;
127 import android.net.TcpKeepalivePacketDataParcelable;
128 import android.net.Uri;
129 import android.net.apf.ApfCapabilities;
130 import android.net.apf.ApfFilter;
131 import android.net.dhcp.DhcpClient;
132 import android.net.dhcp.DhcpPacket;
133 import android.net.dhcp6.Dhcp6Client;
134 import android.net.ipmemorystore.OnNetworkEventCountRetrievedListener;
135 import android.net.ipmemorystore.Status;
136 import android.net.metrics.IpConnectivityLog;
137 import android.net.metrics.IpManagerEvent;
138 import android.net.networkstack.aidl.dhcp.DhcpOption;
139 import android.net.networkstack.aidl.ip.ReachabilityLossInfoParcelable;
140 import android.net.networkstack.aidl.ip.ReachabilityLossReason;
141 import android.net.shared.InitialConfiguration;
142 import android.net.shared.Layer2Information;
143 import android.net.shared.ProvisioningConfiguration;
144 import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
145 import android.net.shared.ProvisioningConfiguration.ScanResultInfo.InformationElement;
146 import android.os.ConditionVariable;
147 import android.os.Handler;
148 import android.os.IBinder;
149 import android.os.Message;
150 import android.os.RemoteException;
151 import android.os.ServiceSpecificException;
152 import android.os.SystemClock;
153 import android.os.UserHandle;
154 import android.stats.connectivity.DisconnectCode;
155 import android.stats.connectivity.NetworkQuirkEvent;
156 import android.stats.connectivity.NudEventType;
157 import android.system.ErrnoException;
158 import android.system.Os;
159 import android.text.TextUtils;
160 import android.text.format.DateUtils;
161 import android.util.LocalLog;
162 import android.util.Log;
163 import android.util.SparseArray;
164 
165 import androidx.annotation.NonNull;
166 import androidx.annotation.Nullable;
167 
168 import com.android.internal.annotations.VisibleForTesting;
169 import com.android.internal.util.HexDump;
170 import com.android.internal.util.IState;
171 import com.android.internal.util.IndentingPrintWriter;
172 import com.android.internal.util.MessageUtils;
173 import com.android.internal.util.State;
174 import com.android.internal.util.StateMachine;
175 import com.android.internal.util.WakeupMessage;
176 import com.android.modules.expresslog.Counter;
177 import com.android.modules.utils.build.SdkLevel;
178 import com.android.net.module.util.CollectionUtils;
179 import com.android.net.module.util.ConnectivityUtils;
180 import com.android.net.module.util.DeviceConfigUtils;
181 import com.android.net.module.util.HandlerUtils;
182 import com.android.net.module.util.InterfaceParams;
183 import com.android.net.module.util.LinkPropertiesUtils;
184 import com.android.net.module.util.SharedLog;
185 import com.android.net.module.util.SocketUtils;
186 import com.android.net.module.util.arp.ArpPacket;
187 import com.android.net.module.util.ip.InterfaceController;
188 import com.android.net.module.util.netlink.NetlinkUtils;
189 import com.android.net.module.util.structs.IaPrefixOption;
190 import com.android.networkstack.R;
191 import com.android.networkstack.apishim.NetworkInformationShimImpl;
192 import com.android.networkstack.apishim.SocketUtilsShimImpl;
193 import com.android.networkstack.apishim.common.NetworkInformationShim;
194 import com.android.networkstack.apishim.common.ShimUtils;
195 import com.android.networkstack.metrics.IpProvisioningMetrics;
196 import com.android.networkstack.metrics.NetworkQuirkMetrics;
197 import com.android.networkstack.metrics.NetworkStackStatsLog;
198 import com.android.networkstack.packets.NeighborAdvertisement;
199 import com.android.networkstack.packets.NeighborSolicitation;
200 import com.android.networkstack.util.NetworkStackUtils;
201 import com.android.server.NetworkStackService.NetworkStackServiceManager;
202 
203 import java.io.File;
204 import java.io.FileDescriptor;
205 import java.io.PrintWriter;
206 import java.net.Inet4Address;
207 import java.net.Inet6Address;
208 import java.net.InetAddress;
209 import java.net.MalformedURLException;
210 import java.net.SocketAddress;
211 import java.net.SocketException;
212 import java.net.URL;
213 import java.nio.BufferUnderflowException;
214 import java.nio.ByteBuffer;
215 import java.util.ArrayList;
216 import java.util.Arrays;
217 import java.util.Collection;
218 import java.util.Collections;
219 import java.util.HashSet;
220 import java.util.List;
221 import java.util.Map;
222 import java.util.Objects;
223 import java.util.Random;
224 import java.util.Set;
225 import java.util.StringJoiner;
226 import java.util.concurrent.CompletableFuture;
227 import java.util.concurrent.ConcurrentHashMap;
228 import java.util.concurrent.ExecutionException;
229 import java.util.concurrent.TimeUnit;
230 import java.util.concurrent.TimeoutException;
231 import java.util.function.Predicate;
232 import java.util.stream.Collectors;
233 
234 /**
235  * IpClient
236  *
237  * This class provides the interface to IP-layer provisioning and maintenance
238  * functionality that can be used by transport layers like Wi-Fi, Ethernet,
239  * et cetera.
240  *
241  * [ Lifetime ]
242  * IpClient is designed to be instantiated as soon as the interface name is
243  * known and can be as long-lived as the class containing it (i.e. declaring
244  * it "private final" is okay).
245  *
246  * @hide
247  */
248 public class IpClient extends StateMachine {
249     private static final String TAG = IpClient.class.getSimpleName();
250     private static final boolean DBG = false;
251     private final boolean mApfDebug;
252 
253     // For message logging.
254     private static final Class[] sMessageClasses = { IpClientCommands.class, DhcpClient.class };
255     private static final SparseArray<String> sWhatToString =
256             MessageUtils.findMessageNames(sMessageClasses);
257     // Static concurrent hashmaps of interface name to logging classes.
258     // This map holds StateMachine logs.
259     private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
260     // This map holds connectivity packet logs.
261     private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
262     // This map holds Apf logs.
263     private static final ConcurrentHashMap<String, SharedLog> sApfLogs = new ConcurrentHashMap<>();
264     private final NetworkStackIpMemoryStore mIpMemoryStore;
265     private final NetworkInformationShim mShim = NetworkInformationShimImpl.newInstance();
266     private final IpProvisioningMetrics mIpProvisioningMetrics = new IpProvisioningMetrics();
267     private final NetworkQuirkMetrics mNetworkQuirkMetrics;
268 
269     private boolean mHasSeenClatInterface = false;
270 
271     /**
272      * Dump all state machine and connectivity packet logs to the specified writer.
273      * @param skippedIfaces Interfaces for which logs should not be dumped.
274      */
dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces)275     public static void dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces) {
276         for (String ifname : sSmLogs.keySet()) {
277             if (skippedIfaces.contains(ifname)) continue;
278 
279             writer.println(String.format("--- BEGIN %s ---", ifname));
280 
281             final SharedLog apfLog = sApfLogs.get(ifname);
282             if (apfLog != null) {
283                 writer.println("APF log:");
284                 apfLog.dump(null, writer, null);
285             }
286 
287             final SharedLog smLog = sSmLogs.get(ifname);
288             if (smLog != null) {
289                 writer.println("State machine log:");
290                 smLog.dump(null, writer, null);
291             }
292 
293             writer.println("");
294 
295             final LocalLog pktLog = sPktLogs.get(ifname);
296             if (pktLog != null) {
297                 writer.println("Connectivity packet log:");
298                 pktLog.readOnlyLocalLog().dump(null, writer, null);
299             }
300 
301             writer.println(String.format("--- END %s ---", ifname));
302         }
303     }
304 
305     // Use a wrapper class to log in order to ensure complete and detailed
306     // logging. This method is lighter weight than annotations/reflection
307     // and has the following benefits:
308     //
309     //     - No invoked method can be forgotten.
310     //       Any new method added to IpClient.Callback must be overridden
311     //       here or it will never be called.
312     //
313     //     - No invoking call site can be forgotten.
314     //       Centralized logging in this way means call sites don't need to
315     //       remember to log, and therefore no call site can be forgotten.
316     //
317     //     - No variation in log format among call sites.
318     //       Encourages logging of any available arguments, and all call sites
319     //       are necessarily logged identically.
320     //
321     // NOTE: Log first because passed objects may or may not be thread-safe and
322     // once passed on to the callback they may be modified by another thread.
323     //
324     // TODO: Find an lighter weight approach.
325     public static class IpClientCallbacksWrapper {
326         private static final String PREFIX = "INVOKE ";
327         private final IIpClientCallbacks mCallback;
328         @NonNull
329         private final SharedLog mLog;
330         @NonNull
331         private final SharedLog mApfLog;
332         @NonNull
333         private final NetworkInformationShim mShim;
334 
335         private final boolean mApfDebug;
336         private final Random mRandom = new Random();
337 
338         @VisibleForTesting
IpClientCallbacksWrapper(IIpClientCallbacks callback, @NonNull SharedLog log, @NonNull SharedLog apfLog, @NonNull NetworkInformationShim shim, boolean apfDebug)339         protected IpClientCallbacksWrapper(IIpClientCallbacks callback, @NonNull SharedLog log,
340                 @NonNull SharedLog apfLog, @NonNull NetworkInformationShim shim,
341                 boolean apfDebug) {
342             mCallback = callback;
343             mLog = log;
344             mApfLog = apfLog;
345             mShim = shim;
346             mApfDebug = apfDebug;
347         }
348 
log(String msg)349         private void log(String msg) {
350             mLog.log(PREFIX + msg);
351         }
352 
log(String msg, Throwable e)353         private void log(String msg, Throwable e) {
354             mLog.e(PREFIX + msg, e);
355         }
356 
357         /**
358          * Callback called prior to DHCP discovery/renewal only if the pre DHCP action
359          * is enabled.
360          */
onPreDhcpAction()361         public void onPreDhcpAction() {
362             log("onPreDhcpAction()");
363             try {
364                 mCallback.onPreDhcpAction();
365             } catch (RemoteException e) {
366                 log("Failed to call onPreDhcpAction", e);
367             }
368         }
369 
370         /**
371          * Callback called after DHCP discovery/renewal only if the pre DHCP action
372          * is enabled.
373          */
onPostDhcpAction()374         public void onPostDhcpAction() {
375             log("onPostDhcpAction()");
376             try {
377                 mCallback.onPostDhcpAction();
378             } catch (RemoteException e) {
379                 log("Failed to call onPostDhcpAction", e);
380             }
381         }
382 
383         /**
384          * Callback called when new DHCP results are available.
385          */
onNewDhcpResults(DhcpResults dhcpResults)386         public void onNewDhcpResults(DhcpResults dhcpResults) {
387             log("onNewDhcpResults({" + dhcpResults + "})");
388             try {
389                 mCallback.onNewDhcpResults(toStableParcelable(dhcpResults));
390             } catch (RemoteException e) {
391                 log("Failed to call onNewDhcpResults", e);
392             }
393         }
394 
395         /**
396          * Indicates that provisioning was successful.
397          */
onProvisioningSuccess(LinkProperties newLp)398         public void onProvisioningSuccess(LinkProperties newLp) {
399             log("onProvisioningSuccess({" + newLp + "})");
400             // We log this error, which has a 1 in 1,000,000 probability, as a heartbeat for
401             // terrible error reporting.
402             if (mRandom.nextInt(1000000) == 0) {
403                 NetworkStackStatsLog.write(
404                         NetworkStackStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED,
405                         NetworkStackStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_UNKNOWN);
406             }
407             try {
408                 mCallback.onProvisioningSuccess(mShim.makeSensitiveFieldsParcelingCopy(newLp));
409             } catch (RemoteException e) {
410                 log("Failed to call onProvisioningSuccess", e);
411             }
412         }
413 
414         /**
415          * Indicates that provisioning failed.
416          */
onProvisioningFailure(LinkProperties newLp)417         public void onProvisioningFailure(LinkProperties newLp) {
418             log("onProvisioningFailure({" + newLp + "})");
419             try {
420                 mCallback.onProvisioningFailure(mShim.makeSensitiveFieldsParcelingCopy(newLp));
421             } catch (RemoteException e) {
422                 log("Failed to call onProvisioningFailure", e);
423             }
424         }
425 
426         /**
427          * Invoked on LinkProperties changes.
428          */
onLinkPropertiesChange(LinkProperties newLp)429         public void onLinkPropertiesChange(LinkProperties newLp) {
430             log("onLinkPropertiesChange({" + newLp + "})");
431             try {
432                 mCallback.onLinkPropertiesChange(mShim.makeSensitiveFieldsParcelingCopy(newLp));
433             } catch (RemoteException e) {
434                 log("Failed to call onLinkPropertiesChange", e);
435             }
436         }
437 
438         /**
439          * Called when the internal IpReachabilityMonitor (if enabled) has detected the loss of
440          * required neighbors (e.g. on-link default gw or dns servers) due to NUD_FAILED.
441          *
442          * Note this method is only supported on networkstack-aidl-interfaces-v12 or below.
443          * For above aidl versions, the caller should call {@link onReachabilityFailure} instead.
444          * For callbacks extending IpClientCallbacks, this method will be called iff the callback
445          * does not implement onReachabilityFailure.
446          */
onReachabilityLost(String logMsg)447         public void onReachabilityLost(String logMsg) {
448             log("onReachabilityLost(" + logMsg + ")");
449             try {
450                 mCallback.onReachabilityLost(logMsg);
451             } catch (RemoteException e) {
452                 log("Failed to call onReachabilityLost", e);
453             }
454         }
455 
456         /**
457          * Called when the IpClient state machine terminates.
458          */
onQuit()459         public void onQuit() {
460             log("onQuit()");
461             try {
462                 mCallback.onQuit();
463             } catch (RemoteException e) {
464                 log("Failed to call onQuit", e);
465             }
466         }
467 
468         /**
469          * Called to indicate that a new APF program must be installed to filter incoming packets.
470          */
installPacketFilter(byte[] filter, @NonNull String filterConfig)471         public boolean installPacketFilter(byte[] filter, @NonNull String filterConfig) {
472             log("installPacketFilter(byte[" + filter.length + "])" + " config: "
473                     + filterConfig);
474             try {
475                 if (mApfDebug) {
476                     mApfLog.log("updated APF program: " + HexDump.toHexString(filter));
477                 }
478                 mCallback.installPacketFilter(filter);
479             } catch (RemoteException e) {
480                 log("Failed to call installPacketFilter", e);
481                 return false;
482             }
483             return true;
484         }
485 
486         /**
487          * Called to indicate that the APF Program & data buffer must be read asynchronously from
488          * the wifi driver.
489          */
startReadPacketFilter(@onNull String event)490         public void startReadPacketFilter(@NonNull String event) {
491             log("startReadPacketFilter(), event: " + event);
492             try {
493                 mCallback.startReadPacketFilter();
494             } catch (RemoteException e) {
495                 log("Failed to call startReadPacketFilter", e);
496             }
497         }
498 
499         /**
500          * If multicast filtering cannot be accomplished with APF, this function will be called to
501          * actuate multicast filtering using another means.
502          */
setFallbackMulticastFilter(boolean enabled)503         public void setFallbackMulticastFilter(boolean enabled) {
504             log("setFallbackMulticastFilter(" + enabled + ")");
505             try {
506                 mCallback.setFallbackMulticastFilter(enabled);
507             } catch (RemoteException e) {
508                 log("Failed to call setFallbackMulticastFilter", e);
509             }
510         }
511 
512         /**
513          * Enabled/disable Neighbor Discover offload functionality. This is called, for example,
514          * whenever 464xlat is being started or stopped.
515          */
setNeighborDiscoveryOffload(boolean enable)516         public void setNeighborDiscoveryOffload(boolean enable) {
517             log("setNeighborDiscoveryOffload(" + enable + ")");
518             try {
519                 mCallback.setNeighborDiscoveryOffload(enable);
520             } catch (RemoteException e) {
521                 log("Failed to call setNeighborDiscoveryOffload", e);
522             }
523         }
524 
525         /**
526          * Invoked on starting preconnection process.
527          */
onPreconnectionStart(List<Layer2PacketParcelable> packets)528         public void onPreconnectionStart(List<Layer2PacketParcelable> packets) {
529             log("onPreconnectionStart(Layer2Packets[" + packets.size() + "])");
530             try {
531                 mCallback.onPreconnectionStart(packets);
532             } catch (RemoteException e) {
533                 log("Failed to call onPreconnectionStart", e);
534             }
535         }
536 
537         /**
538          * Called when Neighbor Unreachability Detection fails, that might be caused by the organic
539          * probe or probeAll from IpReachabilityMonitor (if enabled).
540          */
onReachabilityFailure(ReachabilityLossInfoParcelable lossInfo)541         public void onReachabilityFailure(ReachabilityLossInfoParcelable lossInfo) {
542             log("onReachabilityFailure(" + lossInfo.message + ", loss reason: "
543                     + reachabilityLossReasonToString(lossInfo.reason) + ")");
544             try {
545                 mCallback.onReachabilityFailure(lossInfo);
546             } catch (RemoteException e) {
547                 log("Failed to call onReachabilityFailure", e);
548             }
549         }
550 
551         /**
552          * Set maximum acceptable DTIM multiplier to hardware driver.
553          */
setMaxDtimMultiplier(int multiplier)554         public void setMaxDtimMultiplier(int multiplier) {
555             try {
556                 // {@link IWifiStaIface#setDtimMultiplier} has been implemented since U, calling
557                 // this method on U- platforms does nothing actually.
558                 if (!SdkLevel.isAtLeastU()) {
559                     log("SDK level is lower than U, do not call setMaxDtimMultiplier method");
560                     return;
561                 }
562                 log("setMaxDtimMultiplier(" + multiplier + ")");
563                 mCallback.setMaxDtimMultiplier(multiplier);
564             } catch (RemoteException e) {
565                 log("Failed to call setMaxDtimMultiplier", e);
566             }
567         }
568 
569         /**
570          * Get the version of the IIpClientCallbacks AIDL interface.
571          */
getInterfaceVersion()572         public int getInterfaceVersion() {
573             log("getInterfaceVersion");
574             try {
575                 return mCallback.getInterfaceVersion();
576             } catch (RemoteException e) {
577                 // This can never happen for callers in the system server, because if the
578                 // system server crashes, then the networkstack will crash as well. But it can
579                 // happen for other callers such as bluetooth or telephony (if it starts to use
580                 // IpClient). 0 will generally work but will assume an old client and disable
581                 // all new features.
582                 log("Failed to call getInterfaceVersion", e);
583                 return 0;
584             }
585         }
586     }
587 
588     public static final String DUMP_ARG_CONFIRM = "confirm";
589 
590     // Sysctl parameter strings.
591     private static final String ACCEPT_RA = "accept_ra";
592     private static final String ACCEPT_RA_DEFRTR = "accept_ra_defrtr";
593     @VisibleForTesting
594     static final String ACCEPT_RA_MIN_LFT = "accept_ra_min_lft";
595     private static final String DAD_TRANSMITS = "dad_transmits";
596 
597     /**
598      * The IpClientCommands constant values.
599      *
600      * @hide
601      */
602     public static class IpClientCommands {
IpClientCommands()603         private IpClientCommands() {
604         }
605 
606         // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
607         static final int CMD_TERMINATE_AFTER_STOP = 1;
608         static final int CMD_STOP = 2;
609         static final int CMD_START = 3;
610         static final int CMD_CONFIRM = 4;
611         static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 5;
612         // Triggered by IpClientLinkObserver to communicate netlink events.
613         static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
614         static final int CMD_UPDATE_TCP_BUFFER_SIZES = 7;
615         static final int CMD_UPDATE_HTTP_PROXY = 8;
616         static final int CMD_SET_MULTICAST_FILTER = 9;
617         static final int EVENT_PROVISIONING_TIMEOUT = 10;
618         static final int EVENT_DHCPACTION_TIMEOUT = 11;
619         static final int EVENT_READ_PACKET_FILTER_COMPLETE = 12;
620         static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
621         static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
622         static final int CMD_COMPLETE_PRECONNECTION = 15;
623         static final int CMD_UPDATE_L2INFORMATION = 16;
624         static final int CMD_SET_DTIM_MULTIPLIER_AFTER_DELAY = 17;
625         static final int CMD_UPDATE_APF_CAPABILITIES = 18;
626         static final int EVENT_IPV6_AUTOCONF_TIMEOUT = 19;
627         static final int CMD_UPDATE_APF_DATA_SNAPSHOT = 20;
628         static final int EVENT_NUD_FAILURE_QUERY_TIMEOUT = 21;
629         static final int EVENT_NUD_FAILURE_QUERY_SUCCESS = 22;
630         static final int EVENT_NUD_FAILURE_QUERY_FAILURE = 23;
631         static final int EVENT_PIO_PREFIX_UPDATE = 24;
632         // Internal commands to use instead of trying to call transitionTo() inside
633         // a given State's enter() method. Calling transitionTo() from enter/exit
634         // encounters a Log.wtf() that can cause trouble on eng builds.
635         static final int CMD_ADDRESSES_CLEARED = 100;
636         static final int CMD_JUMP_RUNNING_TO_STOPPING = 101;
637         static final int CMD_JUMP_STOPPING_TO_STOPPED = 102;
638     }
639 
640     private static final int ARG_LINKPROP_CHANGED_LINKSTATE_DOWN = 0;
641     private static final int ARG_LINKPROP_CHANGED_LINKSTATE_UP = 1;
642 
643     // IpClient shares a handler with DhcpClient: commands must not overlap
644     public static final int DHCPCLIENT_CMD_BASE = 1000;
645 
646     // IpClient shares a handler with Dhcp6Client: commands must not overlap
647     public static final int DHCP6CLIENT_CMD_BASE = 2000;
648     private static final int DHCPV6_PREFIX_DELEGATION_ADDRESS_FLAGS =
649             IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE | IFA_F_NODAD;
650 
651     // Settings and default values.
652     private static final int MAX_LOG_RECORDS = 500;
653     private static final int MAX_PACKET_RECORDS = 100;
654 
655     @VisibleForTesting
656     static final String CONFIG_ACCEPT_RA_MIN_LFT = "ipclient_accept_ra_min_lft";
657     @VisibleForTesting
658     static final int DEFAULT_ACCEPT_RA_MIN_LFT = 180;
659 
660     @VisibleForTesting
661     static final String CONFIG_APF_COUNTER_POLLING_INTERVAL_SECS =
662             "ipclient_apf_counter_polling_interval_secs";
663     @VisibleForTesting
664     static final int DEFAULT_APF_COUNTER_POLLING_INTERVAL_SECS = 300;
665 
666     // Used to wait for the provisioning to complete eventually and then decide the target
667     // network type, which gives the accurate hint to set DTIM multiplier. Per current IPv6
668     // provisioning connection latency metrics, the latency of 95% can go up to 16s, so pick
669     // ProvisioningConfiguration.DEFAULT_TIMEOUT_MS value for this delay.
670     @VisibleForTesting
671     static final String CONFIG_INITIAL_PROVISIONING_DTIM_DELAY_MS =
672             "ipclient_initial_provisioning_dtim_delay";
673     private static final int DEFAULT_INITIAL_PROVISIONING_DTIM_DELAY_MS = 18000;
674 
675     @VisibleForTesting
676     static final String CONFIG_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER =
677             "ipclient_multicast_lock_max_dtim_multiplier";
678     @VisibleForTesting
679     static final int DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER = 1;
680 
681     @VisibleForTesting
682     static final String CONFIG_IPV6_ONLY_NETWORK_MAX_DTIM_MULTIPLIER =
683             "ipclient_ipv6_only_max_dtim_multiplier";
684     @VisibleForTesting
685     static final int DEFAULT_IPV6_ONLY_NETWORK_MAX_DTIM_MULTIPLIER = 2;
686 
687     @VisibleForTesting
688     static final String CONFIG_IPV4_ONLY_NETWORK_MAX_DTIM_MULTIPLIER =
689             "ipclient_ipv4_only_max_dtim_multiplier";
690     @VisibleForTesting
691     static final int DEFAULT_IPV4_ONLY_NETWORK_MAX_DTIM_MULTIPLIER = 9;
692 
693     @VisibleForTesting
694     static final String CONFIG_DUAL_STACK_MAX_DTIM_MULTIPLIER =
695             "ipclient_dual_stack_max_dtim_multiplier";
696     // The default value for dual-stack networks is the min of maximum DTIM multiplier to use for
697     // IPv4-only and IPv6-only networks.
698     @VisibleForTesting
699     static final int DEFAULT_DUAL_STACK_MAX_DTIM_MULTIPLIER = 2;
700 
701     @VisibleForTesting
702     static final String CONFIG_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER =
703             "ipclient_before_ipv6_prov_max_dtim_multiplier";
704     @VisibleForTesting
705     static final int DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER = 1;
706 
707     // Timeout to wait for IPv6 autoconf via SLAAC to complete before starting DHCPv6
708     // prefix delegation.
709     @VisibleForTesting
710     static final String CONFIG_IPV6_AUTOCONF_TIMEOUT = "ipclient_ipv6_autoconf_timeout";
711     private static final int DEFAULT_IPV6_AUTOCONF_TIMEOUT_MS = 5000;
712 
713     private static final int IPMEMORYSTORE_TIMEOUT_MS = 1000;
714     @VisibleForTesting
715     public static final long SIX_HOURS_IN_MS = 6 * 3600 * 1000L;
716     @VisibleForTesting
717     public static final long ONE_DAY_IN_MS = 4 * SIX_HOURS_IN_MS;
718     @VisibleForTesting
719     public static final long ONE_WEEK_IN_MS = 7 * ONE_DAY_IN_MS;
720     @VisibleForTesting
721     static final String CONFIG_NUD_FAILURE_COUNT_DAILY_THRESHOLD =
722             "nud_failure_count_daily_threshold";
723     @VisibleForTesting
724     static final int DEFAULT_NUD_FAILURE_COUNT_DAILY_THRESHOLD = 10;
725     @VisibleForTesting
726     static final String CONFIG_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD =
727             "nud_failure_count_weekly_threshold";
728     @VisibleForTesting
729     static final int DEFAULT_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD = 20;
730 
731     private static final boolean NO_CALLBACKS = false;
732     private static final boolean SEND_CALLBACKS = true;
733 
734     private static final int IMMEDIATE_FAILURE_DURATION = 0;
735 
736     private static final int PROV_CHANGE_STILL_NOT_PROVISIONED = 1;
737     private static final int PROV_CHANGE_LOST_PROVISIONING = 2;
738     private static final int PROV_CHANGE_GAINED_PROVISIONING = 3;
739     private static final int PROV_CHANGE_STILL_PROVISIONED = 4;
740 
741     // onReachabilityFailure callback is added since networkstack-aidl-interfaces-v13.
742     @VisibleForTesting
743     static final int VERSION_ADDED_REACHABILITY_FAILURE = 13;
744 
745     // Specific vendor OUI(3 bytes)/vendor specific type(1 byte) pattern for upstream hotspot
746     // device detection. Add new byte array pattern below in turn.
747     private static final List<byte[]> METERED_IE_PATTERN_LIST = Collections.singletonList(
748             new byte[] { (byte) 0x00, (byte) 0x17, (byte) 0xf2, (byte) 0x06 }
749     );
750 
751     // Allows Wi-Fi to pass in DHCP options when particular vendor-specific IEs are present.
752     // Maps each DHCP option code to a list of IEs, any of which will allow that option.
753     private static final Map<Byte, List<byte[]>> DHCP_OPTIONS_ALLOWED = Map.of(
754             (byte) 60, Collections.singletonList(
755                     // KT OUI: 00:17:C3, type: 33(0x21). See b/236745261.
756                     new byte[]{ (byte) 0x00, (byte) 0x17, (byte) 0xc3, (byte) 0x21 }),
757             (byte) 77, Collections.singletonList(
758                     // KT OUI: 00:17:C3, type: 33(0x21). See b/236745261.
759                     new byte[]{ (byte) 0x00, (byte) 0x17, (byte) 0xc3, (byte) 0x21 })
760     );
761 
762     // Initialize configurable particular SSID set supporting DHCP Roaming feature. See
763     // b/131797393 for more details.
764     private static final Set<String> DHCP_ROAMING_SSID_SET = new HashSet<>(
765             Arrays.asList(
766                     "0001docomo", "ollehWiFi", "olleh GiGa WiFi", "KT WiFi",
767                     "KT GiGA WiFi", "marente"
768     ));
769 
770     // The NUD failure event types to query. Although only NETWORK_EVENT_NUD_FAILURE_ORGANIC event
771     // is stored in the database currently, this array is still maintained to include other event
772     // types for testing and future expansion.
773     @VisibleForTesting
774     public static final int[] NETWORK_EVENT_NUD_FAILURE_TYPES = new int[] {
775             NETWORK_EVENT_NUD_FAILURE_ROAM,
776             NETWORK_EVENT_NUD_FAILURE_CONFIRM,
777             NETWORK_EVENT_NUD_FAILURE_ORGANIC,
778             NETWORK_EVENT_NUD_FAILURE_MAC_ADDRESS_CHANGED
779     };
780 
781     private final State mStoppedState = new StoppedState();
782     private final State mStoppingState = new StoppingState();
783     private final State mClearingIpAddressesState = new ClearingIpAddressesState();
784     private final State mStartedState = new StartedState();
785     private final State mRunningState = new RunningState();
786     private final State mPreconnectingState = new PreconnectingState();
787     private final State mNudFailureQueryState = new NudFailureQueryState();
788 
789     private final String mTag;
790     private final Context mContext;
791     private final String mInterfaceName;
792     @VisibleForTesting
793     protected final IpClientCallbacksWrapper mCallback;
794     private final ApfFilter.IApfController mIpClientApfController;
795     private final Dependencies mDependencies;
796     private final ConnectivityManager mCm;
797     private final INetd mNetd;
798     private final IpClientLinkObserver mLinkObserver;
799     private final WakeupMessage mProvisioningTimeoutAlarm;
800     private final WakeupMessage mDhcpActionTimeoutAlarm;
801     private final SharedLog mLog;
802     private final SharedLog mApfLog;
803     private final LocalLog mConnectivityPacketLog;
804     private final MessageHandlingLogger mMsgStateLogger;
805     private final IpConnectivityLog mMetricsLog;
806     private final InterfaceController mInterfaceCtrl;
807     // Set of IPv6 addresses for which unsolicited gratuitous NA packets have been sent.
808     private final Set<Inet6Address> mGratuitousNaTargetAddresses = new HashSet<>();
809     // Set of IPv6 addresses from which multicast NS packets have been sent.
810     private final Set<Inet6Address> mMulticastNsSourceAddresses = new HashSet<>();
811     // Set of delegated prefixes.
812     private final Set<IpPrefix> mDelegatedPrefixes = new HashSet<>();
813     @Nullable
814     private final DevicePolicyManager mDevicePolicyManager;
815 
816     // Ignore any nonzero RA section with lifetime below this value.
817     private final int mAcceptRaMinLft;
818 
819     // Polling interval to update APF data snapshot
820     private final long mApfCounterPollingIntervalMs;
821 
822     private final int mNudFailureCountDailyThreshold;
823     private final int mNudFailureCountWeeklyThreshold;
824 
825     // Experiment flags read from device config.
826     private final boolean mIsAcceptRaMinLftEnabled;
827     private final boolean mEnableApfPollingCounters;
828     private final boolean mPopulateLinkAddressLifetime;
829     private final boolean mEnableApf;
830     private final boolean mApfHandleArpOffload;
831     private final boolean mApfHandleNdOffload;
832     private final boolean mApfHandleMdnsOffload;
833     private final boolean mApfHandleIgmpOffload;
834     private final boolean mApfHandleMldOffload;
835     private final boolean mApfHandleIpv4PingOffload;
836     private final boolean mApfHandleIpv6PingOffload;
837     private final boolean mIgnoreNudFailureEnabled;
838     private final boolean mDhcp6PdPreferredFlagEnabled;
839     private final boolean mReplaceNetdWithNetlinkEnabled;
840 
841     private InterfaceParams mInterfaceParams;
842 
843     /**
844      * Non-final member variables accessed only from within our StateMachine.
845      */
846     private LinkProperties mLinkProperties;
847     private android.net.shared.ProvisioningConfiguration mConfiguration;
848     private IpReachabilityMonitor mIpReachabilityMonitor;
849     private DhcpClient mDhcpClient;
850     private Dhcp6Client mDhcp6Client;
851     private DhcpResults mDhcpResults;
852     private String mTcpBufferSizes;
853     private ProxyInfo mHttpProxy;
854     private ApfFilter mApfFilter;
855     private String mL2Key; // The L2 key for this network, for writing into the memory store
856     private String mCluster; // The cluster for this network, for writing into the memory store
857     private int mCreatorUid; // Uid of app creating the wifi configuration
858     private boolean mMulticastFiltering;
859     private long mStartTimeMillis;
860     private long mIPv6ProvisioningDtimGracePeriodMillis;
861     private MacAddress mCurrentBssid;
862     private boolean mHasDisabledAcceptRaDefrtrOnProvLoss;
863     private Integer mDadTransmits = null;
864     private int mMaxDtimMultiplier = DTIM_MULTIPLIER_RESET;
865     private ApfCapabilities mCurrentApfCapabilities;
866     private WakeupMessage mIpv6AutoconfTimeoutAlarm = null;
867     private boolean mIgnoreNudFailure;
868     /**
869      * An array of NUD failure event counts retrieved from the memory store  since the timestamps
870      * in the past, and is always initialized to null in StoppedState. Currently supported array
871      * elements are as follows:
872      * element 0: failures in the past week
873      * element 1: failures in the past day
874      * element 2: failures in the past 6h
875      */
876     @Nullable
877     private int[] mNudFailureEventCounts = null;
878 
879     /**
880      * The number of NUD failure events that were stored in the memory store since this IpClient
881      * was last started. Always set to zero in StoppedState. Used to prevent writing excessive NUD
882      * failure events to the memory store.
883      */
884     private int mNudFailuresStoredSinceStart = 0;
885 
886     /**
887      * Reading the snapshot is an asynchronous operation initiated by invoking
888      * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
889      * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
890      * signals when a new snapshot is ready.
891      */
892     private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
893 
894     public static class Dependencies {
895         /**
896          * Get interface parameters for the specified interface.
897          */
getInterfaceParams(String ifname)898         public InterfaceParams getInterfaceParams(String ifname) {
899             return InterfaceParams.getByName(ifname);
900         }
901 
902         /**
903          * Get a INetd connector.
904          */
getNetd(Context context)905         public INetd getNetd(Context context) {
906             return INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
907         }
908 
909         /**
910          * Get a IpMemoryStore instance.
911          */
getIpMemoryStore(Context context, NetworkStackServiceManager nssManager)912         public NetworkStackIpMemoryStore getIpMemoryStore(Context context,
913                 NetworkStackServiceManager nssManager) {
914             return new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
915         }
916 
917         /**
918          * Get a DhcpClient instance.
919          */
makeDhcpClient(Context context, StateMachine controller, InterfaceParams ifParams, DhcpClient.Dependencies deps)920         public DhcpClient makeDhcpClient(Context context, StateMachine controller,
921                 InterfaceParams ifParams, DhcpClient.Dependencies deps) {
922             return DhcpClient.makeDhcpClient(context, controller, ifParams, deps);
923         }
924 
925         /**
926          * Get a Dhcp6Client instance.
927          */
makeDhcp6Client(Context context, StateMachine controller, InterfaceParams ifParams, Dhcp6Client.Dependencies deps)928         public Dhcp6Client makeDhcp6Client(Context context, StateMachine controller,
929                 InterfaceParams ifParams, Dhcp6Client.Dependencies deps) {
930             return Dhcp6Client.makeDhcp6Client(context, controller, ifParams, deps);
931         }
932 
933         /**
934          * Get a DhcpClient Dependencies instance.
935          */
getDhcpClientDependencies( NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics)936         public DhcpClient.Dependencies getDhcpClientDependencies(
937                 NetworkStackIpMemoryStore ipMemoryStore, IpProvisioningMetrics metrics) {
938             return new DhcpClient.Dependencies(ipMemoryStore, metrics);
939         }
940 
941         /**
942          * Get a Dhcp6Client Dependencies instance.
943          */
getDhcp6ClientDependencies()944         public Dhcp6Client.Dependencies getDhcp6ClientDependencies() {
945             return new Dhcp6Client.Dependencies();
946         }
947 
948         /**
949          * Read an integer DeviceConfig property.
950          */
getDeviceConfigPropertyInt(String name, int defaultValue)951         public int getDeviceConfigPropertyInt(String name, int defaultValue) {
952             return DeviceConfigUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name,
953                     defaultValue);
954         }
955 
956         /**
957          * Get a IpConnectivityLog instance.
958          */
getIpConnectivityLog()959         public IpConnectivityLog getIpConnectivityLog() {
960             return new IpConnectivityLog();
961         }
962 
963         /**
964          * Get a NetworkQuirkMetrics instance.
965          */
getNetworkQuirkMetrics()966         public NetworkQuirkMetrics getNetworkQuirkMetrics() {
967             return new NetworkQuirkMetrics();
968         }
969 
970         /**
971          * Get a IpReachabilityMonitor instance.
972          */
getIpReachabilityMonitor(Context context, InterfaceParams ifParams, Handler h, SharedLog log, IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker, IpReachabilityMonitor.Dependencies deps, final INetd netd)973         public IpReachabilityMonitor getIpReachabilityMonitor(Context context,
974                 InterfaceParams ifParams, Handler h, SharedLog log,
975                 IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker,
976                 IpReachabilityMonitor.Dependencies deps, final INetd netd) {
977             return new IpReachabilityMonitor(context, ifParams, h, log, callback,
978                     usingMultinetworkPolicyTracker, deps, netd);
979         }
980 
981         /**
982          * Get a IpReachabilityMonitor dependencies instance.
983          */
getIpReachabilityMonitorDeps(Context context, String name)984         public IpReachabilityMonitor.Dependencies getIpReachabilityMonitorDeps(Context context,
985                 String name) {
986             return IpReachabilityMonitor.Dependencies.makeDefault(context, name);
987         }
988 
989         /**
990          * Return whether a feature guarded by a feature flag is enabled.
991          * @see DeviceConfigUtils#isNetworkStackFeatureEnabled(Context, String)
992          */
isFeatureEnabled(final Context context, final String name)993         public boolean isFeatureEnabled(final Context context, final String name) {
994             return DeviceConfigUtils.isNetworkStackFeatureEnabled(context, name);
995         }
996 
997         /**
998          * Check whether one specific feature is not disabled.
999          * @see DeviceConfigUtils#isNetworkStackFeatureNotChickenedOut(Context, String)
1000          */
isFeatureNotChickenedOut(final Context context, final String name)1001         public boolean isFeatureNotChickenedOut(final Context context, final String name) {
1002             return DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(context, name);
1003         }
1004 
1005         /**
1006          * Create an APF filter if apfCapabilities indicates support for packet filtering using
1007          * APF programs.
1008          * @see ApfFilter#maybeCreate
1009          */
maybeCreateApfFilter(Handler handler, Context context, ApfFilter.ApfConfiguration config, InterfaceParams ifParams, ApfFilter.IApfController apfController, NetworkQuirkMetrics networkQuirkMetrics)1010         public ApfFilter maybeCreateApfFilter(Handler handler, Context context,
1011                 ApfFilter.ApfConfiguration config, InterfaceParams ifParams,
1012                 ApfFilter.IApfController apfController,
1013                 NetworkQuirkMetrics networkQuirkMetrics) {
1014             return ApfFilter.maybeCreate(handler, context, config, ifParams, apfController,
1015                     networkQuirkMetrics);
1016         }
1017 
1018         /**
1019          * Check if a specific IPv6 sysctl file exists or not.
1020          */
hasIpv6Sysctl(final String ifname, final String name)1021         public boolean hasIpv6Sysctl(final String ifname, final String name) {
1022             final String path = "/proc/sys/net/ipv6/conf/" + ifname + "/" + name;
1023             final File sysctl = new File(path);
1024             return sysctl.exists();
1025         }
1026 
1027         /**
1028          * Get the configuration from RRO to check whether or not to send domain search list
1029          * option in DHCPDISCOVER/DHCPREQUEST message.
1030          */
getSendDomainSearchListOption(final Context context)1031         public boolean getSendDomainSearchListOption(final Context context) {
1032             return context.getResources().getBoolean(R.bool.config_dhcp_client_domain_search_list);
1033         }
1034 
1035         /**
1036          * Create an IpClientNetlinkMonitor instance.
1037          */
makeIpClientNetlinkMonitor(Handler h, SharedLog log, String tag, int sockRcvbufSize, boolean isDhcp6PdPreferredFlagEnabled, INetlinkMessageProcessor p)1038         public IpClientNetlinkMonitor makeIpClientNetlinkMonitor(Handler h, SharedLog log,
1039                 String tag, int sockRcvbufSize, boolean isDhcp6PdPreferredFlagEnabled,
1040                 INetlinkMessageProcessor p) {
1041             return new IpClientNetlinkMonitor(h, log, tag, sockRcvbufSize,
1042                     isDhcp6PdPreferredFlagEnabled, p);
1043         }
1044     }
1045 
IpClient(Context context, String ifName, IIpClientCallbacks callback, NetworkStackServiceManager nssManager)1046     public IpClient(Context context, String ifName, IIpClientCallbacks callback,
1047             NetworkStackServiceManager nssManager) {
1048         this(context, ifName, callback, nssManager, new Dependencies());
1049     }
1050 
1051     @VisibleForTesting
IpClient(Context context, String ifName, IIpClientCallbacks callback, NetworkStackServiceManager nssManager, Dependencies deps)1052     public IpClient(Context context, String ifName, IIpClientCallbacks callback,
1053             NetworkStackServiceManager nssManager, Dependencies deps) {
1054         super(IpClient.class.getSimpleName() + "." + ifName);
1055         Objects.requireNonNull(ifName);
1056         Objects.requireNonNull(callback);
1057 
1058         mTag = getName();
1059 
1060         mDevicePolicyManager = (DevicePolicyManager)
1061                 context.getSystemService(Context.DEVICE_POLICY_SERVICE);
1062         mContext = context;
1063         mInterfaceName = ifName;
1064         mDependencies = deps;
1065         mMetricsLog = deps.getIpConnectivityLog();
1066         mNetworkQuirkMetrics = deps.getNetworkQuirkMetrics();
1067         mCm = mContext.getSystemService(ConnectivityManager.class);
1068         mIpMemoryStore = deps.getIpMemoryStore(context, nssManager);
1069 
1070         sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
1071         mLog = sSmLogs.get(mInterfaceName);
1072         sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
1073         mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
1074         sApfLogs.putIfAbsent(mInterfaceName, new SharedLog(10 /* maxRecords */, mTag));
1075         mApfLog = sApfLogs.get(mInterfaceName);
1076         mApfDebug = Log.isLoggable(ApfFilter.class.getSimpleName(), Log.DEBUG);
1077         mMsgStateLogger = new MessageHandlingLogger();
1078         mCallback = new IpClientCallbacksWrapper(callback, mLog, mApfLog, mShim, mApfDebug);
1079         mIpClientApfController = new ApfFilter.IApfController() {
1080             @Override
1081             public boolean installPacketFilter(byte[] filter, String filterConfig) {
1082                 return mCallback.installPacketFilter(filter, filterConfig);
1083             }
1084 
1085             @Override
1086             public void readPacketFilterRam(String event) {
1087                 mCallback.startReadPacketFilter(event);
1088             }
1089         };
1090 
1091         // TODO: Consider creating, constructing, and passing in some kind of
1092         // InterfaceController.Dependencies class.
1093         mNetd = deps.getNetd(mContext);
1094         mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
1095 
1096         mAcceptRaMinLft = mDependencies.getDeviceConfigPropertyInt(CONFIG_ACCEPT_RA_MIN_LFT,
1097                 DEFAULT_ACCEPT_RA_MIN_LFT);
1098         mApfCounterPollingIntervalMs = mDependencies.getDeviceConfigPropertyInt(
1099                 CONFIG_APF_COUNTER_POLLING_INTERVAL_SECS,
1100                 DEFAULT_APF_COUNTER_POLLING_INTERVAL_SECS) * DateUtils.SECOND_IN_MILLIS;
1101         mEnableApfPollingCounters = mDependencies.isFeatureEnabled(context,
1102                 APF_POLLING_COUNTERS_VERSION);
1103         mIsAcceptRaMinLftEnabled =
1104                 SdkLevel.isAtLeastV() || mDependencies.isFeatureEnabled(context,
1105                         IPCLIENT_IGNORE_LOW_RA_LIFETIME_VERSION);
1106         mEnableApf = mDependencies.isFeatureNotChickenedOut(mContext, APF_ENABLE);
1107         mApfHandleArpOffload = mDependencies.isFeatureNotChickenedOut(
1108                 mContext, APF_HANDLE_ARP_OFFLOAD);
1109         mApfHandleNdOffload = mDependencies.isFeatureNotChickenedOut(
1110                 mContext, APF_HANDLE_ND_OFFLOAD);
1111         // TODO: turn on APF mDNS offload on handhelds.
1112         mApfHandleMdnsOffload = isAtLeast25Q2() && context.getPackageManager().hasSystemFeature(
1113                 FEATURE_LEANBACK);
1114         mApfHandleIgmpOffload =
1115                 mDependencies.isFeatureNotChickenedOut(mContext, APF_HANDLE_IGMP_OFFLOAD)
1116                     && (isAtLeast25Q2()
1117                         || mDependencies.isFeatureEnabled(context, APF_HANDLE_IGMP_OFFLOAD_VERSION)
1118                     );
1119         mApfHandleMldOffload =
1120                 mDependencies.isFeatureNotChickenedOut(mContext, APF_HANDLE_MLD_OFFLOAD)
1121                     && (isAtLeast25Q2()
1122                         || mDependencies.isFeatureEnabled(context, APF_HANDLE_MLD_OFFLOAD_VERSION)
1123                     );
1124         mApfHandleIpv4PingOffload =
1125                 mDependencies.isFeatureNotChickenedOut(mContext, APF_HANDLE_PING4_OFFLOAD)
1126                     && (isAtLeast25Q2()
1127                         || mDependencies.isFeatureEnabled(context, APF_HANDLE_PING4_OFFLOAD_VERSION)
1128                     );
1129         mApfHandleIpv6PingOffload =
1130                 mDependencies.isFeatureNotChickenedOut(mContext, APF_HANDLE_PING6_OFFLOAD)
1131                     && (isAtLeast25Q2()
1132                         || mDependencies.isFeatureEnabled(context, APF_HANDLE_PING6_OFFLOAD_VERSION)
1133                 );
1134         mPopulateLinkAddressLifetime = mDependencies.isFeatureEnabled(context,
1135                 IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION);
1136         mIgnoreNudFailureEnabled = mDependencies.isFeatureEnabled(mContext,
1137                 IP_REACHABILITY_IGNORE_NUD_FAILURE_VERSION);
1138         mNudFailureCountDailyThreshold = mDependencies.getDeviceConfigPropertyInt(
1139                 CONFIG_NUD_FAILURE_COUNT_DAILY_THRESHOLD,
1140                 DEFAULT_NUD_FAILURE_COUNT_DAILY_THRESHOLD);
1141         mNudFailureCountWeeklyThreshold = mDependencies.getDeviceConfigPropertyInt(
1142                 CONFIG_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD,
1143                 DEFAULT_NUD_FAILURE_COUNT_WEEKLY_THRESHOLD);
1144         mDhcp6PdPreferredFlagEnabled =
1145                 mDependencies.isFeatureEnabled(mContext, IPCLIENT_DHCPV6_PD_PREFERRED_FLAG_VERSION);
1146         mReplaceNetdWithNetlinkEnabled = mDependencies.isFeatureEnabled(mContext,
1147                 IPCLIENT_REPLACE_NETD_WITH_NETLINK_VERSION);
1148         IpClientLinkObserver.Configuration config = new IpClientLinkObserver.Configuration(
1149                 mAcceptRaMinLft, mPopulateLinkAddressLifetime, mDhcp6PdPreferredFlagEnabled);
1150 
1151         mLinkObserver = new IpClientLinkObserver(
1152                 mContext, getHandler(),
1153                 mInterfaceName,
1154                 new IpClientLinkObserver.Callback() {
1155                     @Override
1156                     public void update(boolean linkState) {
1157                         sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED, linkState
1158                                 ? ARG_LINKPROP_CHANGED_LINKSTATE_UP
1159                                 : ARG_LINKPROP_CHANGED_LINKSTATE_DOWN);
1160                     }
1161 
1162                     @Override
1163                     public void onIpv6AddressRemoved(final Inet6Address address) {
1164                         // The update of Gratuitous NA target addresses set or unsolicited
1165                         // multicast NS source addresses set should be only accessed from the
1166                         // handler thread of IpClient StateMachine. This can be done by either
1167                         // sending a message to StateMachine or posting a handler.
1168                         if (address.isLinkLocalAddress()) return;
1169                         getHandler().post(() -> {
1170                             mLog.log("Remove IPv6 GUA " + address
1171                                     + " from both Gratuituous NA and Multicast NS sets");
1172                             mGratuitousNaTargetAddresses.remove(address);
1173                             mMulticastNsSourceAddresses.remove(address);
1174                         });
1175                     }
1176 
1177                     @Override
1178                     public void onClatInterfaceStateUpdate(boolean add) {
1179                         getHandler().post(() -> {
1180                             if (mHasSeenClatInterface == add) return;
1181                             // If Apf is not supported or Apf doesn't support ND offload, then
1182                             // configure the vendor ND offload feature based on the Clat
1183                             // interface state.
1184                             if (mApfFilter == null || !mApfFilter.enableNdOffload()) {
1185                                 // Clat interface information is spliced into LinkProperties by
1186                                 // ConnectivityService, so it cannot be added to the LinkProperties
1187                                 // here as those propagate back to ConnectivityService.
1188                                 mCallback.setNeighborDiscoveryOffload(add ? false : true);
1189                             }
1190                             mHasSeenClatInterface = add;
1191                             if (mApfFilter != null) {
1192                                 mApfFilter.updateClatInterfaceState(add);
1193                             }
1194                         });
1195                     }
1196 
1197                     @Override
1198                     public void onNewPrefix(PrefixInfo info) {
1199                         if (!mDhcp6PdPreferredFlagEnabled) return;
1200                         sendMessage(EVENT_PIO_PREFIX_UPDATE, info);
1201                     }
1202                 },
1203                 config, mLog, mDependencies
1204         );
1205 
1206         mLinkProperties = new LinkProperties();
1207         mLinkProperties.setInterfaceName(mInterfaceName);
1208 
1209         mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
1210                 mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
1211         mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
1212                 mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
1213 
1214         // Anything the StateMachine may access must have been instantiated
1215         // before this point.
1216         configureAndStartStateMachine();
1217 
1218         // Anything that may send messages to the StateMachine must only be
1219         // configured to do so after the StateMachine has started (above).
1220         startStateMachineUpdaters();
1221     }
1222 
1223     /**
1224      * Make a IIpClient connector to communicate with this IpClient.
1225      */
makeConnector()1226     public IIpClient makeConnector() {
1227         return new IpClientConnector();
1228     }
1229 
1230     class IpClientConnector extends IIpClient.Stub {
1231         @Override
completedPreDhcpAction()1232         public void completedPreDhcpAction() {
1233             enforceNetworkStackCallingPermission();
1234             IpClient.this.completedPreDhcpAction();
1235         }
1236         @Override
confirmConfiguration()1237         public void confirmConfiguration() {
1238             enforceNetworkStackCallingPermission();
1239             IpClient.this.confirmConfiguration();
1240         }
1241         @Override
readPacketFilterComplete(byte[] data)1242         public void readPacketFilterComplete(byte[] data) {
1243             enforceNetworkStackCallingPermission();
1244             IpClient.this.readPacketFilterComplete(data);
1245         }
1246         @Override
shutdown()1247         public void shutdown() {
1248             enforceNetworkStackCallingPermission();
1249             IpClient.this.shutdown();
1250         }
1251         @Override
startProvisioning(ProvisioningConfigurationParcelable req)1252         public void startProvisioning(ProvisioningConfigurationParcelable req) {
1253             enforceNetworkStackCallingPermission();
1254             IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req,
1255                     mCallback.getInterfaceVersion()));
1256         }
1257         @Override
stop()1258         public void stop() {
1259             enforceNetworkStackCallingPermission();
1260             IpClient.this.stop();
1261         }
1262         @Override
setL2KeyAndGroupHint(String l2Key, String cluster)1263         public void setL2KeyAndGroupHint(String l2Key, String cluster) {
1264             enforceNetworkStackCallingPermission();
1265             // This method is not supported anymore. The caller should call
1266             // #updateLayer2Information() instead.
1267         }
1268         @Override
setTcpBufferSizes(String tcpBufferSizes)1269         public void setTcpBufferSizes(String tcpBufferSizes) {
1270             enforceNetworkStackCallingPermission();
1271             IpClient.this.setTcpBufferSizes(tcpBufferSizes);
1272         }
1273         @Override
setHttpProxy(ProxyInfo proxyInfo)1274         public void setHttpProxy(ProxyInfo proxyInfo) {
1275             enforceNetworkStackCallingPermission();
1276             IpClient.this.setHttpProxy(proxyInfo);
1277         }
1278         @Override
setMulticastFilter(boolean enabled)1279         public void setMulticastFilter(boolean enabled) {
1280             enforceNetworkStackCallingPermission();
1281             IpClient.this.setMulticastFilter(enabled);
1282         }
1283         @Override
addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt)1284         public void addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) {
1285             enforceNetworkStackCallingPermission();
1286             IpClient.this.addKeepalivePacketFilter(slot, pkt);
1287         }
1288         @Override
addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt)1289         public void addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt) {
1290             enforceNetworkStackCallingPermission();
1291             IpClient.this.addNattKeepalivePacketFilter(slot, pkt);
1292         }
1293         @Override
removeKeepalivePacketFilter(int slot)1294         public void removeKeepalivePacketFilter(int slot) {
1295             enforceNetworkStackCallingPermission();
1296             IpClient.this.removeKeepalivePacketFilter(slot);
1297         }
1298         @Override
notifyPreconnectionComplete(boolean success)1299         public void notifyPreconnectionComplete(boolean success) {
1300             enforceNetworkStackCallingPermission();
1301             IpClient.this.notifyPreconnectionComplete(success);
1302         }
1303         @Override
updateLayer2Information(Layer2InformationParcelable info)1304         public void updateLayer2Information(Layer2InformationParcelable info) {
1305             enforceNetworkStackCallingPermission();
1306             IpClient.this.updateLayer2Information(info);
1307         }
1308         @Override
updateApfCapabilities(ApfCapabilities apfCapabilities)1309         public void updateApfCapabilities(ApfCapabilities apfCapabilities) {
1310             enforceNetworkStackCallingPermission();
1311             IpClient.this.updateApfCapabilities(apfCapabilities);
1312         }
1313 
1314         @Override
getInterfaceVersion()1315         public int getInterfaceVersion() {
1316             return this.VERSION;
1317         }
1318 
1319         @Override
getInterfaceHash()1320         public String getInterfaceHash() {
1321             return this.HASH;
1322         }
1323     }
1324 
getInterfaceName()1325     public String getInterfaceName() {
1326         return mInterfaceName;
1327     }
1328 
configureAndStartStateMachine()1329     private void configureAndStartStateMachine() {
1330         // CHECKSTYLE:OFF IndentationCheck
1331         addState(mStoppedState);
1332         addState(mStartedState);
1333             addState(mPreconnectingState, mStartedState);
1334             addState(mNudFailureQueryState, mStartedState);
1335             addState(mClearingIpAddressesState, mStartedState);
1336             addState(mRunningState, mStartedState);
1337         addState(mStoppingState);
1338         // CHECKSTYLE:ON IndentationCheck
1339 
1340         setInitialState(mStoppedState);
1341 
1342         super.start();
1343     }
1344 
startStateMachineUpdaters()1345     private void startStateMachineUpdaters() {
1346     }
1347 
stopStateMachineUpdaters()1348     private void stopStateMachineUpdaters() {
1349         mLinkObserver.clearInterfaceParams();
1350         mLinkObserver.shutdown();
1351     }
1352 
1353     @VisibleForTesting
getInitialBssid(final Layer2Information layer2Info, final ScanResultInfo scanResultInfo, boolean isAtLeastS)1354     static MacAddress getInitialBssid(final Layer2Information layer2Info,
1355             final ScanResultInfo scanResultInfo, boolean isAtLeastS) {
1356         MacAddress bssid = null;
1357         // http://b/185202634
1358         // ScanResultInfo is not populated in some situations.
1359         // On S and above, prefer getting the BSSID from the Layer2Info.
1360         // On R and below, get the BSSID from the ScanResultInfo and fall back to
1361         // getting it from the Layer2Info. This ensures no regressions if any R
1362         // devices pass in a null or meaningless BSSID in the Layer2Info.
1363         if (!isAtLeastS && scanResultInfo != null) {
1364             try {
1365                 bssid = MacAddress.fromString(scanResultInfo.getBssid());
1366             } catch (IllegalArgumentException e) {
1367                 Log.wtf(TAG, "Invalid BSSID: " + scanResultInfo.getBssid()
1368                         + " in provisioning configuration", e);
1369             }
1370         }
1371         if (bssid == null && layer2Info != null) {
1372             bssid = layer2Info.mBssid;
1373         }
1374         return bssid;
1375     }
1376 
1377     @Override
onQuitting()1378     protected void onQuitting() {
1379         mCallback.onQuit();
1380     }
1381 
1382     /**
1383      * Shut down this IpClient instance altogether.
1384      */
shutdown()1385     public void shutdown() {
1386         stop();
1387         sendMessage(CMD_TERMINATE_AFTER_STOP);
1388     }
1389 
1390     /**
1391      * Start provisioning with the provided parameters.
1392      */
startProvisioning(ProvisioningConfiguration req)1393     public void startProvisioning(ProvisioningConfiguration req) {
1394         if (!req.isValid()) {
1395             doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
1396             return;
1397         }
1398         sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
1399     }
1400 
1401     /**
1402      * Stop this IpClient.
1403      *
1404      * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}.
1405      *    The message "arg1" parameter is used to record the disconnect code metrics.
1406      *    Usually this method is called by the peer (e.g. wifi) intentionally to stop IpClient,
1407      *    consider that's the normal user termination.
1408      */
stop()1409     public void stop() {
1410         sendMessage(CMD_STOP, DisconnectCode.DC_NORMAL_TERMINATION.getNumber());
1411     }
1412 
1413     /**
1414      * Confirm the provisioning configuration.
1415      */
confirmConfiguration()1416     public void confirmConfiguration() {
1417         sendMessage(CMD_CONFIRM);
1418     }
1419 
1420     /**
1421      * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be
1422      * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to
1423      * proceed.
1424      */
completedPreDhcpAction()1425     public void completedPreDhcpAction() {
1426         sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
1427     }
1428 
1429     /**
1430      * Indicate that packet filter read is complete.
1431      */
readPacketFilterComplete(byte[] data)1432     public void readPacketFilterComplete(byte[] data) {
1433         sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
1434     }
1435 
1436     /**
1437      * Set the TCP buffer sizes to use.
1438      *
1439      * This may be called, repeatedly, at any time before or after a call to
1440      * #startProvisioning(). The setting is cleared upon calling #stop().
1441      */
setTcpBufferSizes(String tcpBufferSizes)1442     public void setTcpBufferSizes(String tcpBufferSizes) {
1443         sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
1444     }
1445 
1446     /**
1447      * Set the HTTP Proxy configuration to use.
1448      *
1449      * This may be called, repeatedly, at any time before or after a call to
1450      * #startProvisioning(). The setting is cleared upon calling #stop().
1451      */
setHttpProxy(ProxyInfo proxyInfo)1452     public void setHttpProxy(ProxyInfo proxyInfo) {
1453         sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
1454     }
1455 
1456     /**
1457      * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
1458      * if not, Callback.setFallbackMulticastFilter() is called.
1459      */
setMulticastFilter(boolean enabled)1460     public void setMulticastFilter(boolean enabled) {
1461         sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
1462     }
1463 
1464     /**
1465      * Called by WifiStateMachine to add TCP keepalive packet filter before setting up
1466      * keepalive offload.
1467      */
addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt)1468     public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
1469         sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
1470     }
1471 
1472     /**
1473      *  Called by WifiStateMachine to add NATT keepalive packet filter before setting up
1474      *  keepalive offload.
1475      */
addNattKeepalivePacketFilter(int slot, @NonNull NattKeepalivePacketDataParcelable pkt)1476     public void addNattKeepalivePacketFilter(int slot,
1477             @NonNull NattKeepalivePacketDataParcelable pkt) {
1478         sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */ , pkt);
1479     }
1480 
1481     /**
1482      * Called by WifiStateMachine to remove keepalive packet filter after stopping keepalive
1483      * offload.
1484      */
removeKeepalivePacketFilter(int slot)1485     public void removeKeepalivePacketFilter(int slot) {
1486         sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot, 0 /* Unused */);
1487     }
1488 
1489     /**
1490      * Notify IpClient that preconnection is complete and that the link is ready for use.
1491      * The success parameter indicates whether the packets passed in by onPreconnectionStart were
1492      * successfully sent to the network or not.
1493      */
notifyPreconnectionComplete(boolean success)1494     public void notifyPreconnectionComplete(boolean success) {
1495         sendMessage(CMD_COMPLETE_PRECONNECTION, success ? 1 : 0);
1496     }
1497 
1498     /**
1499      * Update the network bssid, L2Key and cluster on L2 roaming happened.
1500      */
updateLayer2Information(@onNull Layer2InformationParcelable info)1501     public void updateLayer2Information(@NonNull Layer2InformationParcelable info) {
1502         sendMessage(CMD_UPDATE_L2INFORMATION, info);
1503     }
1504 
1505     /**
1506      * Update the APF capabilities.
1507      *
1508      * This method will update the APF capabilities used in IpClient and decide if a new APF
1509      * program should be installed to filter the incoming packets based on that. So far this
1510      * method only allows for the APF capabilities to go from null to non-null, and no other
1511      * changes are allowed. One use case is when WiFi interface switches from secondary to
1512      * primary in STA+STA mode.
1513      */
updateApfCapabilities(@onNull ApfCapabilities apfCapabilities)1514     public void updateApfCapabilities(@NonNull ApfCapabilities apfCapabilities) {
1515         sendMessage(CMD_UPDATE_APF_CAPABILITIES, apfCapabilities);
1516     }
1517 
1518     /**
1519      * Dump logs of this IpClient.
1520      */
dump(FileDescriptor fd, PrintWriter writer, String[] args)1521     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1522         if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
1523             // Execute confirmConfiguration() and take no further action.
1524             confirmConfiguration();
1525             return;
1526         }
1527 
1528         // Thread-unsafe access to mApfFilter but just used for debugging.
1529         final ApfFilter apfFilter = mApfFilter;
1530         final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration;
1531         final ApfCapabilities apfCapabilities = mCurrentApfCapabilities;
1532 
1533         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
1534         pw.println(mTag + " APF dump:");
1535         pw.increaseIndent();
1536         if (apfFilter != null) {
1537             if (apfCapabilities != null && apfFilter.hasDataAccess(
1538                     apfCapabilities.apfVersionSupported)) {
1539                 // Request a new snapshot, then wait for it.
1540                 mApfDataSnapshotComplete.close();
1541                 // To ensure long-term flexibility and support for different APF controller
1542                 // implementations (e.g., Ethtool-based), we use apfFilter.getApfController()
1543                 // instead of directly accessing mIpClientApfController. This approach makes
1544                 // code reusable and simplifies future transitions to alternative APF
1545                 // controllers.
1546                 apfFilter.getApfController().readPacketFilterRam("dumpsys");
1547                 if (!mApfDataSnapshotComplete.block(1000)) {
1548                     pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
1549                 }
1550             }
1551             final Handler handler = getHandler();
1552             if (handler == null) {
1553                 // This situation is unexpected. The getHandler() function should not return null
1554                 // unless the IpClient has stopped running. When the IpClient exits the RunningState
1555                 // , it should have already set apfFilter to null.
1556                 pw.println("ApfFilter is not null even if IpClient is not running.");
1557             } else {
1558                 HandlerUtils.runWithScissorsForDump(handler, () -> apfFilter.dump(pw),
1559                         10_000 /* ms */);
1560             }
1561             pw.println("APF log:");
1562             pw.println("mApfDebug: " + mApfDebug);
1563             mApfLog.dump(fd, pw, args);
1564         } else {
1565             pw.print("No active ApfFilter; ");
1566             if (provisioningConfig == null) {
1567                 pw.println("IpClient not yet started.");
1568             } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
1569                 pw.println("Hardware does not support APF.");
1570             } else {
1571                 pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
1572             }
1573         }
1574         pw.decreaseIndent();
1575         pw.println();
1576         pw.println(mTag + " current ProvisioningConfiguration:");
1577         pw.increaseIndent();
1578         pw.println(Objects.toString(provisioningConfig, "N/A"));
1579         pw.decreaseIndent();
1580 
1581         final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
1582         if (iprm != null) {
1583             pw.println();
1584             pw.println(mTag + " current IpReachabilityMonitor state:");
1585             pw.increaseIndent();
1586             iprm.dump(pw);
1587             pw.decreaseIndent();
1588         }
1589 
1590         pw.println();
1591         pw.println(mTag + " StateMachine dump:");
1592         pw.increaseIndent();
1593         mLog.dump(fd, pw, args);
1594         pw.decreaseIndent();
1595 
1596         pw.println();
1597         pw.println(mTag + " connectivity packet log:");
1598         pw.println();
1599         pw.println("Debug with python and scapy via:");
1600         pw.println("shell$ python");
1601         pw.println(">>> from scapy import all as scapy");
1602         pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
1603         pw.println();
1604 
1605         pw.increaseIndent();
1606         mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
1607         pw.decreaseIndent();
1608     }
1609 
1610     /**
1611      * Handle "adb shell cmd apf" command.
1612      */
apfShellCommand(String cmd, @Nullable String optarg)1613     public String apfShellCommand(String cmd, @Nullable String optarg) {
1614         final long oneDayInMs = 86400 * 1000;
1615         if (SystemClock.elapsedRealtime() >= oneDayInMs) {
1616             throw new IllegalStateException("Error: This test interface requires uptime < 24h");
1617         }
1618 
1619         // Waiting for a "read" result cannot block the handler thread, since the result gets
1620         // processed on it. This is test only code, so mApfFilter going away is not a concern.
1621         if (cmd.equals("read")) {
1622             if (mApfFilter == null) {
1623                 throw new IllegalStateException("Error: No active APF filter");
1624             }
1625             // Request a new snapshot, then wait for it.
1626             mApfDataSnapshotComplete.close();
1627             mApfFilter.getApfController().readPacketFilterRam("shell command");
1628             if (!mApfDataSnapshotComplete.block(5000 /* ms */)) {
1629                 throw new RuntimeException("Error: Failed to read APF program");
1630             }
1631         }
1632 
1633         final CompletableFuture<String> result = new CompletableFuture<>();
1634 
1635         getHandler().post(() -> {
1636             try {
1637                 if (mApfFilter == null) {
1638                     // IpClient has either stopped or the interface does not support APF.
1639                     throw new IllegalStateException("No active APF filter.");
1640                 }
1641                 switch (cmd) {
1642                     case "status":
1643                         result.complete(mApfFilter.isRunning() ? "running" : "paused");
1644                         break;
1645                     case "pause":
1646                         mApfFilter.pause();
1647                         result.complete("success");
1648                         break;
1649                     case "resume":
1650                         mApfFilter.resume();
1651                         result.complete("success");
1652                         break;
1653                     case "install":
1654                         Objects.requireNonNull(optarg, "No program provided");
1655                         if (mApfFilter.isRunning()) {
1656                             throw new IllegalStateException("APF filter must first be paused");
1657                         }
1658                         mApfFilter.getApfController().installPacketFilter(
1659                                 HexDump.hexStringToByteArray(optarg), "program from shell command");
1660                         result.complete("success");
1661                         break;
1662                     case "capabilities":
1663                         final StringJoiner joiner = new StringJoiner(",");
1664                         joiner.add(Integer.toString(mCurrentApfCapabilities.apfVersionSupported));
1665                         joiner.add(Integer.toString(mCurrentApfCapabilities.maximumApfProgramSize));
1666                         joiner.add(Integer.toString(mCurrentApfCapabilities.apfPacketFormat));
1667                         result.complete(joiner.toString());
1668                         break;
1669                     case "read":
1670                         final String snapshot = mApfFilter.getDataSnapshotHexString();
1671                         Objects.requireNonNull(snapshot, "No data snapshot recorded.");
1672                         result.complete(snapshot);
1673                         break;
1674                     default:
1675                         throw new IllegalArgumentException("Invalid apf command: " + cmd);
1676                 }
1677             } catch (Exception e) {
1678                 result.completeExceptionally(e);
1679             }
1680         });
1681 
1682         try {
1683             return result.get(30, TimeUnit.SECONDS);
1684         } catch (ExecutionException | InterruptedException | TimeoutException e) {
1685             // completeExceptionally is solely used to return error messages back to the user, so
1686             // the stack trace is not all that interesting. (A similar argument can be made for
1687             // InterruptedException). Only extract the message from the checked exception.
1688             throw new RuntimeException(e.getMessage());
1689         }
1690     }
1691 
1692     /**
1693      * Internals.
1694      */
1695 
1696     @Override
getWhatToString(int what)1697     protected String getWhatToString(int what) {
1698         return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
1699     }
1700 
1701     @Override
getLogRecString(Message msg)1702     protected String getLogRecString(Message msg) {
1703         final String logLine = String.format(
1704                 "%s/%d %d %d %s [%s]",
1705                 mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
1706                 msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
1707 
1708         final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
1709         mLog.log(richerLogLine);
1710         if (DBG) {
1711             Log.d(mTag, richerLogLine);
1712         }
1713 
1714         mMsgStateLogger.reset();
1715         return logLine;
1716     }
1717 
1718     @Override
recordLogRec(Message msg)1719     protected boolean recordLogRec(Message msg) {
1720         // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
1721         // and we already log any LinkProperties change that results in an
1722         // invocation of IpClient.Callback#onLinkPropertiesChange().
1723         final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
1724         if (!shouldLog) {
1725             mMsgStateLogger.reset();
1726         }
1727         return shouldLog;
1728     }
1729 
logError(String fmt, Throwable e, Object... args)1730     private void logError(String fmt, Throwable e, Object... args) {
1731         mLog.e(String.format(fmt, args), e);
1732     }
1733 
logError(String fmt, Object... args)1734     private void logError(String fmt, Object... args) {
1735         logError(fmt, null, args);
1736     }
1737 
1738     // This needs to be called with care to ensure that our LinkProperties
1739     // are in sync with the actual LinkProperties of the interface. For example,
1740     // we should only call this if we know for sure that there are no IP addresses
1741     // assigned to the interface, etc.
resetLinkProperties()1742     private void resetLinkProperties() {
1743         mLinkObserver.clearLinkProperties();
1744         mConfiguration = null;
1745         mDhcpResults = null;
1746         mTcpBufferSizes = "";
1747         mHttpProxy = null;
1748 
1749         mLinkProperties = new LinkProperties();
1750         mLinkProperties.setInterfaceName(mInterfaceName);
1751     }
1752 
recordMetric(final int type)1753     private void recordMetric(final int type) {
1754         // We may record error metrics prior to starting.
1755         // Map this to IMMEDIATE_FAILURE_DURATION.
1756         final long duration = (mStartTimeMillis > 0)
1757                 ? (SystemClock.elapsedRealtime() - mStartTimeMillis)
1758                 : IMMEDIATE_FAILURE_DURATION;
1759         mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
1760     }
1761 
1762     // Record the DisconnectCode and transition to StoppingState.
transitionToStoppingState(final DisconnectCode code)1763     private void transitionToStoppingState(final DisconnectCode code) {
1764         mIpProvisioningMetrics.setDisconnectCode(code);
1765         transitionTo(mStoppingState);
1766     }
1767 
1768     // Convert reachability loss reason enum to a string.
reachabilityLossReasonToString(int reason)1769     private static String reachabilityLossReasonToString(int reason) {
1770         switch (reason) {
1771             case ReachabilityLossReason.ROAM:
1772                 return "reachability_loss_after_roam";
1773             case ReachabilityLossReason.CONFIRM:
1774                 return "reachability_loss_after_confirm";
1775             case ReachabilityLossReason.ORGANIC:
1776                 return "reachability_loss_organic";
1777             default:
1778                 return "unknown";
1779         }
1780     }
1781 
hasIpv6LinkLocalInterfaceRoute(final LinkProperties lp)1782     private static boolean hasIpv6LinkLocalInterfaceRoute(final LinkProperties lp) {
1783         for (RouteInfo r : lp.getRoutes()) {
1784             if (r.getDestination().equals(new IpPrefix("fe80::/64"))
1785                     && r.getGateway().isAnyLocalAddress()) {
1786                 return true;
1787             }
1788         }
1789         return false;
1790     }
1791 
hasIpv6LinkLocalAddress(final LinkProperties lp)1792     private static boolean hasIpv6LinkLocalAddress(final LinkProperties lp) {
1793         for (LinkAddress address : lp.getLinkAddresses()) {
1794             if (address.isIpv6() && address.getAddress().isLinkLocalAddress()) {
1795                 return true;
1796             }
1797         }
1798         return false;
1799     }
1800 
1801     // LinkProperties has a link-local (fe80::xxx) IPv6 address and route to fe80::/64 destination.
isIpv6LinkLocalProvisioned(final LinkProperties lp)1802     private boolean isIpv6LinkLocalProvisioned(final LinkProperties lp) {
1803         if (mConfiguration == null
1804                 || mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_LINKLOCAL) return false;
1805         if (hasIpv6LinkLocalAddress(lp) && hasIpv6LinkLocalInterfaceRoute(lp)) return true;
1806         return false;
1807     }
1808 
1809     // For now: use WifiStateMachine's historical notion of provisioned.
1810     @VisibleForTesting
isProvisioned(final LinkProperties lp, final InitialConfiguration config)1811     boolean isProvisioned(final LinkProperties lp, final InitialConfiguration config) {
1812         // For historical reasons, we should connect even if all we have is an IPv4
1813         // address and nothing else. If IPv6 link-local only mode is enabled and
1814         // it's provisioned without IPv4, then still connecting once IPv6 link-local
1815         // address is ready to use and route to fe80::/64 destination is up.
1816         if (lp.hasIpv4Address() || lp.isProvisioned() || isIpv6LinkLocalProvisioned(lp)) {
1817             return true;
1818         }
1819         if (config == null) {
1820             return false;
1821         }
1822 
1823         // When an InitialConfiguration is specified, ignore any difference with previous
1824         // properties and instead check if properties observed match the desired properties.
1825         return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
1826     }
1827 
1828     // Set "/proc/sys/net/ipv6/conf/${iface}/${name}" with the given specific value.
setIpv6Sysctl(@onNull final String name, int value)1829     private void setIpv6Sysctl(@NonNull final String name, int value) {
1830         try {
1831             mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mInterfaceName,
1832                     name, Integer.toString(value));
1833         } catch (Exception e) {
1834             Log.e(mTag, "Failed to set " + name + " to " + value + ": " + e);
1835         }
1836     }
1837 
1838     // Read "/proc/sys/net/ipv6/conf/${iface}/${name}".
getIpv6Sysctl(@onNull final String name)1839     private Integer getIpv6Sysctl(@NonNull final String name) {
1840         try {
1841             return Integer.parseInt(mNetd.getProcSysNet(INetd.IPV6, INetd.CONF,
1842                     mInterfaceName, name));
1843         } catch (RemoteException | ServiceSpecificException e) {
1844             logError("Couldn't read " + name + " on " + mInterfaceName, e);
1845             return null;
1846         }
1847     }
1848 
1849     // TODO: Investigate folding all this into the existing static function
1850     // LinkProperties.compareProvisioning() or some other single function that
1851     // takes two LinkProperties objects and returns a ProvisioningChange
1852     // object that is a correct and complete assessment of what changed, taking
1853     // account of the asymmetries described in the comments in this function.
1854     // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
compareProvisioning(LinkProperties oldLp, LinkProperties newLp)1855     private int compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
1856         int delta;
1857         InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
1858         final boolean wasProvisioned = isProvisioned(oldLp, config);
1859         final boolean isProvisioned = isProvisioned(newLp, config);
1860 
1861         if (!wasProvisioned && isProvisioned) {
1862             delta = PROV_CHANGE_GAINED_PROVISIONING;
1863         } else if (wasProvisioned && isProvisioned) {
1864             delta = PROV_CHANGE_STILL_PROVISIONED;
1865         } else if (!wasProvisioned && !isProvisioned) {
1866             delta = PROV_CHANGE_STILL_NOT_PROVISIONED;
1867         } else {
1868             // (wasProvisioned && !isProvisioned)
1869             //
1870             // Note that this is true even if we lose a configuration element
1871             // (e.g., a default gateway) that would not be required to advance
1872             // into provisioned state. This is intended: if we have a default
1873             // router and we lose it, that's a sure sign of a problem, but if
1874             // we connect to a network with no IPv4 DNS servers, we consider
1875             // that to be a network without DNS servers and connect anyway.
1876             //
1877             // See the comment below.
1878             delta = PROV_CHANGE_LOST_PROVISIONING;
1879         }
1880 
1881         final boolean lostIPv6 = oldLp.isIpv6Provisioned() && !newLp.isIpv6Provisioned();
1882         final boolean lostIPv4Address = oldLp.hasIpv4Address() && !newLp.hasIpv4Address();
1883         final boolean lostIPv6Router = oldLp.hasIpv6DefaultRoute() && !newLp.hasIpv6DefaultRoute();
1884 
1885         // If bad wifi avoidance is disabled, then ignore IPv6 loss of
1886         // provisioning. Otherwise, when a hotspot that loses Internet
1887         // access sends out a 0-lifetime RA to its clients, the clients
1888         // will disconnect and then reconnect, avoiding the bad hotspot,
1889         // instead of getting stuck on the bad hotspot. http://b/31827713 .
1890         //
1891         // This is incorrect because if the hotspot then regains Internet
1892         // access with a different prefix, TCP connections on the
1893         // deprecated addresses will remain stuck.
1894         //
1895         // Note that we can still be disconnected by IpReachabilityMonitor
1896         // if the IPv6 default gateway (but not the IPv6 DNS servers; see
1897         // accompanying code in IpReachabilityMonitor) is unreachable.
1898         final boolean ignoreIPv6ProvisioningLoss = mHasDisabledAcceptRaDefrtrOnProvLoss
1899                 || (mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
1900                         && !mCm.shouldAvoidBadWifi());
1901 
1902         // Additionally:
1903         //
1904         // Partial configurations (e.g., only an IPv4 address with no DNS
1905         // servers and no default route) are accepted as long as DHCPv4
1906         // succeeds. On such a network, isProvisioned() will always return
1907         // false, because the configuration is not complete, but we want to
1908         // connect anyway. It might be a disconnected network such as a
1909         // Chromecast or a wireless printer, for example.
1910         //
1911         // Because on such a network isProvisioned() will always return false,
1912         // delta will never be LOST_PROVISIONING. So check for loss of
1913         // provisioning here too.
1914         if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
1915             delta = PROV_CHANGE_LOST_PROVISIONING;
1916         }
1917 
1918         // Additionally:
1919         //
1920         // If the previous link properties had a global IPv6 address and an
1921         // IPv6 default route then also consider the loss of that default route
1922         // to be a loss of provisioning. See b/27962810.
1923         if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
1924             // Although link properties have lost IPv6 default route in this case, if IPv4 is still
1925             // working with appropriate routes and DNS servers, we can keep the current connection
1926             // without disconnecting from the network, just disable accept_ra_defrtr sysctl on that
1927             // given network until to the next provisioning.
1928             //
1929             // Disabling IPv6 stack will result in all IPv6 connectivity torn down and all IPv6
1930             // sockets being closed, the non-routable IPv6 DNS servers will be stripped out, so
1931             // applications will be able to reconnect immediately over IPv4. See b/131781810.
1932             //
1933             // Sometimes disabling IPv6 stack can cause other problems(see b/179222860), conversely,
1934             // disabling accept_ra_defrtr can still keep the interface IPv6 capable, but no longer
1935             // learns the default router from incoming RA, partial IPv6 connectivity will remain on
1936             // the interface, through which applications can still communicate locally.
1937             if (newLp.isIpv4Provisioned()) {
1938                 // Restart ipv6 with accept_ra_defrtr set to 0.
1939                 mInterfaceCtrl.disableIPv6();
1940                 startIPv6(0 /* accept_ra_defrtr */);
1941 
1942                 mNetworkQuirkMetrics.setEvent(NetworkQuirkEvent.QE_IPV6_PROVISIONING_ROUTER_LOST);
1943                 mNetworkQuirkMetrics.statsWrite();
1944                 mHasDisabledAcceptRaDefrtrOnProvLoss = true;
1945                 delta = PROV_CHANGE_STILL_PROVISIONED;
1946                 mLog.log("Disabled accept_ra_defrtr sysctl on loss of IPv6 default router");
1947             } else {
1948                 delta = PROV_CHANGE_LOST_PROVISIONING;
1949             }
1950         }
1951 
1952         return delta;
1953     }
1954 
dispatchCallback(int delta, LinkProperties newLp)1955     private void dispatchCallback(int delta, LinkProperties newLp) {
1956         switch (delta) {
1957             case PROV_CHANGE_GAINED_PROVISIONING:
1958                 if (DBG) {
1959                     Log.d(mTag, "onProvisioningSuccess()");
1960                 }
1961                 recordMetric(IpManagerEvent.PROVISIONING_OK);
1962                 mCallback.onProvisioningSuccess(newLp);
1963                 break;
1964 
1965             case PROV_CHANGE_LOST_PROVISIONING:
1966                 if (DBG) {
1967                     Log.d(mTag, "onProvisioningFailure()");
1968                 }
1969                 recordMetric(IpManagerEvent.PROVISIONING_FAIL);
1970                 mCallback.onProvisioningFailure(newLp);
1971                 break;
1972 
1973             default:
1974                 if (DBG) {
1975                     Log.d(mTag, "onLinkPropertiesChange()");
1976                 }
1977                 mCallback.onLinkPropertiesChange(newLp);
1978                 break;
1979         }
1980     }
1981 
1982     // Updates all IpClient-related state concerned with LinkProperties.
1983     // Returns a ProvisioningChange for possibly notifying other interested
1984     // parties that are not fronted by IpClient.
setLinkProperties(LinkProperties newLp)1985     private int setLinkProperties(LinkProperties newLp) {
1986         if (mApfFilter != null) {
1987             mApfFilter.setLinkProperties(newLp);
1988         }
1989         if (mIpReachabilityMonitor != null) {
1990             mIpReachabilityMonitor.updateLinkProperties(newLp);
1991         }
1992 
1993         int delta = compareProvisioning(mLinkProperties, newLp);
1994         mLinkProperties = new LinkProperties(newLp);
1995 
1996         if (delta == PROV_CHANGE_GAINED_PROVISIONING) {
1997             // TODO: Add a proper ProvisionedState and cancel the alarm in
1998             // its enter() method.
1999             mProvisioningTimeoutAlarm.cancel();
2000         }
2001 
2002         return delta;
2003     }
2004 
assembleLinkProperties()2005     private LinkProperties assembleLinkProperties() {
2006         // [1] Create a new LinkProperties object to populate.
2007         LinkProperties newLp = new LinkProperties();
2008         newLp.setInterfaceName(mInterfaceName);
2009 
2010         // [2] Pull in data from netlink:
2011         //         - IPv4 addresses
2012         //         - IPv6 addresses
2013         //         - IPv6 routes
2014         //         - IPv6 DNS servers
2015         //
2016         // N.B.: this is fundamentally race-prone and should be fixed by
2017         // changing IpClientLinkObserver from a hybrid edge/level model to an
2018         // edge-only model, or by giving IpClient its own netlink socket(s)
2019         // so as to track all required information directly.
2020         LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties();
2021         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
2022         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
2023             newLp.addRoute(route);
2024         }
2025         addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
2026         mShim.setNat64Prefix(newLp, mShim.getNat64Prefix(netlinkLinkProperties));
2027 
2028         // Check if any link address update from netlink.
2029         final CompareResult<LinkAddress> results =
2030                 LinkPropertiesUtils.compareAddresses(mLinkProperties, newLp);
2031         // In the case that there are multiple netlink update events about a global IPv6 address
2032         // derived from the delegated prefix, a flag-only change event(e.g. due to the duplicate
2033         // address detection) will cause an identical IP address to be put into both Added and
2034         // Removed list based on the CompareResult implementation. To prevent a prefix from being
2035         // mistakenly removed from the delegate prefix list, it is better to always check the
2036         // removed list before checking the added list(e.g. anyway we can add the removed prefix
2037         // back again).
2038         for (LinkAddress la : results.removed) {
2039             if (isIpv6StableDelegatedAddress(la)) {
2040                 final IpPrefix prefix = new IpPrefix(la.getAddress(), RFC7421_PREFIX_LENGTH);
2041                 mDelegatedPrefixes.remove(prefix);
2042             }
2043             // TODO: remove onIpv6AddressRemoved callback.
2044         }
2045 
2046         for (LinkAddress la : results.added) {
2047             if (isIpv6StableDelegatedAddress(la)) {
2048                 final IpPrefix prefix = new IpPrefix(la.getAddress(), RFC7421_PREFIX_LENGTH);
2049                 mDelegatedPrefixes.add(prefix);
2050             }
2051         }
2052 
2053         // [3] Add in data from DHCPv4, if available.
2054         //
2055         // mDhcpResults is never shared with any other owner so we don't have
2056         // to worry about concurrent modification.
2057         if (mDhcpResults != null) {
2058             final List<RouteInfo> routes =
2059                     mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName);
2060             for (RouteInfo route : routes) {
2061                 newLp.addRoute(route);
2062             }
2063             addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
2064             if (mDhcpResults.dmnsrchList.size() == 0) {
2065                 newLp.setDomains(mDhcpResults.domains);
2066             } else {
2067                 final String domainsString = mDhcpResults.appendDomainsSearchList();
2068                 newLp.setDomains(TextUtils.isEmpty(domainsString) ? null : domainsString);
2069             }
2070 
2071             if (mDhcpResults.mtu != 0) {
2072                 newLp.setMtu(mDhcpResults.mtu);
2073             }
2074 
2075             if (mDhcpResults.serverAddress != null) {
2076                 mShim.setDhcpServerAddress(newLp, mDhcpResults.serverAddress);
2077             }
2078 
2079             final String capportUrl = mDhcpResults.captivePortalApiUrl;
2080             // Uri.parse does no syntax check; do a simple check to eliminate garbage.
2081             // If the URL is still incorrect data fetching will fail later, which is fine.
2082             if (isParseableUrl(capportUrl)) {
2083                 NetworkInformationShimImpl.newInstance()
2084                         .setCaptivePortalApiUrl(newLp, Uri.parse(capportUrl));
2085             }
2086             // TODO: also look at the IPv6 RA (netlink) for captive portal URL
2087         }
2088 
2089         // [4] Add route with delegated prefix according to the global address update.
2090         for (IpPrefix destination : mDelegatedPrefixes) {
2091             // Direct-connected route to delegated prefix. Add RTN_UNREACHABLE to
2092             // this route based on the delegated prefix. To prevent the traffic loop
2093             // between host and upstream delegated router. Because we specify the
2094             // IFA_F_NOPREFIXROUTE when adding the IPv6 address, the kernel does not
2095             // create a delegated prefix route, as a result, the user space won't
2096             // receive any RTM_NEWROUTE message about the delegated prefix, we still
2097             // need to install an unreachable route for the delegated prefix manually
2098             // in LinkProperties to notify the caller this update.
2099             // TODO: support RTN_BLACKHOLE in netd and use that on newer Android
2100             // versions.
2101             final RouteInfo route = new RouteInfo(destination,
2102                     null /* gateway */, mInterfaceName, RTN_UNREACHABLE);
2103             newLp.addRoute(route);
2104         }
2105 
2106         // [5] Add in TCP buffer sizes and HTTP Proxy config, if available.
2107         if (!TextUtils.isEmpty(mTcpBufferSizes)) {
2108             newLp.setTcpBufferSizes(mTcpBufferSizes);
2109         }
2110         if (mHttpProxy != null) {
2111             newLp.setHttpProxy(mHttpProxy);
2112         }
2113 
2114         // [6] Add data from InitialConfiguration
2115         if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
2116             InitialConfiguration config = mConfiguration.mInitialConfig;
2117             // Add InitialConfiguration routes and dns server addresses once all addresses
2118             // specified in the InitialConfiguration have been observed with Netlink.
2119             if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
2120                 for (IpPrefix prefix : config.directlyConnectedRoutes) {
2121                     newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName, RTN_UNICAST));
2122                 }
2123             }
2124             addAllReachableDnsServers(newLp, config.dnsServers);
2125         }
2126         final LinkProperties oldLp = mLinkProperties;
2127         if (DBG) {
2128             Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
2129                     netlinkLinkProperties, newLp, oldLp));
2130         }
2131 
2132         // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
2133         // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
2134         return newLp;
2135     }
2136 
isParseableUrl(String url)2137     private static boolean isParseableUrl(String url) {
2138         // Verify that a URL has a reasonable format that can be parsed as per the URL constructor.
2139         // This does not use Patterns.WEB_URL as that pattern excludes URLs without TLDs, such as on
2140         // localhost.
2141         if (url == null) return false;
2142         try {
2143             new URL(url);
2144             return true;
2145         } catch (MalformedURLException e) {
2146             return false;
2147         }
2148     }
2149 
addAllReachableDnsServers( LinkProperties lp, Iterable<InetAddress> dnses)2150     private static void addAllReachableDnsServers(
2151             LinkProperties lp, Iterable<InetAddress> dnses) {
2152         // TODO: Investigate deleting this reachability check.  We should be
2153         // able to pass everything down to netd and let netd do evaluation
2154         // and RFC6724-style sorting.
2155         for (InetAddress dns : dnses) {
2156             if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
2157                 lp.addDnsServer(dns);
2158             }
2159         }
2160     }
2161 
transmitPacket(final ByteBuffer packet, final SocketAddress sockAddress, final String msg)2162     private void transmitPacket(final ByteBuffer packet, final SocketAddress sockAddress,
2163             final String msg) {
2164         FileDescriptor sock = null;
2165         try {
2166             sock = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0 /* protocol */);
2167             Os.sendto(sock, packet.array(), 0 /* byteOffset */, packet.limit() /* byteCount */,
2168                     0 /* flags */, sockAddress);
2169         } catch (SocketException | ErrnoException e) {
2170             logError(msg, e);
2171         } finally {
2172             SocketUtils.closeSocketQuietly(sock);
2173         }
2174     }
2175 
sendGratuitousNA(final Inet6Address srcIp, final Inet6Address targetIp)2176     private void sendGratuitousNA(final Inet6Address srcIp, final Inet6Address targetIp) {
2177         final int flags = 0; // R=0, S=0, O=0
2178         final Inet6Address dstIp = IPV6_ADDR_ALL_ROUTERS_MULTICAST;
2179         // Ethernet multicast destination address: 33:33:00:00:00:02.
2180         final MacAddress dstMac = NetworkStackUtils.ipv6MulticastToEthernetMulticast(dstIp);
2181         final ByteBuffer packet = NeighborAdvertisement.build(mInterfaceParams.macAddr, dstMac,
2182                 srcIp, dstIp, flags, targetIp);
2183         final SocketAddress sockAddress =
2184                 SocketUtilsShimImpl.newInstance().makePacketSocketAddress(ETH_P_IPV6,
2185                         mInterfaceParams.index, dstMac.toByteArray());
2186 
2187         transmitPacket(packet, sockAddress, "Failed to send Gratuitous Neighbor Advertisement");
2188     }
2189 
sendGratuitousARP(final Inet4Address srcIp)2190     private void sendGratuitousARP(final Inet4Address srcIp) {
2191         final ByteBuffer packet = ArpPacket.buildArpPacket(ETHER_BROADCAST /* dstMac */,
2192                 mInterfaceParams.macAddr.toByteArray() /* srcMac */,
2193                 srcIp.getAddress() /* targetIp */,
2194                 ETHER_BROADCAST /* targetHwAddress */,
2195                 srcIp.getAddress() /* senderIp */, (short) ARP_REPLY);
2196         final SocketAddress sockAddress =
2197                 makePacketSocketAddress(ETH_P_ARP, mInterfaceParams.index);
2198 
2199         transmitPacket(packet, sockAddress, "Failed to send GARP");
2200     }
2201 
sendMulticastNs(final Inet6Address srcIp, final Inet6Address dstIp, final Inet6Address targetIp)2202     private void sendMulticastNs(final Inet6Address srcIp, final Inet6Address dstIp,
2203             final Inet6Address targetIp) {
2204         final MacAddress dstMac = NetworkStackUtils.ipv6MulticastToEthernetMulticast(dstIp);
2205         final ByteBuffer packet = NeighborSolicitation.build(mInterfaceParams.macAddr, dstMac,
2206                 srcIp, dstIp, targetIp);
2207         final SocketAddress sockAddress =
2208                 SocketUtilsShimImpl.newInstance().makePacketSocketAddress(ETH_P_IPV6,
2209                         mInterfaceParams.index, dstMac.toByteArray());
2210 
2211         if (DBG) {
2212             mLog.log("send multicast NS from " + srcIp.getHostAddress() + " to "
2213                     + dstIp.getHostAddress() + " , target IP: " + targetIp.getHostAddress());
2214         }
2215         transmitPacket(packet, sockAddress, "Failed to send multicast Neighbor Solicitation");
2216     }
2217 
2218     @Nullable
getIpv6LinkLocalAddress(final LinkProperties newLp)2219     private static Inet6Address getIpv6LinkLocalAddress(final LinkProperties newLp) {
2220         for (LinkAddress la : newLp.getLinkAddresses()) {
2221             if (!la.isIpv6()) continue;
2222             final Inet6Address ip = (Inet6Address) la.getAddress();
2223             if (ip.isLinkLocalAddress()) return ip;
2224         }
2225         return null;
2226     }
2227 
maybeSendGratuitousNAs(final LinkProperties lp, boolean afterRoaming)2228     private void maybeSendGratuitousNAs(final LinkProperties lp, boolean afterRoaming) {
2229         if (!lp.hasGlobalIpv6Address()) return;
2230 
2231         final Inet6Address srcIp = getIpv6LinkLocalAddress(lp);
2232         if (srcIp == null) return;
2233 
2234         // TODO: add experiment with sending only one gratuitous NA packet instead of one
2235         // packet per address.
2236         for (LinkAddress la : lp.getLinkAddresses()) {
2237             if (!NetworkStackUtils.isIPv6GUA(la)) continue;
2238             final Inet6Address targetIp = (Inet6Address) la.getAddress();
2239             // Already sent gratuitous NA with this target global IPv6 address. But for
2240             // the L2 roaming case, device should always (re)transmit Gratuitous NA for
2241             // each IPv6 global unicast address respectively after roaming.
2242             if (!afterRoaming && mGratuitousNaTargetAddresses.contains(targetIp)) continue;
2243             if (DBG) {
2244                 mLog.log("send Gratuitous NA from " + srcIp.getHostAddress() + " for "
2245                         + targetIp.getHostAddress() + (afterRoaming ? " after roaming" : ""));
2246             }
2247             sendGratuitousNA(srcIp, targetIp);
2248             if (!afterRoaming) {
2249                 mGratuitousNaTargetAddresses.add(targetIp);
2250             }
2251         }
2252     }
2253 
maybeSendGratuitousARP(final LinkProperties lp)2254     private void maybeSendGratuitousARP(final LinkProperties lp) {
2255         for (LinkAddress address : lp.getLinkAddresses()) {
2256             if (address.getAddress() instanceof Inet4Address) {
2257                 final Inet4Address srcIp = (Inet4Address) address.getAddress();
2258                 if (DBG) {
2259                     mLog.log("send GARP for " + srcIp.getHostAddress() + " HW address: "
2260                             + mInterfaceParams.macAddr);
2261                 }
2262                 sendGratuitousARP(srcIp);
2263             }
2264         }
2265     }
2266 
2267     @Nullable
getIPv6DefaultGateway(final LinkProperties lp)2268     private static Inet6Address getIPv6DefaultGateway(final LinkProperties lp) {
2269         for (RouteInfo r : lp.getRoutes()) {
2270             // TODO: call {@link RouteInfo#isIPv6Default} directly after core networking modules
2271             // are consolidated.
2272             if (r.getType() == RTN_UNICAST && r.getDestination().getPrefixLength() == 0
2273                     && r.getDestination().getAddress() instanceof Inet6Address) {
2274                 // Check if it's IPv6 default route, if yes, return the gateway address
2275                 // (i.e. default router's IPv6 link-local address)
2276                 return (Inet6Address) r.getGateway();
2277             }
2278         }
2279         return null;
2280     }
2281 
maybeSendMulticastNSes(final LinkProperties lp)2282     private void maybeSendMulticastNSes(final LinkProperties lp) {
2283         if (!(lp.hasGlobalIpv6Address() && lp.hasIpv6DefaultRoute())) return;
2284 
2285         // Get the default router's IPv6 link-local address.
2286         final Inet6Address targetIp = getIPv6DefaultGateway(lp);
2287         if (targetIp == null) return;
2288         final Inet6Address dstIp = NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast(targetIp);
2289         if (dstIp == null) return;
2290 
2291         for (LinkAddress la : lp.getLinkAddresses()) {
2292             if (!NetworkStackUtils.isIPv6GUA(la)) continue;
2293             final Inet6Address srcIp = (Inet6Address) la.getAddress();
2294             if (mMulticastNsSourceAddresses.contains(srcIp)) continue;
2295             sendMulticastNs(srcIp, dstIp, targetIp);
2296             mMulticastNsSourceAddresses.add(srcIp);
2297         }
2298     }
2299 
hasFlag(@onNull final LinkAddress la, final int flags)2300     private static boolean hasFlag(@NonNull final LinkAddress la, final int flags) {
2301         return (la.getFlags() & flags) == flags;
2302 
2303     }
2304 
2305     // Check whether a global IPv6 stable address is derived from DHCPv6 prefix delegation.
2306     // Address derived from delegated prefix should be:
2307     // - unicast global routable address
2308     // - with prefix length of 64
2309     // - has IFA_F_MANAGETEMPADDR, IFA_F_NOPREFIXROUTE and IFA_F_NODAD flags
isIpv6StableDelegatedAddress(@onNull final LinkAddress la)2310     private static boolean isIpv6StableDelegatedAddress(@NonNull final LinkAddress la) {
2311         return la.isIpv6()
2312                 && !ConnectivityUtils.isIPv6ULA(la.getAddress())
2313                 && (la.getPrefixLength() == RFC7421_PREFIX_LENGTH)
2314                 && (la.getScope() == (byte) RT_SCOPE_UNIVERSE)
2315                 && hasFlag(la, DHCPV6_PREFIX_DELEGATION_ADDRESS_FLAGS);
2316     }
2317 
2318     // Returns false if we have lost provisioning, true otherwise.
handleLinkPropertiesUpdate(boolean sendCallbacks)2319     private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
2320         final LinkProperties newLp = assembleLinkProperties();
2321 
2322         // We need to call mApfFilter.setLinkProperties(newLp) every time there is a LinkAddress
2323         // change because ApfFilter needs to know when addresses change from tentative to
2324         // non-tentative. setLinkProperties() inside IpClient won't be called if the
2325         // LinkProperties.equal() check returns true. The LinkProperties.equal() check does not
2326         // currently take into account the LinkAddress flag change.
2327         // It is OK to call mApfFilter.setLinkProperties() multiple times because if IP
2328         // addresses are not updated, ApfFilter won't generate new program.
2329         if (mApfFilter != null) {
2330             mApfFilter.setLinkProperties(newLp);
2331         }
2332 
2333         if (Objects.equals(newLp, mLinkProperties)) {
2334             return true;
2335         }
2336 
2337         // Set an alarm to wait for IPv6 autoconf via SLAAC to succeed after receiving an RA,
2338         // if we don't see global IPv6 address within timeout then start DHCPv6 Prefix Delegation
2339         // for provisioning. We cannot just check if there is an available on-link IPv6 DNS server
2340         // in the LinkProperties, because on-link IPv6 DNS server won't be updated to LP until
2341         // we have a global IPv6 address via PD. Instead, we have to check if the IPv6 default
2342         // route exists and start DHCPv6 Prefix Delegation process if IPv6 provisioning still
2343         // doesn't complete with success after timeout. This check also handles IPv6-only link
2344         // local mode case, since there will be no IPv6 default route in that mode even with Prefix
2345         // Delegation experiment flag enabled.
2346         if (newLp.hasIpv6DefaultRoute()
2347                 && mIpv6AutoconfTimeoutAlarm == null) {
2348             mIpv6AutoconfTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
2349                     mTag + ".EVENT_IPV6_AUTOCONF_TIMEOUT", EVENT_IPV6_AUTOCONF_TIMEOUT);
2350             final long alarmTime = SystemClock.elapsedRealtime()
2351                     + mDependencies.getDeviceConfigPropertyInt(CONFIG_IPV6_AUTOCONF_TIMEOUT,
2352                             DEFAULT_IPV6_AUTOCONF_TIMEOUT_MS);
2353             mIpv6AutoconfTimeoutAlarm.schedule(alarmTime);
2354         }
2355 
2356         // Check if new assigned IPv6 GUA is available in the LinkProperties now. If so, initiate
2357         // gratuitous multicast unsolicited Neighbor Advertisements as soon as possible to inform
2358         // first-hop routers that the new GUA host is goning to use.
2359         maybeSendGratuitousNAs(newLp, false /* isGratuitousNaAfterRoaming */);
2360 
2361         // Sending multicast NS from each new assigned IPv6 GUAs to the solicited-node multicast
2362         // address based on the default router's IPv6 link-local address should trigger default
2363         // router response with NA, and update the neighbor cache entry immediately, that would
2364         // help speed up the connection to an IPv6-only network.
2365         //
2366         // TODO: stop sending this multicast NS after deployment of RFC9131 in the field, leverage
2367         // the gratuitous NA to update the first-hop router's neighbor cache entry.
2368         maybeSendMulticastNSes(newLp);
2369 
2370         final boolean gainedV6 = !mLinkProperties.isIpv6Provisioned() && newLp.isIpv6Provisioned();
2371         // mDelegatedPrefixes is updated as part of the call to assembleLinkProperties() above.
2372         if (gainedV6 && !mDelegatedPrefixes.isEmpty()) {
2373             mNetworkQuirkMetrics.setEvent(QE_DHCP6_PD_PROVISIONED);
2374             mNetworkQuirkMetrics.statsWrite();
2375         }
2376 
2377         // Either success IPv4 or IPv6 provisioning triggers new LinkProperties update,
2378         // wait for the provisioning completion and record the latency.
2379         mIpProvisioningMetrics.setIPv4ProvisionedLatencyOnFirstTime(newLp.isIpv4Provisioned());
2380         mIpProvisioningMetrics.setIPv6ProvisionedLatencyOnFirstTime(newLp.isIpv6Provisioned());
2381 
2382         final int delta = setLinkProperties(newLp);
2383         // Most of the attributes stored in the memory store are deduced from
2384         // the link properties, therefore when the properties update the memory
2385         // store record should be updated too.
2386         maybeSaveNetworkToIpMemoryStore();
2387         if (sendCallbacks) {
2388             dispatchCallback(delta, newLp);
2389             // We cannot do this along with onProvisioningSuccess callback, because the network
2390             // can become dual-stack after a success IPv6 provisioning, and the multiplier also
2391             // needs to be updated upon the loss of IPv4 and/or IPv6 provisioning. The multiplier
2392             // has been initialized with DTIM_MULTIPLIER_RESET before starting provisioning, it
2393             // gets updated on the first LinkProperties update (which usually happens when the
2394             // IPv6 link-local address appears).
2395             updateMaxDtimMultiplier();
2396         }
2397         return (delta != PROV_CHANGE_LOST_PROVISIONING);
2398     }
2399 
2400     @VisibleForTesting
removeDoubleQuotes(@onNull String ssid)2401     static String removeDoubleQuotes(@NonNull String ssid) {
2402         final int length = ssid.length();
2403         if ((length > 1) && (ssid.charAt(0) == '"') && (ssid.charAt(length - 1) == '"')) {
2404             return ssid.substring(1, length - 1);
2405         }
2406         return ssid;
2407     }
2408 
getVendorSpecificIEs(@onNull ScanResultInfo scanResultInfo)2409     private static List<ByteBuffer> getVendorSpecificIEs(@NonNull ScanResultInfo scanResultInfo) {
2410         ArrayList<ByteBuffer> vendorSpecificPayloadList = new ArrayList<>();
2411         for (InformationElement ie : scanResultInfo.getInformationElements()) {
2412             if (ie.getId() == VENDOR_SPECIFIC_IE_ID) {
2413                 vendorSpecificPayloadList.add(ie.getPayload());
2414             }
2415         }
2416         return vendorSpecificPayloadList;
2417     }
2418 
checkIfOuiAndTypeMatched(@onNull ScanResultInfo scanResultInfo, @NonNull List<byte[]> patternList)2419     private boolean checkIfOuiAndTypeMatched(@NonNull ScanResultInfo scanResultInfo,
2420             @NonNull List<byte[]> patternList) {
2421         final List<ByteBuffer> vendorSpecificPayloadList = getVendorSpecificIEs(scanResultInfo);
2422 
2423         for (ByteBuffer payload : vendorSpecificPayloadList) {
2424             byte[] ouiAndType = new byte[4];
2425             try {
2426                 payload.get(ouiAndType);
2427             } catch (BufferUnderflowException e) {
2428                 Log.e(mTag, "Couldn't parse vendor specific IE, buffer underflow");
2429                 return false;
2430             }
2431             for (byte[] pattern : patternList) {
2432                 if (Arrays.equals(pattern, ouiAndType)) {
2433                     if (DBG) {
2434                         Log.d(mTag, "match pattern: " + HexDump.toHexString(ouiAndType));
2435                     }
2436                     return true;
2437                 }
2438             }
2439         }
2440         return false;
2441     }
2442 
detectUpstreamHotspotFromVendorIe()2443     private boolean detectUpstreamHotspotFromVendorIe() {
2444         final ScanResultInfo scanResultInfo = mConfiguration.mScanResultInfo;
2445         if (scanResultInfo == null) return false;
2446         final String ssid = scanResultInfo.getSsid();
2447 
2448         if (mConfiguration.mDisplayName == null
2449                 || !removeDoubleQuotes(mConfiguration.mDisplayName).equals(ssid)) {
2450             return false;
2451         }
2452         return checkIfOuiAndTypeMatched(scanResultInfo, METERED_IE_PATTERN_LIST);
2453     }
2454 
handleIPv4Success(DhcpResults dhcpResults)2455     private void handleIPv4Success(DhcpResults dhcpResults) {
2456         mDhcpResults = new DhcpResults(dhcpResults);
2457         final LinkProperties newLp = assembleLinkProperties();
2458         final int delta = setLinkProperties(newLp);
2459 
2460         if (mDhcpResults.vendorInfo == null && detectUpstreamHotspotFromVendorIe()) {
2461             mDhcpResults.vendorInfo = DhcpPacket.VENDOR_INFO_ANDROID_METERED;
2462         }
2463 
2464         if (DBG) {
2465             Log.d(mTag, "onNewDhcpResults(" + Objects.toString(mDhcpResults) + ")");
2466             Log.d(mTag, "handleIPv4Success newLp{" + newLp + "}");
2467         }
2468         mCallback.onNewDhcpResults(mDhcpResults);
2469         maybeSaveNetworkToIpMemoryStore();
2470 
2471         dispatchCallback(delta, newLp);
2472     }
2473 
handleIPv4Failure()2474     private void handleIPv4Failure() {
2475         // TODO: Investigate deleting this clearIPv4Address() call.
2476         //
2477         // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
2478         // that could trigger a call to this function. If we missed handling
2479         // that message in StartedState for some reason we would still clear
2480         // any addresses upon entry to StoppedState.
2481         mInterfaceCtrl.clearIPv4Address();
2482         mDhcpResults = null;
2483         if (DBG) {
2484             Log.d(mTag, "onNewDhcpResults(null)");
2485         }
2486         mCallback.onNewDhcpResults(null);
2487 
2488         handleProvisioningFailure(DisconnectCode.DC_PROVISIONING_FAIL);
2489     }
2490 
handleProvisioningFailure(final DisconnectCode code)2491     private void handleProvisioningFailure(final DisconnectCode code) {
2492         final LinkProperties newLp = assembleLinkProperties();
2493         int delta = setLinkProperties(newLp);
2494         // If we've gotten here and we're still not provisioned treat that as
2495         // a total loss of provisioning.
2496         //
2497         // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
2498         // there was no usable IPv6 obtained before a non-zero provisioning
2499         // timeout expired.
2500         //
2501         // Regardless: GAME OVER.
2502         if (delta == PROV_CHANGE_STILL_NOT_PROVISIONED) {
2503             delta = PROV_CHANGE_LOST_PROVISIONING;
2504         }
2505 
2506         dispatchCallback(delta, newLp);
2507         if (delta == PROV_CHANGE_LOST_PROVISIONING) {
2508             transitionToStoppingState(code);
2509         }
2510     }
2511 
doImmediateProvisioningFailure(int failureType)2512     private void doImmediateProvisioningFailure(int failureType) {
2513         logError("onProvisioningFailure(): %s", failureType);
2514         recordMetric(failureType);
2515         mCallback.onProvisioningFailure(mLinkProperties);
2516     }
2517 
2518     @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
startIPv4()2519     private boolean startIPv4() {
2520         // If we have a StaticIpConfiguration attempt to apply it and
2521         // handle the result accordingly.
2522         if (mConfiguration.mStaticIpConfig != null) {
2523             if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {
2524                 handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
2525             } else {
2526                 return false;
2527             }
2528         } else {
2529             if (mDhcpClient != null) {
2530                 Log.wtf(mTag, "DhcpClient should never be non-null in startIPv4()");
2531             }
2532             startDhcpClient();
2533         }
2534 
2535         return true;
2536     }
2537 
shouldDisableDad()2538     private boolean shouldDisableDad() {
2539         return mConfiguration.mUniqueEui64AddressesOnly
2540                 && mConfiguration.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL
2541                 && mConfiguration.mIPv6AddrGenMode
2542                         == ProvisioningConfiguration.IPV6_ADDR_GEN_MODE_EUI64;
2543     }
2544 
startIPv6(int acceptRaDefrtr)2545     private boolean startIPv6(int acceptRaDefrtr) {
2546         setIpv6Sysctl(ACCEPT_RA,
2547                 mConfiguration.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL ? 0 : 2);
2548         setIpv6Sysctl(ACCEPT_RA_DEFRTR, acceptRaDefrtr);
2549         if (shouldDisableDad()) {
2550             final Integer dadTransmits = getIpv6Sysctl(DAD_TRANSMITS);
2551             if (dadTransmits != null) {
2552                 mDadTransmits = dadTransmits;
2553                 setIpv6Sysctl(DAD_TRANSMITS, 0 /* dad_transmits */);
2554             }
2555         }
2556         return mInterfaceCtrl.setIPv6PrivacyExtensions(true)
2557                 && mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode)
2558                 && mInterfaceCtrl.enableIPv6();
2559     }
2560 
startDhcp6PrefixDelegation()2561     private void startDhcp6PrefixDelegation() {
2562         if (mDhcp6Client != null) {
2563             Log.wtf(mTag, "Dhcp6Client should never be non-null in startDhcp6PrefixDelegation");
2564             return;
2565         }
2566         mDhcp6Client = mDependencies.makeDhcp6Client(mContext, IpClient.this, mInterfaceParams,
2567                 mDependencies.getDhcp6ClientDependencies());
2568         mDhcp6Client.sendMessage(Dhcp6Client.CMD_START_DHCP6);
2569     }
2570 
applyInitialConfig(InitialConfiguration config)2571     private boolean applyInitialConfig(InitialConfiguration config) {
2572         // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
2573         for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIpv6)) {
2574             if (!mInterfaceCtrl.addAddress(addr)) return false;
2575         }
2576 
2577         return true;
2578     }
2579 
2580     // In order to avoid overflowing the database (the maximum is 10MB) in case of a NUD failure
2581     // happens frequently (e.g, every 30s in a broken network), we stop writing the NUD failure
2582     // event to database if the total event count in past 6h, plus the number of events written
2583     // since IpClient was started, has exceeded the daily threshold.
2584     //
2585     // The code also counts the number of events written since this IpClient was last started.
2586     // Otherwise, if NUD failures are already being ignored due to a (daily or weekly) threshold
2587     // being hit by events that happened more than 6 hours ago, but there have been no failures in
2588     // the last 6 hours, the code would never stop logging failures (filling up the memory store)
2589     // until IpClient is restarted and queries the memory store again.
2590     //
2591     // The 6-hour count is still useful, even though the code looks at the number of NUD failures
2592     // since IpClient was last started, because it ensures that even if the network disconnects and
2593     // reconnects frequently for any other reason, the code will never store more than 10 NUD
2594     // failures every 6 hours.
shouldStopWritingNudFailureEventToDatabase()2595     private boolean shouldStopWritingNudFailureEventToDatabase() {
2596         // NUD failure query has not completed yet.
2597         if (mNudFailureEventCounts == null) return true;
2598         return mNudFailureEventCounts[2] + mNudFailuresStoredSinceStart
2599                 >= mNudFailureCountDailyThreshold;
2600     }
2601 
maybeStoreNudFailureToDatabase(final NudEventType type)2602     private void maybeStoreNudFailureToDatabase(final NudEventType type) {
2603         if (!mIgnoreNudFailureEnabled) return;
2604         final int event = IpReachabilityMonitor.nudEventTypeToNetworkEvent(type);
2605         // So far only NUD failure events due to organic kernel check are stored, which can be
2606         // expanded to other causes later if necessary.
2607         if (event != NETWORK_EVENT_NUD_FAILURE_ORGANIC) return;
2608         if (shouldStopWritingNudFailureEventToDatabase()) return;
2609 
2610         final long now = System.currentTimeMillis();
2611         final long expiry = now + ONE_WEEK_IN_MS;
2612         mIpMemoryStore.storeNetworkEvent(mCluster, now, expiry, event,
2613                 status -> {
2614                     if (!status.isSuccess()) {
2615                         Log.e(TAG, "Failed to store NUD failure event");
2616                     }
2617                 });
2618         mNudFailuresStoredSinceStart++;
2619         if (DBG) {
2620             Log.d(TAG, "store network event " + type
2621                     + " at " + now
2622                     + " expire at " + expiry
2623                     + " with cluster " + mCluster);
2624         }
2625     }
2626 
startIpReachabilityMonitor()2627     private boolean startIpReachabilityMonitor() {
2628         try {
2629             mIpReachabilityMonitor = mDependencies.getIpReachabilityMonitor(
2630                     mContext,
2631                     mInterfaceParams,
2632                     getHandler(),
2633                     mLog,
2634                     new IpReachabilityMonitor.Callback() {
2635                         @Override
2636                         public void notifyLost(String logMsg, NudEventType type) {
2637                             maybeStoreNudFailureToDatabase(type);
2638                             if (mIgnoreNudFailure) {
2639                                 Counter.logIncrement("core_networking.value_nud_failure_ignored");
2640                                 return;
2641                             }
2642                             final int version = mCallback.getInterfaceVersion();
2643                             if (version >= VERSION_ADDED_REACHABILITY_FAILURE) {
2644                                 final int reason = nudEventTypeToInt(type);
2645                                 if (reason == INVALID_REACHABILITY_LOSS_TYPE) return;
2646                                 final ReachabilityLossInfoParcelable lossInfo =
2647                                         new ReachabilityLossInfoParcelable(logMsg, reason);
2648                                 mCallback.onReachabilityFailure(lossInfo);
2649                             } else {
2650                                 mCallback.onReachabilityLost(logMsg);
2651                             }
2652                         }
2653                     },
2654                     mConfiguration.mUsingMultinetworkPolicyTracker,
2655                     mDependencies.getIpReachabilityMonitorDeps(mContext, mInterfaceParams.name),
2656                     mNetd);
2657         } catch (IllegalArgumentException iae) {
2658             // Failed to start IpReachabilityMonitor. Log it and call
2659             // onProvisioningFailure() immediately.
2660             //
2661             // See http://b/31038971.
2662             logError("IpReachabilityMonitor failure: %s", iae);
2663             mIpReachabilityMonitor = null;
2664         }
2665 
2666         return (mIpReachabilityMonitor != null);
2667     }
2668 
stopAllIP()2669     private void stopAllIP() {
2670         // We don't need to worry about routes, just addresses, because:
2671         //     - disableIpv6() will clear autoconf IPv6 routes as well, and
2672         //     - we don't get IPv4 routes from netlink
2673         // so we neither react to nor need to wait for changes in either.
2674         mInterfaceCtrl.disableIPv6();
2675         mInterfaceCtrl.clearAllAddresses();
2676 
2677         // Reset IPv6 sysctls to their initial state. It's better to restore
2678         // sysctls after IPv6 stack is disabled, which prevents a potential
2679         // race where receiving an RA between restoring accept_ra and disabling
2680         // IPv6 stack, although it's unlikely.
2681         setIpv6Sysctl(ACCEPT_RA, 2);
2682         setIpv6Sysctl(ACCEPT_RA_DEFRTR, 1);
2683         maybeRestoreDadTransmits();
2684         if (mIsAcceptRaMinLftEnabled
2685                 && mDependencies.hasIpv6Sysctl(mInterfaceName, ACCEPT_RA_MIN_LFT)) {
2686             setIpv6Sysctl(ACCEPT_RA_MIN_LFT, 0 /* sysctl default */);
2687         }
2688     }
2689 
maybeSaveNetworkToIpMemoryStore()2690     private void maybeSaveNetworkToIpMemoryStore() {
2691         // TODO : implement this
2692     }
2693 
maybeRestoreInterfaceMtu()2694     private void maybeRestoreInterfaceMtu() {
2695         InterfaceParams params = mDependencies.getInterfaceParams(mInterfaceName);
2696         if (params == null) {
2697             Log.w(mTag, "interface: " + mInterfaceName + " is gone");
2698             return;
2699         }
2700 
2701         // Check whether "mInterfaceParams" is null or not to prevent the potential NPE
2702         // introduced if the interface was initially not found, but came back before this
2703         // method was called. See b/162808916 for more details. TODO: query the new interface
2704         // parameters by the interface index instead and check that the index has not changed.
2705         if (mInterfaceParams == null || params.index != mInterfaceParams.index) {
2706             Log.w(mTag, "interface: " + mInterfaceName + " has a different index: " + params.index);
2707             return;
2708         }
2709 
2710         if (params.defaultMtu == mInterfaceParams.defaultMtu) return;
2711 
2712         if (mReplaceNetdWithNetlinkEnabled) {
2713             if (!NetlinkUtils.setInterfaceMtu(mInterfaceName, mInterfaceParams.defaultMtu)) {
2714                 logError("Couldn't reset MTU on " + mInterfaceName + " from "
2715                         + params.defaultMtu + " to " + mInterfaceParams.defaultMtu);
2716             }
2717         } else {
2718             try {
2719                 mNetd.interfaceSetMtu(mInterfaceName, mInterfaceParams.defaultMtu);
2720             } catch (RemoteException | ServiceSpecificException e) {
2721                 logError("Couldn't reset MTU on " + mInterfaceName + " from "
2722                         + params.defaultMtu + " to " + mInterfaceParams.defaultMtu, e);
2723             }
2724         }
2725     }
2726 
maybeRestoreDadTransmits()2727     private void maybeRestoreDadTransmits() {
2728         if (mDadTransmits == null) return;
2729 
2730         setIpv6Sysctl(DAD_TRANSMITS, mDadTransmits);
2731         mDadTransmits = null;
2732     }
2733 
handleUpdateL2Information(@onNull Layer2InformationParcelable info)2734     private void handleUpdateL2Information(@NonNull Layer2InformationParcelable info) {
2735         mL2Key = info.l2Key;
2736         mCluster = info.cluster;
2737 
2738         // Sometimes the wifi code passes in a null BSSID. Don't use Log.wtf in R because
2739         // it's a known bug that will not be fixed in R.
2740         if (info.bssid == null || mCurrentBssid == null) {
2741             final String msg = "bssid in the parcelable: " + info.bssid + " or "
2742                     + "current tracked bssid: " + mCurrentBssid + " is null";
2743             if (ShimUtils.isAtLeastS()) {
2744                 Log.wtf(mTag, msg);
2745             } else {
2746                 Log.w(mTag, msg);
2747             }
2748             return;
2749         }
2750 
2751         // If the BSSID has not changed, there is nothing to do.
2752         if (info.bssid.equals(mCurrentBssid)) return;
2753 
2754         // Before trigger probing to the critical neighbors, send Gratuitous ARP
2755         // and Neighbor Advertisment in advance to propgate host's IPv4/v6 addresses.
2756         maybeSendGratuitousARP(mLinkProperties);
2757         maybeSendGratuitousNAs(mLinkProperties, true /* isGratuitousNaAfterRoaming */);
2758 
2759         // Check whether attempting to refresh previous IP lease on specific networks or need to
2760         // probe the critical neighbors proactively on L2 roaming happened. The NUD probe on the
2761         // specific networks is cancelled because otherwise the probe will happen in parallel with
2762         // DHCP refresh, it will be difficult to understand what happened exactly and error-prone
2763         // to introduce race condition.
2764         final String ssid = removeDoubleQuotes(mConfiguration.mDisplayName);
2765         if (DHCP_ROAMING_SSID_SET.contains(ssid) && mDhcpClient != null) {
2766             if (DBG) {
2767                 Log.d(mTag, "L2 roaming happened from " + mCurrentBssid
2768                         + " to " + info.bssid
2769                         + " , SSID: " + ssid
2770                         + " , starting refresh leased IP address");
2771             }
2772             mDhcpClient.sendMessage(DhcpClient.CMD_REFRESH_LINKADDRESS);
2773         } else if (mIpReachabilityMonitor != null) {
2774             mIpReachabilityMonitor.probeAll(true /* dueToRoam */);
2775         }
2776         mCurrentBssid = info.bssid;
2777     }
2778 
2779     @Nullable
maybeCreateApfFilter(final ApfCapabilities apfCaps)2780     private ApfFilter maybeCreateApfFilter(final ApfCapabilities apfCaps) {
2781         ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
2782         if (apfCaps == null || !mEnableApf) {
2783             return null;
2784         }
2785         // For now only support generating programs for Ethernet frames. If this restriction is
2786         // lifted the program generator will need its offsets adjusted.
2787         if (apfCaps.apfPacketFormat != ARPHRD_ETHER) return null;
2788         // For devices declare APFv3+ support but have less than 1024 bytes of RAM available for
2789         // the APF, set the APF version to v2. The counter region will use a few hundred bytes of
2790         // RAM. If the RAM size is too small, we should reserve that region for program use.
2791         if (apfCaps.apfVersionSupported >= 3 && apfCaps.maximumApfProgramSize < 1024) {
2792             apfConfig.apfVersionSupported = 2;
2793         } else if (SdkLevel.isAtLeastS()) {
2794             apfConfig.apfVersionSupported = apfCaps.apfVersionSupported;
2795         } else {
2796             // In Android R, ApfCapabilities#hasDataAccess() can be modified by OEMs. The
2797             // ApfFilter logic uses ApfCapabilities.apfVersionSupported to determine whether
2798             // data region access is supported. Therefore, we need to recalculate
2799             // ApfCapabilities.apfVersionSupported based on the return value of
2800             // ApfCapabilities#hasDataAccess().
2801             apfConfig.apfVersionSupported = apfCaps.hasDataAccess() ? 3 : 2;
2802         }
2803         apfConfig.apfRamSize = apfCaps.maximumApfProgramSize;
2804         if (!SdkLevel.isAtLeastV() && apfConfig.apfVersionSupported <= 4) {
2805             apfConfig.installableProgramSizeClamp = 1024;
2806         }
2807         apfConfig.multicastFilter = mMulticastFiltering;
2808         // Get the Configuration for ApfFilter from Context
2809         // Resource settings were moved from ApfCapabilities APIs to NetworkStack resources in S
2810         if (ShimUtils.isAtLeastS()) {
2811             final Resources res = mContext.getResources();
2812             apfConfig.ieee802_3Filter = res.getBoolean(R.bool.config_apfDrop802_3Frames);
2813             apfConfig.ethTypeBlackList = res.getIntArray(R.array.config_apfEthTypeDenyList);
2814         } else {
2815             apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
2816             apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
2817         }
2818 
2819         // The RDNSS option is not processed by the kernel, so lifetime filtering
2820         // can occur independent of kernel support for accept_ra_min_lft.
2821         apfConfig.minRdnssLifetimeSec = mAcceptRaMinLft;
2822         // Check the feature flag first before reading IPv6 sysctl, which can prevent from
2823         // triggering a potential kernel bug about the sysctl.
2824         // TODO: add unit test to check if the setIpv6Sysctl() is called or not.
2825         if (mIsAcceptRaMinLftEnabled
2826                 && mDependencies.hasIpv6Sysctl(mInterfaceName, ACCEPT_RA_MIN_LFT)) {
2827             setIpv6Sysctl(ACCEPT_RA_MIN_LFT, mAcceptRaMinLft);
2828             final Integer acceptRaMinLft = getIpv6Sysctl(ACCEPT_RA_MIN_LFT);
2829             apfConfig.acceptRaMinLft = acceptRaMinLft == null ? 0 : acceptRaMinLft;
2830         } else {
2831             apfConfig.acceptRaMinLft = 0;
2832         }
2833         apfConfig.handleArpOffload = mApfHandleArpOffload;
2834         apfConfig.handleNdOffload = mApfHandleNdOffload;
2835         apfConfig.handleMdnsOffload = mApfHandleMdnsOffload;
2836         apfConfig.handleIgmpOffload = mApfHandleIgmpOffload;
2837         // TODO: Turn on MLD offload on devices with 2048 ~ 2999 bytes of APF RAM.
2838         apfConfig.handleMldOffload = mApfHandleMldOffload && apfConfig.apfRamSize >= 3000;
2839         apfConfig.handleIpv4PingOffload = mApfHandleIpv4PingOffload;
2840         // TODO: Turn on Ping6 offload on devices with 2048 ~ 2999 bytes of APF RAM.
2841         apfConfig.handleIpv6PingOffload = mApfHandleIpv6PingOffload && apfConfig.apfRamSize >= 3000;
2842         apfConfig.minMetricsSessionDurationMs = mApfCounterPollingIntervalMs;
2843         apfConfig.hasClatInterface = mHasSeenClatInterface;
2844         return mDependencies.maybeCreateApfFilter(getHandler(), mContext, apfConfig,
2845                 mInterfaceParams, mIpClientApfController, mNetworkQuirkMetrics);
2846     }
2847 
handleUpdateApfCapabilities(@onNull final ApfCapabilities apfCapabilities)2848     private boolean handleUpdateApfCapabilities(@NonNull final ApfCapabilities apfCapabilities) {
2849         // For the use case where the wifi interface switches from secondary to primary, the
2850         // secondary interface does not support APF by default see the overlay config about
2851         // {@link config_wifiEnableApfOnNonPrimarySta}. so we should see empty ApfCapabilities
2852         // in {@link ProvisioningConfiguration} when wifi starts provisioning on the secondary
2853         // interface. For other cases, we should not accept the updateApfCapabilities call.
2854         if (mCurrentApfCapabilities != null || apfCapabilities == null) {
2855             Log.wtf(mTag, "current ApfCapabilities " + mCurrentApfCapabilities
2856                     + " is not null or new ApfCapabilities " + apfCapabilities + " is null");
2857             return false;
2858         }
2859         if (mApfFilter != null) {
2860             mApfFilter.shutdown();
2861         }
2862         mCurrentApfCapabilities = apfCapabilities;
2863         return apfCapabilities != null;
2864     }
2865 
handleProvisioningConfiguration(@onNull final ProvisioningConfiguration config)2866     private void handleProvisioningConfiguration(@NonNull final ProvisioningConfiguration config) {
2867         mCurrentBssid = getInitialBssid(config.mLayer2Info, config.mScanResultInfo,
2868                 ShimUtils.isAtLeastS());
2869         mCurrentApfCapabilities = config.mApfCapabilities;
2870         mCreatorUid = config.mCreatorUid;
2871         if (config.mLayer2Info != null) {
2872             mL2Key = config.mLayer2Info.mL2Key;
2873             mCluster = config.mLayer2Info.mCluster;
2874         }
2875     }
2876 
2877     class StoppedState extends State {
2878         @Override
enter()2879         public void enter() {
2880             stopAllIP();
2881             mHasDisabledAcceptRaDefrtrOnProvLoss = false;
2882             mGratuitousNaTargetAddresses.clear();
2883             mMulticastNsSourceAddresses.clear();
2884             mDelegatedPrefixes.clear();
2885             mNudFailureEventCounts = null;
2886             mNudFailuresStoredSinceStart = 0;
2887 
2888             resetLinkProperties();
2889             if (mStartTimeMillis > 0) {
2890                 // Completed a life-cycle; send a final empty LinkProperties
2891                 // (cleared in resetLinkProperties() above) and record an event.
2892                 mCallback.onLinkPropertiesChange(mLinkProperties);
2893                 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
2894                 mStartTimeMillis = 0;
2895             }
2896         }
2897 
2898         @Override
processMessage(Message msg)2899         public boolean processMessage(Message msg) {
2900             switch (msg.what) {
2901                 case CMD_TERMINATE_AFTER_STOP:
2902                     stopStateMachineUpdaters();
2903                     quit();
2904                     break;
2905 
2906                 case CMD_STOP:
2907                     break;
2908 
2909                 case CMD_START:
2910                     mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
2911                     handleProvisioningConfiguration(mConfiguration);
2912                     transitionTo(mIgnoreNudFailureEnabled
2913                             ? mNudFailureQueryState
2914                             : mClearingIpAddressesState);
2915                     break;
2916 
2917                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
2918                     handleLinkPropertiesUpdate(NO_CALLBACKS);
2919                     break;
2920 
2921                 case CMD_UPDATE_TCP_BUFFER_SIZES:
2922                     mTcpBufferSizes = (String) msg.obj;
2923                     handleLinkPropertiesUpdate(NO_CALLBACKS);
2924                     break;
2925 
2926                 case CMD_UPDATE_HTTP_PROXY:
2927                     mHttpProxy = (ProxyInfo) msg.obj;
2928                     handleLinkPropertiesUpdate(NO_CALLBACKS);
2929                     break;
2930 
2931                 case CMD_SET_MULTICAST_FILTER:
2932                     mMulticastFiltering = (boolean) msg.obj;
2933                     break;
2934 
2935                 case DhcpClient.CMD_ON_QUIT:
2936                 case Dhcp6Client.CMD_ON_QUIT:
2937                     // Everything is already stopped.
2938                     logError("Unexpected CMD_ON_QUIT (already stopped).");
2939                     break;
2940 
2941                 default:
2942                     return NOT_HANDLED;
2943             }
2944 
2945             mMsgStateLogger.handled(this, getCurrentState());
2946             return HANDLED;
2947         }
2948     }
2949 
2950     class StoppingState extends State {
2951         @Override
enter()2952         public void enter() {
2953             if (mDhcpClient == null && mDhcp6Client == null) {
2954                 // There's no DHCPv4 as well as DHCPv6 for which to wait; proceed to stopped
2955                 deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
2956             } else {
2957                 if (mDhcpClient != null) {
2958                     mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
2959                     mDhcpClient.doQuit();
2960                 }
2961                 if (mDhcp6Client != null) {
2962                     mDhcp6Client.sendMessage(Dhcp6Client.CMD_STOP_DHCP6);
2963                     mDhcp6Client.doQuit();
2964                 }
2965             }
2966 
2967             // Restore the interface MTU to initial value if it has changed.
2968             maybeRestoreInterfaceMtu();
2969             // Reset DTIM multiplier to default value if changed.
2970             if (mMaxDtimMultiplier != DTIM_MULTIPLIER_RESET) {
2971                 mCallback.setMaxDtimMultiplier(DTIM_MULTIPLIER_RESET);
2972                 mMaxDtimMultiplier = DTIM_MULTIPLIER_RESET;
2973                 mIPv6ProvisioningDtimGracePeriodMillis = 0;
2974             }
2975         }
2976 
2977         @Override
processMessage(Message msg)2978         public boolean processMessage(Message msg) {
2979             switch (msg.what) {
2980                 case CMD_JUMP_STOPPING_TO_STOPPED:
2981                     transitionTo(mStoppedState);
2982                     break;
2983 
2984                 case CMD_STOP:
2985                     break;
2986 
2987                 case DhcpClient.CMD_CLEAR_LINKADDRESS:
2988                     mInterfaceCtrl.clearIPv4Address();
2989                     break;
2990 
2991                 case DhcpClient.CMD_ON_QUIT:
2992                     mDhcpClient = null;
2993                     // DhcpClient always starts no matter of target network type, however, we have
2994                     // to make sure both of DHCPv4 and DHCPv6 client have quit from state machine
2995                     // before transition to StoppedState, otherwise, we may miss CMD_ON_QUIT cmd
2996                     // that arrives later and transit to StoppedState before that.
2997                     if (mDhcp6Client == null) {
2998                         transitionTo(mStoppedState);
2999                     }
3000                     break;
3001 
3002                 case Dhcp6Client.CMD_ON_QUIT:
3003                     mDhcp6Client = null;
3004                     if (mDhcpClient == null) {
3005                         transitionTo(mStoppedState);
3006                     }
3007                     break;
3008 
3009                 default:
3010                     deferMessage(msg);
3011             }
3012 
3013             mMsgStateLogger.handled(this, getCurrentState());
3014             return HANDLED;
3015         }
3016     }
3017 
isUsingPreconnection()3018     private boolean isUsingPreconnection() {
3019         return mConfiguration.mEnablePreconnection && mConfiguration.mStaticIpConfig == null;
3020     }
3021 
3022     /**
3023      * Check if the customized DHCP client options passed from Wi-Fi are allowed to be put
3024      * in PRL or in the DHCP packet.
3025      */
maybeFilterCustomizedDhcpOptions()3026     private List<DhcpOption> maybeFilterCustomizedDhcpOptions() {
3027         final List<DhcpOption> options = new ArrayList<DhcpOption>();
3028         if (mConfiguration.mDhcpOptions == null
3029                 || mConfiguration.mScanResultInfo == null) return options; // empty DhcpOption list
3030 
3031         for (DhcpOption option : mConfiguration.mDhcpOptions) {
3032             final List<byte[]> patternList = DHCP_OPTIONS_ALLOWED.get(option.type);
3033             // requested option won't be added if no vendor-specific IE oui/type allows this option.
3034             if (patternList == null) continue;
3035             if (checkIfOuiAndTypeMatched(mConfiguration.mScanResultInfo, patternList)) {
3036                 options.add(option);
3037             }
3038         }
3039         Collections.sort(options, (o1, o2) ->
3040                 Integer.compare(Byte.toUnsignedInt(o1.type), Byte.toUnsignedInt(o2.type)));
3041         return options;
3042     }
3043 
startDhcpClient()3044     private void startDhcpClient() {
3045         // Start DHCPv4.
3046         mDhcpClient = mDependencies.makeDhcpClient(mContext, IpClient.this, mInterfaceParams,
3047                 mDependencies.getDhcpClientDependencies(mIpMemoryStore, mIpProvisioningMetrics));
3048 
3049         // Check if the vendor-specific IE oui/type matches and filters the customized DHCP options.
3050         final List<DhcpOption> options = maybeFilterCustomizedDhcpOptions();
3051 
3052         // If preconnection is enabled, there is no need to ask Wi-Fi to disable powersaving
3053         // during DHCP, because the DHCP handshake will happen during association. In order to
3054         // ensure that future renews still do the DHCP action (if configured),
3055         // registerForPreDhcpNotification is called later when processing the CMD_*_PRECONNECTION
3056         // messages.
3057         if (!isUsingPreconnection()) mDhcpClient.registerForPreDhcpNotification();
3058         boolean isManagedWifiProfile = false;
3059         if (mDependencies.getSendDomainSearchListOption(mContext)
3060                 && (mCreatorUid > 0) && (isDeviceOwnerNetwork(mCreatorUid)
3061                 || isProfileOwner(mCreatorUid))) {
3062             isManagedWifiProfile = true;
3063         }
3064         mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP, new DhcpClient.Configuration(mL2Key,
3065                 isUsingPreconnection(), options, isManagedWifiProfile,
3066                 mConfiguration.mHostnameSetting, mPopulateLinkAddressLifetime));
3067     }
3068 
hasPermission(String permissionName)3069     private boolean hasPermission(String permissionName) {
3070         return (mContext.checkCallingOrSelfPermission(permissionName)
3071                 == PackageManager.PERMISSION_GRANTED);
3072     }
3073 
isDeviceOwnerNetwork(int creatorUid)3074     private boolean isDeviceOwnerNetwork(int creatorUid) {
3075         if (mDevicePolicyManager == null) return false;
3076         if (!hasPermission(android.Manifest.permission.MANAGE_USERS)) return false;
3077         final ComponentName devicecmpName = mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();
3078         if (devicecmpName == null) return false;
3079         final String deviceOwnerPackageName = devicecmpName.getPackageName();
3080         if (deviceOwnerPackageName == null) return false;
3081 
3082         final String[] packages = mContext.getPackageManager().getPackagesForUid(creatorUid);
3083 
3084         for (String pkg : packages) {
3085             if (pkg.equals(deviceOwnerPackageName)) {
3086                 return true;
3087             }
3088         }
3089         return false;
3090     }
3091 
3092     @Nullable
createPackageContextAsUser(int uid)3093     private Context createPackageContextAsUser(int uid) {
3094         Context userContext = null;
3095         try {
3096             userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
3097                     UserHandle.getUserHandleForUid(uid));
3098         } catch (PackageManager.NameNotFoundException e) {
3099             Log.e(TAG, "Unknown package name");
3100             return null;
3101         }
3102         return userContext;
3103     }
3104 
3105     /**
3106      * Returns the DevicePolicyManager from context
3107      */
retrieveDevicePolicyManagerFromContext(Context context)3108     private DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) {
3109         DevicePolicyManager devicePolicyManager =
3110                 context.getSystemService(DevicePolicyManager.class);
3111         if (devicePolicyManager == null
3112                 && context.getPackageManager().hasSystemFeature(
3113                 PackageManager.FEATURE_DEVICE_ADMIN)) {
3114             Log.wtf(TAG, "Error retrieving DPM service");
3115         }
3116         return devicePolicyManager;
3117     }
3118 
retrieveDevicePolicyManagerFromUserContext(int uid)3119     private DevicePolicyManager retrieveDevicePolicyManagerFromUserContext(int uid) {
3120         Context userContext = createPackageContextAsUser(uid);
3121         if (userContext == null) return null;
3122         return retrieveDevicePolicyManagerFromContext(userContext);
3123     }
3124 
3125     /**
3126      * Returns {@code true} if the calling {@code uid} is the profile owner
3127      *
3128      */
3129 
isProfileOwner(int uid)3130     private boolean isProfileOwner(int uid) {
3131         DevicePolicyManager devicePolicyManager = retrieveDevicePolicyManagerFromUserContext(uid);
3132         if (devicePolicyManager == null) return false;
3133         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
3134         if (packages == null) {
3135             Log.w(TAG, "isProfileOwner: could not find packages for uid="
3136                     + uid);
3137             return false;
3138         }
3139         for (String packageName : packages) {
3140             if (devicePolicyManager.isProfileOwnerApp(packageName)) {
3141                 return true;
3142             }
3143         }
3144         return false;
3145     }
3146 
3147     class ClearingIpAddressesState extends State {
3148         @Override
enter()3149         public void enter() {
3150             // Ensure that interface parameters are fetched on the handler thread so they are
3151             // properly ordered with other events, such as restoring the interface MTU on teardown.
3152             mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
3153             if (mInterfaceParams == null) {
3154                 logError("Failed to find InterfaceParams for " + mInterfaceName);
3155                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
3156                 deferMessage(obtainMessage(CMD_STOP,
3157                         DisconnectCode.DC_INTERFACE_NOT_FOUND.getNumber()));
3158                 return;
3159             }
3160 
3161             mLinkObserver.setInterfaceParams(mInterfaceParams);
3162 
3163             if (readyToProceed()) {
3164                 deferMessage(obtainMessage(CMD_ADDRESSES_CLEARED));
3165             } else {
3166                 // Clear all IPv4 and IPv6 before proceeding to RunningState.
3167                 // Clean up any leftover state from an abnormal exit from
3168                 // tethering or during an IpClient restart.
3169                 stopAllIP();
3170             }
3171 
3172             mCallback.setNeighborDiscoveryOffload(true);
3173         }
3174 
3175         @Override
processMessage(Message msg)3176         public boolean processMessage(Message msg) {
3177             switch (msg.what) {
3178                 case CMD_ADDRESSES_CLEARED:
3179                     transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState);
3180                     break;
3181 
3182                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
3183                     handleLinkPropertiesUpdate(NO_CALLBACKS);
3184                     if (readyToProceed()) {
3185                         transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState);
3186                     }
3187                     break;
3188 
3189                 case CMD_STOP:
3190                 case EVENT_PROVISIONING_TIMEOUT:
3191                     // Fall through to StartedState.
3192                     return NOT_HANDLED;
3193 
3194                 default:
3195                     // It's safe to process messages out of order because the
3196                     // only message that can both
3197                     //     a) be received at this time and
3198                     //     b) affect provisioning state
3199                     // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
3200                     deferMessage(msg);
3201             }
3202             return HANDLED;
3203         }
3204 
readyToProceed()3205         private boolean readyToProceed() {
3206             return !mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address();
3207         }
3208     }
3209 
3210     class PreconnectingState extends State {
3211         @Override
enter()3212         public void enter() {
3213             startDhcpClient();
3214         }
3215 
3216         @Override
processMessage(Message msg)3217         public boolean processMessage(Message msg) {
3218             switch (msg.what) {
3219                 case CMD_COMPLETE_PRECONNECTION:
3220                     boolean success = (msg.arg1 == 1);
3221                     mDhcpClient.registerForPreDhcpNotification();
3222                     if (!success) {
3223                         mDhcpClient.sendMessage(DhcpClient.CMD_ABORT_PRECONNECTION);
3224                     }
3225                     // The link is ready for use. Advance to running state, start IPv6, etc.
3226                     transitionTo(mRunningState);
3227                     break;
3228 
3229                 case DhcpClient.CMD_START_PRECONNECTION:
3230                     final Layer2PacketParcelable l2Packet = (Layer2PacketParcelable) msg.obj;
3231                     mCallback.onPreconnectionStart(Collections.singletonList(l2Packet));
3232                     break;
3233 
3234                 case CMD_STOP:
3235                 case EVENT_PROVISIONING_TIMEOUT:
3236                     // Fall through to StartedState.
3237                     return NOT_HANDLED;
3238 
3239                 default:
3240                     deferMessage(msg);
3241             }
3242             return HANDLED;
3243         }
3244     }
3245 
3246     class StartedState extends State {
3247         @Override
enter()3248         public void enter() {
3249             mIpProvisioningMetrics.reset();
3250             mStartTimeMillis = SystemClock.elapsedRealtime();
3251 
3252             if (mConfiguration.mProvisioningTimeoutMs > 0) {
3253                 final long alarmTime = SystemClock.elapsedRealtime()
3254                         + mConfiguration.mProvisioningTimeoutMs;
3255                 mProvisioningTimeoutAlarm.schedule(alarmTime);
3256             }
3257 
3258             // There is no need to temporarlily lower the DTIM multiplier in IPv6 link-local
3259             // only mode or when IPv6 is disabled.
3260             if (mConfiguration.mIPv6ProvisioningMode == PROV_IPV6_SLAAC) {
3261                 // Send a delay message to wait for IP provisioning to complete eventually and
3262                 // set the specific DTIM multiplier by checking the target network type.
3263                 final int delay = mDependencies.getDeviceConfigPropertyInt(
3264                         CONFIG_INITIAL_PROVISIONING_DTIM_DELAY_MS,
3265                         DEFAULT_INITIAL_PROVISIONING_DTIM_DELAY_MS);
3266                 mIPv6ProvisioningDtimGracePeriodMillis = mStartTimeMillis + delay;
3267                 sendMessageDelayed(CMD_SET_DTIM_MULTIPLIER_AFTER_DELAY, delay);
3268             }
3269         }
3270 
3271         @Override
exit()3272         public void exit() {
3273             mProvisioningTimeoutAlarm.cancel();
3274             mCurrentApfCapabilities = null;
3275 
3276             // Record metrics information once this provisioning has completed due to certain
3277             // reason (normal termination, provisioning timeout, lost provisioning and etc).
3278             mIpProvisioningMetrics.statsWrite();
3279         }
3280 
3281         @Override
processMessage(Message msg)3282         public boolean processMessage(Message msg) {
3283             switch (msg.what) {
3284                 case CMD_STOP:
3285                     transitionToStoppingState(DisconnectCode.forNumber(msg.arg1));
3286                     break;
3287 
3288                 case CMD_UPDATE_L2INFORMATION:
3289                     handleUpdateL2Information((Layer2InformationParcelable) msg.obj);
3290                     break;
3291 
3292                 // Only update the current ApfCapabilities but do not create and start APF
3293                 // filter until transition to RunningState, actually we should always do that
3294                 // in RunningState.
3295                 case CMD_UPDATE_APF_CAPABILITIES:
3296                     handleUpdateApfCapabilities((ApfCapabilities) msg.obj);
3297                     break;
3298 
3299                 case EVENT_PROVISIONING_TIMEOUT:
3300                     handleProvisioningFailure(DisconnectCode.DC_PROVISIONING_TIMEOUT);
3301                     break;
3302 
3303                 default:
3304                     return NOT_HANDLED;
3305             }
3306 
3307             mMsgStateLogger.handled(this, getCurrentState());
3308             return HANDLED;
3309         }
3310     }
3311 
isIpv6Enabled()3312     private boolean isIpv6Enabled() {
3313         return mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_DISABLED;
3314     }
3315 
isIpv4Enabled()3316     private boolean isIpv4Enabled() {
3317         return mConfiguration.mIPv4ProvisioningMode != PROV_IPV4_DISABLED;
3318     }
3319 
shouldIgnoreNudFailure(@onNull final int[] eventCounts)3320     private boolean shouldIgnoreNudFailure(@NonNull final int[] eventCounts) {
3321         if (!mIgnoreNudFailureEnabled) return false;
3322         if (eventCounts.length == 0) return false;
3323 
3324         final int countInPastOneWeek = eventCounts[0];
3325         final int countInPastOneDay = eventCounts[1];
3326         return countInPastOneDay >= mNudFailureCountDailyThreshold
3327                 || countInPastOneWeek >= mNudFailureCountWeeklyThreshold;
3328     }
3329 
3330     class NudFailureQueryState extends State {
3331         // This listener runs in a different thread (the Executor used in the IpMemoryStoreService)
3332         // and it needs to be volatile to allow access by other threads than the IpClient state
3333         // machine handler, which should be fine since it only accesses the mListener and calls
3334         // sendMessage.
3335         private volatile OnNetworkEventCountRetrievedListener mListener =
3336                 new OnNetworkEventCountRetrievedListener() {
3337                     @Override
3338                     public void onNetworkEventCountRetrieved(Status status, int[] counts) {
3339                         if (mListener != this) return;
3340                         if (counts.length == 0) {
3341                             if (!status.isSuccess()) {
3342                                 Log.e(TAG, "Error retrieving NUD failure event count: " + status);
3343                             }
3344                             sendMessage(EVENT_NUD_FAILURE_QUERY_FAILURE);
3345                             return;
3346                         }
3347                         sendMessage(EVENT_NUD_FAILURE_QUERY_SUCCESS, counts);
3348                     }};
3349 
3350         @Override
enter()3351         public void enter() {
3352             super.enter();
3353             // Set a timeout for retrieving NUD failure event counts.
3354             sendMessageDelayed(EVENT_NUD_FAILURE_QUERY_TIMEOUT, IPMEMORYSTORE_TIMEOUT_MS);
3355             final long now = System.currentTimeMillis();
3356             final long[] sinceTimes = new long[3];
3357             sinceTimes[0] = now - ONE_WEEK_IN_MS;
3358             sinceTimes[1] = now - ONE_DAY_IN_MS;
3359             sinceTimes[2] = now - SIX_HOURS_IN_MS;
3360             mIpMemoryStore.retrieveNetworkEventCount(mCluster, sinceTimes,
3361                     NETWORK_EVENT_NUD_FAILURE_TYPES, mListener);
3362             Counter.logIncrement("core_networking.value_nud_failure_queried");
3363         }
3364 
3365         @Override
processMessage(Message message)3366         public boolean processMessage(Message message) {
3367             switch (message.what) {
3368                 case EVENT_NUD_FAILURE_QUERY_FAILURE:
3369                 case EVENT_NUD_FAILURE_QUERY_TIMEOUT:
3370                     // TODO: log query result with metrics.
3371                     transitionTo(mClearingIpAddressesState);
3372                     return HANDLED;
3373 
3374                 case EVENT_NUD_FAILURE_QUERY_SUCCESS:
3375                     mNudFailureEventCounts = (int[]) message.obj;
3376                     mIgnoreNudFailure = shouldIgnoreNudFailure(mNudFailureEventCounts);
3377                     transitionTo(mClearingIpAddressesState);
3378                     return HANDLED;
3379 
3380                 default:
3381                     deferMessage(message); // e.g. LP updated during this state.
3382                     return HANDLED;
3383             }
3384         }
3385 
3386         @Override
exit()3387         public void exit() {
3388             super.exit();
3389             removeMessages(EVENT_NUD_FAILURE_QUERY_FAILURE);
3390             removeMessages(EVENT_NUD_FAILURE_QUERY_TIMEOUT);
3391             removeMessages(EVENT_NUD_FAILURE_QUERY_SUCCESS);
3392         }
3393     }
3394 
3395     class RunningState extends State {
3396         private ConnectivityPacketTracker mPacketTracker;
3397         private boolean mDhcpActionInFlight;
3398 
3399         @Override
enter()3400         public void enter() {
3401             // While it's possible that a stale clat interface still exists when IpClient starts,
3402             // such an interface would not be used for the network that IpClient is currently
3403             // running on, so it's OK to ignore it. This means that there is no need to check
3404             // whether a clat interface exists when IpClient starts - even if one did exist, it's
3405             // guaranteed to be stale. As a result, mHasSeenClatInterface can always be set to false
3406             // at the beginning.
3407             mHasSeenClatInterface = false;
3408             mApfFilter = maybeCreateApfFilter(mCurrentApfCapabilities);
3409             // If Apf supports ND offload, then turn off the vendor ND offload feature.
3410             if (mApfFilter != null && mApfFilter.enableNdOffload()) {
3411                 mCallback.setNeighborDiscoveryOffload(false);
3412             }
3413             // TODO: investigate the effects of any multicast filtering racing/interfering with the
3414             // rest of this IP configuration startup.
3415             if (mApfFilter == null) {
3416                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
3417             }
3418             if (mEnableApfPollingCounters) {
3419                 sendMessageDelayed(CMD_UPDATE_APF_DATA_SNAPSHOT, mApfCounterPollingIntervalMs);
3420             }
3421 
3422             mPacketTracker = createPacketTracker();
3423             if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
3424 
3425             if (isIpv6Enabled() && !startIPv6(1 /* acceptRaDefrtr */)) {
3426                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
3427                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6);
3428                 return;
3429             }
3430 
3431             if (isIpv4Enabled() && !isUsingPreconnection() && !startIPv4()) {
3432                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
3433                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV4);
3434                 return;
3435             }
3436 
3437             final InitialConfiguration config = mConfiguration.mInitialConfig;
3438             if ((config != null) && !applyInitialConfig(config)) {
3439                 // TODO introduce a new IpManagerEvent constant to distinguish this error case.
3440                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
3441                 enqueueJumpToStoppingState(DisconnectCode.DC_INVALID_PROVISIONING);
3442                 return;
3443             }
3444 
3445             if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
3446                 doImmediateProvisioningFailure(
3447                         IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
3448                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPREACHABILITYMONITOR);
3449                 return;
3450             }
3451         }
3452 
3453         @Override
exit()3454         public void exit() {
3455             stopDhcpAction();
3456 
3457             if (mIpv6AutoconfTimeoutAlarm != null) {
3458                 mIpv6AutoconfTimeoutAlarm.cancel();
3459                 mIpv6AutoconfTimeoutAlarm = null;
3460             }
3461 
3462             if (mIpReachabilityMonitor != null) {
3463                 mIpReachabilityMonitor.stop();
3464                 mIpReachabilityMonitor = null;
3465             }
3466 
3467             if (mPacketTracker != null) {
3468                 mPacketTracker.stop();
3469                 mPacketTracker = null;
3470             }
3471 
3472             if (mApfFilter != null) {
3473                 mApfFilter.shutdown();
3474                 mApfFilter = null;
3475             }
3476 
3477             resetLinkProperties();
3478 
3479             removeMessages(CMD_UPDATE_APF_DATA_SNAPSHOT);
3480         }
3481 
enqueueJumpToStoppingState(final DisconnectCode code)3482         private void enqueueJumpToStoppingState(final DisconnectCode code) {
3483             deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING, code.getNumber()));
3484         }
3485 
createPacketTracker()3486         private ConnectivityPacketTracker createPacketTracker() {
3487             try {
3488                 return new ConnectivityPacketTracker(
3489                         getHandler(),
3490                         mInterfaceParams,
3491                         mConnectivityPacketLog,
3492                         true /* attachFilter */);
3493             } catch (IllegalArgumentException e) {
3494                 return null;
3495             }
3496         }
3497 
ensureDhcpAction()3498         private void ensureDhcpAction() {
3499             if (!mDhcpActionInFlight) {
3500                 mCallback.onPreDhcpAction();
3501                 mDhcpActionInFlight = true;
3502                 final long alarmTime = SystemClock.elapsedRealtime()
3503                         + mConfiguration.mRequestedPreDhcpActionMs;
3504                 mDhcpActionTimeoutAlarm.schedule(alarmTime);
3505             }
3506         }
3507 
stopDhcpAction()3508         private void stopDhcpAction() {
3509             mDhcpActionTimeoutAlarm.cancel();
3510             if (mDhcpActionInFlight) {
3511                 mCallback.onPostDhcpAction();
3512                 mDhcpActionInFlight = false;
3513             }
3514         }
3515 
deleteInterfaceAddress(final LinkAddress address)3516         private void deleteInterfaceAddress(final LinkAddress address) {
3517             if (!address.isIpv6()) {
3518                 // NetlinkUtils.sendRtmDelAddressRequest does not support deleting IPv4 addresses.
3519                 Log.wtf(TAG, "Deleting IPv4 address not supported " + address);
3520                 return;
3521             }
3522             final Inet6Address in6addr = (Inet6Address) address.getAddress();
3523             final short plen = (short) address.getPrefixLength();
3524             if (!NetlinkUtils.sendRtmDelAddressRequest(mInterfaceParams.index, in6addr, plen)) {
3525                 Log.e(TAG, "Failed to delete IPv6 address " + address);
3526             }
3527         }
3528 
deleteIpv6PrefixDelegationAddresses(final IpPrefix prefix)3529         private void deleteIpv6PrefixDelegationAddresses(final IpPrefix prefix) {
3530             // b/290747921: some kernels require the mngtmpaddr to be deleted first, to prevent the
3531             // creation of a new tempaddr.
3532             final List<LinkAddress> linkAddresses = mLinkProperties.getLinkAddresses();
3533             // delete addresses with IFA_F_MANAGETEMPADDR contained in the prefix.
3534             for (LinkAddress la : linkAddresses) {
3535                 if (hasFlag(la, IFA_F_MANAGETEMPADDR) && prefix.contains(la.getAddress())) {
3536                     deleteInterfaceAddress(la);
3537                 }
3538             }
3539             // delete all other addresses contained in the prefix.
3540             for (LinkAddress la : linkAddresses) {
3541                 if (!hasFlag(la, IFA_F_MANAGETEMPADDR) && prefix.contains(la.getAddress())) {
3542                     deleteInterfaceAddress(la);
3543                 }
3544             }
3545         }
3546 
addInterfaceAddress(@ullable final Inet6Address address, @NonNull final IaPrefixOption ipo)3547         private void addInterfaceAddress(@Nullable final Inet6Address address,
3548                 @NonNull final IaPrefixOption ipo) {
3549             final int flags = IFA_F_NOPREFIXROUTE | IFA_F_MANAGETEMPADDR | IFA_F_NODAD;
3550             final long now = SystemClock.elapsedRealtime();
3551             // Per RFC8415 section 21.22 the preferred/valid lifetime in IA Prefix option
3552             // expressed in units of seconds.
3553             final long deprecationTime = now + ipo.preferred * 1000;
3554             final long expirationTime = now + ipo.valid * 1000;
3555             final LinkAddress la;
3556             try {
3557                 la = new LinkAddress(address, RFC7421_PREFIX_LENGTH, flags,
3558                         RT_SCOPE_UNIVERSE /* scope */, deprecationTime, expirationTime);
3559             } catch (IllegalArgumentException e) {
3560                 Log.e(TAG, "Invalid IPv6 link address " + e);
3561                 return;
3562             }
3563             if (!la.isGlobalPreferred()) {
3564                 Log.w(TAG, la + " is not a global IPv6 address");
3565                 return;
3566             }
3567             if (!NetlinkUtils.sendRtmNewAddressRequest(mInterfaceParams.index, address,
3568                     (short) RFC7421_PREFIX_LENGTH,
3569                     flags, (byte) RT_SCOPE_UNIVERSE /* scope */,
3570                     ipo.preferred, ipo.valid)) {
3571                 Log.e(TAG, "Failed to set IPv6 address on " + address.getHostAddress()
3572                         + "%" + mInterfaceParams.index);
3573             }
3574         }
3575 
updateDelegatedAddresses(@onNull final List<IaPrefixOption> valid)3576         private void updateDelegatedAddresses(@NonNull final List<IaPrefixOption> valid) {
3577             if (valid.isEmpty()) return;
3578             final List<IpPrefix> zeroLifetimePrefixList = new ArrayList<>();
3579             for (IaPrefixOption ipo : valid) {
3580                 final IpPrefix prefix = ipo.getIpPrefix();
3581                 // The prefix with preferred/valid lifetime of 0 is considered as a valid prefix,
3582                 // and can be passed to IpClient from Dhcp6Client, but client should stop using
3583                 // the global addresses derived from this prefix asap. Deleting the associated
3584                 // global IPv6 addresses immediately before adding another IPv6 address may result
3585                 // in a race where the device throws the provisioning failure callback due to the
3586                 // loss of all valid IPv6 addresses, however, IPv6 provisioning will soon complete
3587                 // successfully when the user space sees the new IPv6 address update. To avoid this
3588                 // race, temporarily store all prefix(es) with 0 preferred/valid lifetime and then
3589                 // delete them after iterating through all valid IA prefix options.
3590                 if (ipo.withZeroLifetimes()) {
3591                     zeroLifetimePrefixList.add(prefix);
3592                     continue;
3593                 }
3594                 // Otherwise, configure IPv6 addresses derived from the delegated prefix(es) on
3595                 // the interface. We've checked that delegated prefix is valid upon receiving the
3596                 // response from DHCPv6 server, and the server may assign a prefix with length less
3597                 // than 64. So for SLAAC use case we always set the prefix length to 64 even if the
3598                 // delegated prefix length is less than 64.
3599                 final Inet6Address address = createInet6AddressFromEui64(prefix,
3600                         macAddressToEui64(mInterfaceParams.macAddr));
3601                 addInterfaceAddress(address, ipo);
3602             }
3603 
3604             // Delete global IPv6 addresses derived from prefix with 0 preferred/valid lifetime.
3605             if (!zeroLifetimePrefixList.isEmpty()) {
3606                 for (IpPrefix prefix : zeroLifetimePrefixList) {
3607                     Log.d(TAG, "Delete IPv6 address derived from prefix " + prefix
3608                             + " with 0 preferred/valid lifetime");
3609                     deleteIpv6PrefixDelegationAddresses(prefix);
3610                 }
3611             }
3612         }
3613 
removeExpiredDelegatedAddresses(@onNull final List<IaPrefixOption> expired)3614         private void removeExpiredDelegatedAddresses(@NonNull final List<IaPrefixOption> expired) {
3615             if (expired.isEmpty()) return;
3616             for (IaPrefixOption ipo : expired) {
3617                 final IpPrefix prefix = ipo.getIpPrefix();
3618                 Log.d(TAG, "Delete IPv6 address derived from expired prefix " + prefix);
3619                 deleteIpv6PrefixDelegationAddresses(prefix);
3620             }
3621         }
3622 
3623         @Override
processMessage(Message msg)3624         public boolean processMessage(Message msg) {
3625             switch (msg.what) {
3626                 case CMD_JUMP_RUNNING_TO_STOPPING:
3627                 case CMD_STOP:
3628                     transitionToStoppingState(DisconnectCode.forNumber(msg.arg1));
3629                     break;
3630 
3631                 case CMD_START:
3632                     logError("ALERT: START received in StartedState. Please fix caller.");
3633                     break;
3634 
3635                 case CMD_CONFIRM:
3636                     // TODO: Possibly introduce a second type of confirmation
3637                     // that both probes (a) on-link neighbors and (b) does
3638                     // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
3639                     // roams.
3640                     if (mIpReachabilityMonitor != null) {
3641                         mIpReachabilityMonitor.probeAll(false /* dueToRoam */);
3642                     }
3643                     break;
3644 
3645                 case EVENT_PRE_DHCP_ACTION_COMPLETE:
3646                     // It's possible to reach here if, for example, someone
3647                     // calls completedPreDhcpAction() after provisioning with
3648                     // a static IP configuration.
3649                     if (mDhcpClient != null) {
3650                         mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
3651                     }
3652                     break;
3653 
3654                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
3655                     // EVENT_NETLINK_LINKPROPERTIES_CHANGED message will be received in both of
3656                     // provisioning loss and normal user termination cases (e.g. turn off wifi or
3657                     // switch to another wifi ssid), hence, checking the current interface link
3658                     // state (down or up) helps distinguish the two cases: if the link state is
3659                     // down, provisioning is only lost because the link is being torn down (for
3660                     // example when turning off wifi), so treat it as a normal termination.
3661                     if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
3662                         final boolean linkStateUp = (msg.arg1 == ARG_LINKPROP_CHANGED_LINKSTATE_UP);
3663                         transitionToStoppingState(linkStateUp ? DisconnectCode.DC_PROVISIONING_FAIL
3664                                 : DisconnectCode.DC_NORMAL_TERMINATION);
3665                     }
3666                     break;
3667 
3668                 case CMD_UPDATE_TCP_BUFFER_SIZES:
3669                     mTcpBufferSizes = (String) msg.obj;
3670                     // This cannot possibly change provisioning state.
3671                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
3672                     break;
3673 
3674                 case CMD_UPDATE_HTTP_PROXY:
3675                     mHttpProxy = (ProxyInfo) msg.obj;
3676                     // This cannot possibly change provisioning state.
3677                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
3678                     break;
3679 
3680                 case CMD_SET_MULTICAST_FILTER: {
3681                     mMulticastFiltering = (boolean) msg.obj;
3682                     if (mApfFilter != null) {
3683                         mApfFilter.setMulticastFilter(mMulticastFiltering);
3684                     } else {
3685                         mCallback.setFallbackMulticastFilter(mMulticastFiltering);
3686                     }
3687                     updateMaxDtimMultiplier();
3688                     break;
3689                 }
3690 
3691                 case EVENT_READ_PACKET_FILTER_COMPLETE: {
3692                     if (mApfFilter != null) {
3693                         String snapShotStr = mApfFilter.setDataSnapshot((byte[]) msg.obj);
3694                         mLog.log("readPacketFilterComplete, ApfCounters: " + snapShotStr);
3695                     }
3696                     mApfDataSnapshotComplete.open();
3697                     break;
3698                 }
3699 
3700                 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
3701                     final int slot = msg.arg1;
3702 
3703                     if (mApfFilter != null) {
3704                         if (msg.obj instanceof NattKeepalivePacketDataParcelable) {
3705                             mApfFilter.addNattKeepalivePacketFilter(slot,
3706                                     (NattKeepalivePacketDataParcelable) msg.obj);
3707                         } else if (msg.obj instanceof TcpKeepalivePacketDataParcelable) {
3708                             mApfFilter.addTcpKeepalivePacketFilter(slot,
3709                                     (TcpKeepalivePacketDataParcelable) msg.obj);
3710                         }
3711                     }
3712                     break;
3713                 }
3714 
3715                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
3716                     final int slot = msg.arg1;
3717                     if (mApfFilter != null) {
3718                         mApfFilter.removeKeepalivePacketFilter(slot);
3719                     }
3720                     break;
3721                 }
3722 
3723                 case EVENT_DHCPACTION_TIMEOUT:
3724                     stopDhcpAction();
3725                     break;
3726 
3727                 case EVENT_IPV6_AUTOCONF_TIMEOUT:
3728                     // Only enable DHCPv6 PD on networks that support IPv6 but not autoconf. The
3729                     // right way to do it is to use the P flag, once it's defined. For now, assume
3730                     // that the network doesn't support autoconf if it provides an IPv6 default
3731                     // route but no addresses via an RA.
3732                     // TODO: leverage the P flag in RA to determine if starting DHCPv6 PD or not,
3733                     // which is more clear and straightforward.
3734                     if (!hasIpv6Address(mLinkProperties)
3735                             && mLinkProperties.hasIpv6DefaultRoute()) {
3736                         Log.d(TAG, "Network supports IPv6 but not autoconf, starting DHCPv6 PD");
3737                         mNetworkQuirkMetrics.setEvent(QE_DHCP6_HEURISTIC_TRIGGERED);
3738                         mNetworkQuirkMetrics.statsWrite();
3739                         startDhcp6PrefixDelegation();
3740                     }
3741                     break;
3742 
3743                 case DhcpClient.CMD_PRE_DHCP_ACTION:
3744                     if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
3745                         ensureDhcpAction();
3746                     } else {
3747                         sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
3748                     }
3749                     break;
3750 
3751                 case DhcpClient.CMD_CLEAR_LINKADDRESS:
3752                     mInterfaceCtrl.clearIPv4Address();
3753                     break;
3754 
3755                 case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
3756                     final LinkAddress ipAddress = (LinkAddress) msg.obj;
3757                     final boolean success;
3758                     if (mPopulateLinkAddressLifetime) {
3759                         // For IPv4 link addresses, there is no concept of preferred/valid
3760                         // lifetimes. Populate the ifa_cacheinfo attribute in the netlink
3761                         // message with the DHCP lease duration, which is used by the kernel
3762                         // to maintain the validity of the IP addresses.
3763                         final int leaseDuration = msg.arg1;
3764                         success = NetlinkUtils.sendRtmNewAddressRequest(mInterfaceParams.index,
3765                                 ipAddress.getAddress(),
3766                                 (short) ipAddress.getPrefixLength(),
3767                                 0 /* flags */,
3768                                 (byte) RT_SCOPE_UNIVERSE /* scope */,
3769                                 leaseDuration /* preferred */,
3770                                 leaseDuration /* valid */);
3771                     } else {
3772                         success = mInterfaceCtrl.setIPv4Address(ipAddress);
3773                     }
3774                     if (success) {
3775                         // Although it's impossible to happen that DHCP client becomes null in
3776                         // RunningState and then NPE is thrown when it attempts to send a message
3777                         // on an null object, sometimes it's found during stress tests. If this
3778                         // issue does happen, log the terrible failure, that would be helpful to
3779                         // see how often this case occurs on fields and the log trace would be
3780                         // also useful for debugging(see b/203174383).
3781                         if (mDhcpClient == null) {
3782                             Log.wtf(mTag, "DhcpClient should never be null in RunningState.");
3783                         }
3784                         mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
3785                     } else {
3786                         logError("Failed to set IPv4 address.");
3787                         dispatchCallback(PROV_CHANGE_LOST_PROVISIONING, mLinkProperties);
3788                         transitionToStoppingState(DisconnectCode.DC_PROVISIONING_FAIL);
3789                     }
3790                     break;
3791                 }
3792 
3793                 // This message is only received when:
3794                 //
3795                 //     a) initial address acquisition succeeds,
3796                 //     b) renew succeeds or is NAK'd,
3797                 //     c) rebind succeeds or is NAK'd, or
3798                 //     d) the lease expires, or
3799                 //     e) the IPv6-only preferred option is enabled and entering Ipv6OnlyWaitState.
3800                 //
3801                 // but never when initial address acquisition fails. The latter
3802                 // condition is now governed by the provisioning timeout.
3803                 case DhcpClient.CMD_POST_DHCP_ACTION:
3804                     stopDhcpAction();
3805 
3806                     switch (msg.arg1) {
3807                         case DhcpClient.DHCP_SUCCESS:
3808                             handleIPv4Success((DhcpResults) msg.obj);
3809                             break;
3810                         case DhcpClient.DHCP_FAILURE:
3811                             handleIPv4Failure();
3812                             break;
3813                         case DhcpClient.DHCP_IPV6_ONLY:
3814                             break;
3815                         case DhcpClient.DHCP_REFRESH_FAILURE:
3816                             // This case should only happen on the receipt of DHCPNAK when
3817                             // refreshing IP address post L2 roaming on some specific networks.
3818                             // WiFi should try to restart a new provisioning immediately without
3819                             // disconnecting L2 when it receives DHCP roaming failure event. IPv4
3820                             // link address still will be cleared when DhcpClient transits to
3821                             // StoppedState from RefreshingAddress State, although it will result
3822                             // in a following onProvisioningFailure then, WiFi should ignore this
3823                             // failure and start a new DHCP reconfiguration from INIT state.
3824                             final ReachabilityLossInfoParcelable lossInfo =
3825                                     new ReachabilityLossInfoParcelable("DHCP refresh failure",
3826                                             ReachabilityLossReason.ROAM);
3827                             mCallback.onReachabilityFailure(lossInfo);
3828                             break;
3829                         default:
3830                             logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
3831                     }
3832                     break;
3833 
3834                 case Dhcp6Client.CMD_DHCP6_RESULT:
3835                     switch(msg.arg1) {
3836                         case Dhcp6Client.DHCP6_PD_SUCCESS:
3837                             final List<IaPrefixOption> toBeUpdated = (List<IaPrefixOption>) msg.obj;
3838                             updateDelegatedAddresses(toBeUpdated);
3839                             handleLinkPropertiesUpdate(SEND_CALLBACKS);
3840                             break;
3841 
3842                         case Dhcp6Client.DHCP6_PD_PREFIX_EXPIRED:
3843                             final List<IaPrefixOption> toBeRemoved = (List<IaPrefixOption>) msg.obj;
3844                             removeExpiredDelegatedAddresses(toBeRemoved);
3845                             handleLinkPropertiesUpdate(SEND_CALLBACKS);
3846                             break;
3847 
3848                         default:
3849                             logError("Unknown CMD_DHCP6_RESULT status: %s", msg.arg1);
3850                     }
3851                     break;
3852 
3853                 case DhcpClient.CMD_ON_QUIT:
3854                     // DHCPv4 quit early for some reason.
3855                     logError("Unexpected CMD_ON_QUIT from DHCPv4.");
3856                     mDhcpClient = null;
3857                     break;
3858 
3859                 case Dhcp6Client.CMD_ON_QUIT:
3860                     // DHCPv6 quit early for some reason.
3861                     logError("Unexpected CMD_ON_QUIT from DHCPv6.");
3862                     mDhcp6Client = null;
3863                     break;
3864 
3865                 case CMD_SET_DTIM_MULTIPLIER_AFTER_DELAY:
3866                     updateMaxDtimMultiplier();
3867                     break;
3868 
3869                 case CMD_UPDATE_APF_CAPABILITIES:
3870                     final ApfCapabilities apfCapabilities = (ApfCapabilities) msg.obj;
3871                     if (handleUpdateApfCapabilities(apfCapabilities)) {
3872                         mApfFilter = maybeCreateApfFilter(apfCapabilities);
3873                         // If Apf supports ND offload, then turn off the vendor ND offload feature.
3874                         if (mApfFilter != null && mApfFilter.enableNdOffload()) {
3875                             mCallback.setNeighborDiscoveryOffload(false);
3876                         }
3877                     }
3878                     break;
3879 
3880                 case CMD_UPDATE_APF_DATA_SNAPSHOT:
3881                     if (mApfFilter != null) {
3882                         // We prevents calls to readPacketFilterRam() when  mApfFilter is null.
3883                         // This is correct because any data read would be discarded when
3884                         // processing the EVENT_READ_PACKET_FILTER_COMPLETE event if no
3885                         // ApfFilter exists.
3886                         mApfFilter.getApfController().readPacketFilterRam("polling");
3887                     }
3888                     // Even if mApfFilter is currently null, periodic checks are necessary to
3889                     // read APF RAM when an ApfFilter becomes available, as APF capabilities can
3890                     // be updated which result in mApfFilter being created.
3891                     sendMessageDelayed(CMD_UPDATE_APF_DATA_SNAPSHOT, mApfCounterPollingIntervalMs);
3892                     break;
3893 
3894                 default:
3895                     return NOT_HANDLED;
3896             }
3897 
3898             mMsgStateLogger.handled(this, getCurrentState());
3899             return HANDLED;
3900         }
3901     }
3902 
3903     /**
3904      * Set the maximum DTIM multiplier to hardware driver per network condition. Any multiplier
3905      * larger than the maximum value must not be accepted, it will cause packet loss higher than
3906      * what the system can accept, which will cause unexpected behavior for apps, and may interrupt
3907      * the network connection.
3908      *
3909      * When Wifi STA is in the power saving mode and the system is suspended, the wakeup interval
3910      * will be set to:
3911      *    1) multiplier * AP's DTIM period if multiplier > 0.
3912      *    2) the driver default value if multiplier <= 0.
3913      * Some implementations may apply an additional cap to wakeup interval in the case of 1).
3914      */
updateMaxDtimMultiplier()3915     private void updateMaxDtimMultiplier() {
3916         int multiplier = deriveDtimMultiplier();
3917         if (mMaxDtimMultiplier == multiplier) return;
3918 
3919         mMaxDtimMultiplier = multiplier;
3920         log("set max DTIM multiplier to " + multiplier);
3921         mCallback.setMaxDtimMultiplier(multiplier);
3922     }
3923 
3924     /**
3925      * Check if current LinkProperties has either global IPv6 address or ULA (i.e. non IPv6
3926      * link-local addres).
3927      *
3928      * This function can be used to derive the DTIM multiplier per current network situation or
3929      * decide if we should start DHCPv6 Prefix Delegation when no IPv6 addresses are available
3930      * after autoconf timeout(5s).
3931      */
hasIpv6Address(@onNull final LinkProperties lp)3932     private static boolean hasIpv6Address(@NonNull final LinkProperties lp) {
3933         return CollectionUtils.any(lp.getLinkAddresses(),
3934                 la -> {
3935                     final InetAddress address = la.getAddress();
3936                     return (address instanceof Inet6Address) && !address.isLinkLocalAddress();
3937                 });
3938     }
3939 
deriveDtimMultiplier()3940     private int deriveDtimMultiplier() {
3941         final boolean hasIpv4Addr = mLinkProperties.hasIpv4Address();
3942         // For a host in the network that has only ULA and link-local but no GUA, consider
3943         // that it also has IPv6 connectivity. LinkProperties#isIpv6Provisioned only returns
3944         // true when it has a GUA, so we cannot use it for IPv6-only network case.
3945         final boolean hasIpv6Addr = hasIpv6Address(mLinkProperties);
3946 
3947         final int multiplier;
3948         if (!mMulticastFiltering) {
3949             multiplier = mDependencies.getDeviceConfigPropertyInt(
3950                     CONFIG_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER,
3951                     DEFAULT_MULTICAST_LOCK_MAX_DTIM_MULTIPLIER);
3952         } else if (!hasIpv6Addr
3953                 && (SystemClock.elapsedRealtime() < mIPv6ProvisioningDtimGracePeriodMillis)) {
3954             // IPv6 provisioning may or may not complete soon in the future, we don't know when
3955             // it will complete, however, setting multiplier to a high value will cause higher
3956             // RA packet loss, that increases the overall IPv6 provisioning latency. So just set
3957             // multiplier to 1 before device gains the IPv6 provisioning, make sure device won't
3958             // miss any RA packet later.
3959             multiplier = mDependencies.getDeviceConfigPropertyInt(
3960                     CONFIG_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER,
3961                     DEFAULT_BEFORE_IPV6_PROV_MAX_DTIM_MULTIPLIER);
3962         } else if (hasIpv6Addr && !hasIpv4Addr) {
3963             multiplier = mDependencies.getDeviceConfigPropertyInt(
3964                     CONFIG_IPV6_ONLY_NETWORK_MAX_DTIM_MULTIPLIER,
3965                     DEFAULT_IPV6_ONLY_NETWORK_MAX_DTIM_MULTIPLIER);
3966         } else if (hasIpv4Addr && !hasIpv6Addr) {
3967             multiplier = mDependencies.getDeviceConfigPropertyInt(
3968                     CONFIG_IPV4_ONLY_NETWORK_MAX_DTIM_MULTIPLIER,
3969                     DEFAULT_IPV4_ONLY_NETWORK_MAX_DTIM_MULTIPLIER);
3970         } else if (hasIpv6Addr && hasIpv4Addr) {
3971             multiplier = mDependencies.getDeviceConfigPropertyInt(
3972                     CONFIG_DUAL_STACK_MAX_DTIM_MULTIPLIER,
3973                     DEFAULT_DUAL_STACK_MAX_DTIM_MULTIPLIER);
3974         } else {
3975             multiplier = DTIM_MULTIPLIER_RESET;
3976         }
3977         return multiplier;
3978     }
3979 
3980     private static class MessageHandlingLogger {
3981         public String processedInState;
3982         public String receivedInState;
3983 
reset()3984         public void reset() {
3985             processedInState = null;
3986             receivedInState = null;
3987         }
3988 
handled(State processedIn, IState receivedIn)3989         public void handled(State processedIn, IState receivedIn) {
3990             processedInState = processedIn.getClass().getSimpleName();
3991             receivedInState = receivedIn.getName();
3992         }
3993 
toString()3994         public String toString() {
3995             return String.format("rcvd_in=%s, proc_in=%s",
3996                                  receivedInState, processedInState);
3997         }
3998     }
3999 
4000     // TODO: extract out into CollectionUtils.
any(Iterable<T> coll, Predicate<T> fn)4001     static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
4002         for (T t : coll) {
4003             if (fn.test(t)) {
4004                 return true;
4005             }
4006         }
4007         return false;
4008     }
4009 
all(Iterable<T> coll, Predicate<T> fn)4010     static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
4011         return !any(coll, not(fn));
4012     }
4013 
not(Predicate<T> fn)4014     static <T> Predicate<T> not(Predicate<T> fn) {
4015         return (t) -> !fn.test(t);
4016     }
4017 
join(String delimiter, Collection<T> coll)4018     static <T> String join(String delimiter, Collection<T> coll) {
4019         return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
4020     }
4021 
4022     /**
4023      * Find a specific element which satisfies the predicate in a collection.
4024      */
4025     @VisibleForTesting
find(Iterable<T> coll, Predicate<T> fn)4026     public static <T> T find(Iterable<T> coll, Predicate<T> fn) {
4027         for (T t: coll) {
4028             if (fn.test(t)) {
4029                 return t;
4030             }
4031         }
4032         return null;
4033     }
4034 
findAll(Collection<T> coll, Predicate<T> fn)4035     static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
4036         return coll.stream().filter(fn).collect(Collectors.toList());
4037     }
4038 }
4039