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