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