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