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 } 781 782 @Override onQuitting()783 protected void onQuitting() { 784 mCallback.onQuit(); 785 mShutdownLatch.countDown(); 786 } 787 788 /** 789 * Shut down this IpClient instance altogether. 790 */ shutdown()791 public void shutdown() { 792 stop(); 793 sendMessage(CMD_TERMINATE_AFTER_STOP); 794 } 795 796 /** 797 * Start provisioning with the provided parameters. 798 */ startProvisioning(ProvisioningConfiguration req)799 public void startProvisioning(ProvisioningConfiguration req) { 800 if (!req.isValid()) { 801 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING); 802 return; 803 } 804 805 final ScanResultInfo scanResultInfo = req.mScanResultInfo; 806 mCurrentBssid = null; 807 if (scanResultInfo != null) { 808 try { 809 mCurrentBssid = MacAddress.fromString(scanResultInfo.getBssid()); 810 } catch (IllegalArgumentException e) { 811 Log.wtf(mTag, "Invalid BSSID: " + scanResultInfo.getBssid() 812 + " in provisioning configuration", e); 813 } 814 } 815 816 if (req.mLayer2Info != null) { 817 mL2Key = req.mLayer2Info.mL2Key; 818 mCluster = req.mLayer2Info.mCluster; 819 } 820 sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req)); 821 } 822 823 /** 824 * Stop this IpClient. 825 * 826 * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}. 827 * The message "arg1" parameter is used to record the disconnect code metrics. 828 * Usually this method is called by the peer (e.g. wifi) intentionally to stop IpClient, 829 * consider that's the normal user termination. 830 */ stop()831 public void stop() { 832 sendMessage(CMD_STOP, DisconnectCode.DC_NORMAL_TERMINATION.getNumber()); 833 } 834 835 /** 836 * Confirm the provisioning configuration. 837 */ confirmConfiguration()838 public void confirmConfiguration() { 839 sendMessage(CMD_CONFIRM); 840 } 841 842 /** 843 * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be 844 * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to 845 * proceed. 846 */ completedPreDhcpAction()847 public void completedPreDhcpAction() { 848 sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE); 849 } 850 851 /** 852 * Indicate that packet filter read is complete. 853 */ readPacketFilterComplete(byte[] data)854 public void readPacketFilterComplete(byte[] data) { 855 sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data); 856 } 857 858 /** 859 * Set the TCP buffer sizes to use. 860 * 861 * This may be called, repeatedly, at any time before or after a call to 862 * #startProvisioning(). The setting is cleared upon calling #stop(). 863 */ setTcpBufferSizes(String tcpBufferSizes)864 public void setTcpBufferSizes(String tcpBufferSizes) { 865 sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes); 866 } 867 868 /** 869 * Set the L2 key and cluster for storing info into the memory store. 870 * 871 * This method is only supported on Q devices. For R or above releases, 872 * caller should call #updateLayer2Information() instead. 873 */ setL2KeyAndCluster(String l2Key, String cluster)874 public void setL2KeyAndCluster(String l2Key, String cluster) { 875 if (!ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) { 876 sendMessage(CMD_UPDATE_L2KEY_CLUSTER, new Pair<>(l2Key, cluster)); 877 } 878 } 879 880 /** 881 * Set the HTTP Proxy configuration to use. 882 * 883 * This may be called, repeatedly, at any time before or after a call to 884 * #startProvisioning(). The setting is cleared upon calling #stop(). 885 */ setHttpProxy(ProxyInfo proxyInfo)886 public void setHttpProxy(ProxyInfo proxyInfo) { 887 sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo); 888 } 889 890 /** 891 * Enable or disable the multicast filter. Attempts to use APF to accomplish the filtering, 892 * if not, Callback.setFallbackMulticastFilter() is called. 893 */ setMulticastFilter(boolean enabled)894 public void setMulticastFilter(boolean enabled) { 895 sendMessage(CMD_SET_MULTICAST_FILTER, enabled); 896 } 897 898 /** 899 * Called by WifiStateMachine to add TCP keepalive packet filter before setting up 900 * keepalive offload. 901 */ addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt)902 public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) { 903 sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt); 904 } 905 906 /** 907 * Called by WifiStateMachine to add NATT keepalive packet filter before setting up 908 * keepalive offload. 909 */ addNattKeepalivePacketFilter(int slot, @NonNull NattKeepalivePacketDataParcelable pkt)910 public void addNattKeepalivePacketFilter(int slot, 911 @NonNull NattKeepalivePacketDataParcelable pkt) { 912 sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */ , pkt); 913 } 914 915 /** 916 * Called by WifiStateMachine to remove keepalive packet filter after stopping keepalive 917 * offload. 918 */ removeKeepalivePacketFilter(int slot)919 public void removeKeepalivePacketFilter(int slot) { 920 sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot, 0 /* Unused */); 921 } 922 923 /** 924 * Notify IpClient that preconnection is complete and that the link is ready for use. 925 * The success parameter indicates whether the packets passed in by onPreconnectionStart were 926 * successfully sent to the network or not. 927 */ notifyPreconnectionComplete(boolean success)928 public void notifyPreconnectionComplete(boolean success) { 929 sendMessage(CMD_COMPLETE_PRECONNECTION, success ? 1 : 0); 930 } 931 932 /** 933 * Update the network bssid, L2Key and cluster on L2 roaming happened. 934 */ updateLayer2Information(@onNull Layer2InformationParcelable info)935 public void updateLayer2Information(@NonNull Layer2InformationParcelable info) { 936 sendMessage(CMD_UPDATE_L2INFORMATION, info); 937 } 938 939 /** 940 * Dump logs of this IpClient. 941 */ dump(FileDescriptor fd, PrintWriter writer, String[] args)942 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 943 if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) { 944 // Execute confirmConfiguration() and take no further action. 945 confirmConfiguration(); 946 return; 947 } 948 949 // Thread-unsafe access to mApfFilter but just used for debugging. 950 final ApfFilter apfFilter = mApfFilter; 951 final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration; 952 final ApfCapabilities apfCapabilities = (provisioningConfig != null) 953 ? provisioningConfig.mApfCapabilities : null; 954 955 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 956 pw.println(mTag + " APF dump:"); 957 pw.increaseIndent(); 958 if (apfFilter != null) { 959 if (apfCapabilities.hasDataAccess()) { 960 // Request a new snapshot, then wait for it. 961 mApfDataSnapshotComplete.close(); 962 mCallback.startReadPacketFilter(); 963 if (!mApfDataSnapshotComplete.block(1000)) { 964 pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT"); 965 } 966 } 967 apfFilter.dump(pw); 968 969 } else { 970 pw.print("No active ApfFilter; "); 971 if (provisioningConfig == null) { 972 pw.println("IpClient not yet started."); 973 } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) { 974 pw.println("Hardware does not support APF."); 975 } else { 976 pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities); 977 } 978 } 979 pw.decreaseIndent(); 980 pw.println(); 981 pw.println(mTag + " current ProvisioningConfiguration:"); 982 pw.increaseIndent(); 983 pw.println(Objects.toString(provisioningConfig, "N/A")); 984 pw.decreaseIndent(); 985 986 final IpReachabilityMonitor iprm = mIpReachabilityMonitor; 987 if (iprm != null) { 988 pw.println(); 989 pw.println(mTag + " current IpReachabilityMonitor state:"); 990 pw.increaseIndent(); 991 iprm.dump(pw); 992 pw.decreaseIndent(); 993 } 994 995 pw.println(); 996 pw.println(mTag + " StateMachine dump:"); 997 pw.increaseIndent(); 998 mLog.dump(fd, pw, args); 999 pw.decreaseIndent(); 1000 1001 pw.println(); 1002 pw.println(mTag + " connectivity packet log:"); 1003 pw.println(); 1004 pw.println("Debug with python and scapy via:"); 1005 pw.println("shell$ python"); 1006 pw.println(">>> from scapy import all as scapy"); 1007 pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()"); 1008 pw.println(); 1009 1010 pw.increaseIndent(); 1011 mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args); 1012 pw.decreaseIndent(); 1013 } 1014 1015 1016 /** 1017 * Internals. 1018 */ 1019 1020 @Override getWhatToString(int what)1021 protected String getWhatToString(int what) { 1022 return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what)); 1023 } 1024 1025 @Override getLogRecString(Message msg)1026 protected String getLogRecString(Message msg) { 1027 final String logLine = String.format( 1028 "%s/%d %d %d %s [%s]", 1029 mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index, 1030 msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger); 1031 1032 final String richerLogLine = getWhatToString(msg.what) + " " + logLine; 1033 mLog.log(richerLogLine); 1034 if (DBG) { 1035 Log.d(mTag, richerLogLine); 1036 } 1037 1038 mMsgStateLogger.reset(); 1039 return logLine; 1040 } 1041 1042 @Override recordLogRec(Message msg)1043 protected boolean recordLogRec(Message msg) { 1044 // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy, 1045 // and we already log any LinkProperties change that results in an 1046 // invocation of IpClient.Callback#onLinkPropertiesChange(). 1047 final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED); 1048 if (!shouldLog) { 1049 mMsgStateLogger.reset(); 1050 } 1051 return shouldLog; 1052 } 1053 logError(String fmt, Throwable e, Object... args)1054 private void logError(String fmt, Throwable e, Object... args) { 1055 mLog.e(String.format(fmt, args), e); 1056 } 1057 logError(String fmt, Object... args)1058 private void logError(String fmt, Object... args) { 1059 logError(fmt, null, args); 1060 } 1061 1062 // This needs to be called with care to ensure that our LinkProperties 1063 // are in sync with the actual LinkProperties of the interface. For example, 1064 // we should only call this if we know for sure that there are no IP addresses 1065 // assigned to the interface, etc. resetLinkProperties()1066 private void resetLinkProperties() { 1067 mLinkObserver.clearLinkProperties(); 1068 mConfiguration = null; 1069 mDhcpResults = null; 1070 mTcpBufferSizes = ""; 1071 mHttpProxy = null; 1072 1073 mLinkProperties = new LinkProperties(); 1074 mLinkProperties.setInterfaceName(mInterfaceName); 1075 } 1076 recordMetric(final int type)1077 private void recordMetric(final int type) { 1078 // We may record error metrics prior to starting. 1079 // Map this to IMMEDIATE_FAILURE_DURATION. 1080 final long duration = (mStartTimeMillis > 0) 1081 ? (SystemClock.elapsedRealtime() - mStartTimeMillis) 1082 : IMMEDIATE_FAILURE_DURATION; 1083 mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration)); 1084 } 1085 1086 // Record the DisconnectCode and transition to StoppingState. transitionToStoppingState(final DisconnectCode code)1087 private void transitionToStoppingState(final DisconnectCode code) { 1088 mIpProvisioningMetrics.setDisconnectCode(code); 1089 transitionTo(mStoppingState); 1090 } 1091 1092 // For now: use WifiStateMachine's historical notion of provisioned. 1093 @VisibleForTesting isProvisioned(LinkProperties lp, InitialConfiguration config)1094 static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) { 1095 // For historical reasons, we should connect even if all we have is 1096 // an IPv4 address and nothing else. 1097 if (lp.hasIpv4Address() || lp.isProvisioned()) { 1098 return true; 1099 } 1100 if (config == null) { 1101 return false; 1102 } 1103 1104 // When an InitialConfiguration is specified, ignore any difference with previous 1105 // properties and instead check if properties observed match the desired properties. 1106 return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes()); 1107 } 1108 1109 // TODO: Investigate folding all this into the existing static function 1110 // LinkProperties.compareProvisioning() or some other single function that 1111 // takes two LinkProperties objects and returns a ProvisioningChange 1112 // object that is a correct and complete assessment of what changed, taking 1113 // account of the asymmetries described in the comments in this function. 1114 // Then switch to using it everywhere (IpReachabilityMonitor, etc.). compareProvisioning(LinkProperties oldLp, LinkProperties newLp)1115 private int compareProvisioning(LinkProperties oldLp, LinkProperties newLp) { 1116 int delta; 1117 InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null; 1118 final boolean wasProvisioned = isProvisioned(oldLp, config); 1119 final boolean isProvisioned = isProvisioned(newLp, config); 1120 1121 if (!wasProvisioned && isProvisioned) { 1122 delta = PROV_CHANGE_GAINED_PROVISIONING; 1123 } else if (wasProvisioned && isProvisioned) { 1124 delta = PROV_CHANGE_STILL_PROVISIONED; 1125 } else if (!wasProvisioned && !isProvisioned) { 1126 delta = PROV_CHANGE_STILL_NOT_PROVISIONED; 1127 } else { 1128 // (wasProvisioned && !isProvisioned) 1129 // 1130 // Note that this is true even if we lose a configuration element 1131 // (e.g., a default gateway) that would not be required to advance 1132 // into provisioned state. This is intended: if we have a default 1133 // router and we lose it, that's a sure sign of a problem, but if 1134 // we connect to a network with no IPv4 DNS servers, we consider 1135 // that to be a network without DNS servers and connect anyway. 1136 // 1137 // See the comment below. 1138 delta = PROV_CHANGE_LOST_PROVISIONING; 1139 } 1140 1141 final boolean lostIPv6 = oldLp.isIpv6Provisioned() && !newLp.isIpv6Provisioned(); 1142 final boolean lostIPv4Address = oldLp.hasIpv4Address() && !newLp.hasIpv4Address(); 1143 final boolean lostIPv6Router = oldLp.hasIpv6DefaultRoute() && !newLp.hasIpv6DefaultRoute(); 1144 1145 // If bad wifi avoidance is disabled, then ignore IPv6 loss of 1146 // provisioning. Otherwise, when a hotspot that loses Internet 1147 // access sends out a 0-lifetime RA to its clients, the clients 1148 // will disconnect and then reconnect, avoiding the bad hotspot, 1149 // instead of getting stuck on the bad hotspot. http://b/31827713 . 1150 // 1151 // This is incorrect because if the hotspot then regains Internet 1152 // access with a different prefix, TCP connections on the 1153 // deprecated addresses will remain stuck. 1154 // 1155 // Note that we can still be disconnected by IpReachabilityMonitor 1156 // if the IPv6 default gateway (but not the IPv6 DNS servers; see 1157 // accompanying code in IpReachabilityMonitor) is unreachable. 1158 final boolean ignoreIPv6ProvisioningLoss = mHasDisabledIPv6OnProvLoss 1159 || (mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker 1160 && !mCm.shouldAvoidBadWifi()); 1161 1162 // Additionally: 1163 // 1164 // Partial configurations (e.g., only an IPv4 address with no DNS 1165 // servers and no default route) are accepted as long as DHCPv4 1166 // succeeds. On such a network, isProvisioned() will always return 1167 // false, because the configuration is not complete, but we want to 1168 // connect anyway. It might be a disconnected network such as a 1169 // Chromecast or a wireless printer, for example. 1170 // 1171 // Because on such a network isProvisioned() will always return false, 1172 // delta will never be LOST_PROVISIONING. So check for loss of 1173 // provisioning here too. 1174 if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) { 1175 delta = PROV_CHANGE_LOST_PROVISIONING; 1176 } 1177 1178 // Additionally: 1179 // 1180 // If the previous link properties had a global IPv6 address and an 1181 // IPv6 default route then also consider the loss of that default route 1182 // to be a loss of provisioning. See b/27962810. 1183 if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) { 1184 // Although link properties have lost IPv6 default route in this case, if IPv4 is still 1185 // working with appropriate routes and DNS servers, we can keep the current connection 1186 // without disconnecting from the network, just disable IPv6 on that given network until 1187 // to the next provisioning. Disabling IPv6 will result in all IPv6 connectivity torn 1188 // down and all IPv6 sockets being closed, the non-routable IPv6 DNS servers will be 1189 // stripped out, so applications will be able to reconnect immediately over IPv4. See 1190 // b/131781810. 1191 if (newLp.isIpv4Provisioned()) { 1192 mInterfaceCtrl.disableIPv6(); 1193 mHasDisabledIPv6OnProvLoss = true; 1194 delta = PROV_CHANGE_STILL_PROVISIONED; 1195 if (DBG) { 1196 mLog.log("Disable IPv6 stack completely when the default router has gone"); 1197 } 1198 } else { 1199 delta = PROV_CHANGE_LOST_PROVISIONING; 1200 } 1201 } 1202 1203 return delta; 1204 } 1205 dispatchCallback(int delta, LinkProperties newLp)1206 private void dispatchCallback(int delta, LinkProperties newLp) { 1207 switch (delta) { 1208 case PROV_CHANGE_GAINED_PROVISIONING: 1209 if (DBG) { 1210 Log.d(mTag, "onProvisioningSuccess()"); 1211 } 1212 recordMetric(IpManagerEvent.PROVISIONING_OK); 1213 mCallback.onProvisioningSuccess(newLp); 1214 break; 1215 1216 case PROV_CHANGE_LOST_PROVISIONING: 1217 if (DBG) { 1218 Log.d(mTag, "onProvisioningFailure()"); 1219 } 1220 recordMetric(IpManagerEvent.PROVISIONING_FAIL); 1221 mCallback.onProvisioningFailure(newLp); 1222 break; 1223 1224 default: 1225 if (DBG) { 1226 Log.d(mTag, "onLinkPropertiesChange()"); 1227 } 1228 mCallback.onLinkPropertiesChange(newLp); 1229 break; 1230 } 1231 } 1232 1233 // Updates all IpClient-related state concerned with LinkProperties. 1234 // Returns a ProvisioningChange for possibly notifying other interested 1235 // parties that are not fronted by IpClient. setLinkProperties(LinkProperties newLp)1236 private int setLinkProperties(LinkProperties newLp) { 1237 if (mApfFilter != null) { 1238 mApfFilter.setLinkProperties(newLp); 1239 } 1240 if (mIpReachabilityMonitor != null) { 1241 mIpReachabilityMonitor.updateLinkProperties(newLp); 1242 } 1243 1244 int delta = compareProvisioning(mLinkProperties, newLp); 1245 mLinkProperties = new LinkProperties(newLp); 1246 1247 if (delta == PROV_CHANGE_GAINED_PROVISIONING) { 1248 // TODO: Add a proper ProvisionedState and cancel the alarm in 1249 // its enter() method. 1250 mProvisioningTimeoutAlarm.cancel(); 1251 } 1252 1253 return delta; 1254 } 1255 assembleLinkProperties()1256 private LinkProperties assembleLinkProperties() { 1257 // [1] Create a new LinkProperties object to populate. 1258 LinkProperties newLp = new LinkProperties(); 1259 newLp.setInterfaceName(mInterfaceName); 1260 1261 // [2] Pull in data from netlink: 1262 // - IPv4 addresses 1263 // - IPv6 addresses 1264 // - IPv6 routes 1265 // - IPv6 DNS servers 1266 // 1267 // N.B.: this is fundamentally race-prone and should be fixed by 1268 // changing IpClientLinkObserver from a hybrid edge/level model to an 1269 // edge-only model, or by giving IpClient its own netlink socket(s) 1270 // so as to track all required information directly. 1271 LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties(); 1272 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 1273 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 1274 newLp.addRoute(route); 1275 } 1276 addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers()); 1277 newLp.setNat64Prefix(netlinkLinkProperties.getNat64Prefix()); 1278 1279 // [3] Add in data from DHCPv4, if available. 1280 // 1281 // mDhcpResults is never shared with any other owner so we don't have 1282 // to worry about concurrent modification. 1283 if (mDhcpResults != null) { 1284 final List<RouteInfo> routes = 1285 mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName); 1286 for (RouteInfo route : routes) { 1287 newLp.addRoute(route); 1288 } 1289 addAllReachableDnsServers(newLp, mDhcpResults.dnsServers); 1290 newLp.setDomains(mDhcpResults.domains); 1291 1292 if (mDhcpResults.mtu != 0) { 1293 newLp.setMtu(mDhcpResults.mtu); 1294 } 1295 1296 if (mDhcpResults.serverAddress != null) { 1297 mShim.setDhcpServerAddress(newLp, mDhcpResults.serverAddress); 1298 } 1299 1300 final String capportUrl = mDhcpResults.captivePortalApiUrl; 1301 // Uri.parse does no syntax check; do a simple check to eliminate garbage. 1302 // If the URL is still incorrect data fetching will fail later, which is fine. 1303 if (isParseableUrl(capportUrl)) { 1304 NetworkInformationShimImpl.newInstance() 1305 .setCaptivePortalApiUrl(newLp, Uri.parse(capportUrl)); 1306 } 1307 // TODO: also look at the IPv6 RA (netlink) for captive portal URL 1308 } 1309 1310 // [4] Add in TCP buffer sizes and HTTP Proxy config, if available. 1311 if (!TextUtils.isEmpty(mTcpBufferSizes)) { 1312 newLp.setTcpBufferSizes(mTcpBufferSizes); 1313 } 1314 if (mHttpProxy != null) { 1315 newLp.setHttpProxy(mHttpProxy); 1316 } 1317 1318 // [5] Add data from InitialConfiguration 1319 if (mConfiguration != null && mConfiguration.mInitialConfig != null) { 1320 InitialConfiguration config = mConfiguration.mInitialConfig; 1321 // Add InitialConfiguration routes and dns server addresses once all addresses 1322 // specified in the InitialConfiguration have been observed with Netlink. 1323 if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) { 1324 for (IpPrefix prefix : config.directlyConnectedRoutes) { 1325 newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName, RTN_UNICAST)); 1326 } 1327 } 1328 addAllReachableDnsServers(newLp, config.dnsServers); 1329 } 1330 final LinkProperties oldLp = mLinkProperties; 1331 if (DBG) { 1332 Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s", 1333 netlinkLinkProperties, newLp, oldLp)); 1334 } 1335 1336 // TODO: also learn via netlink routes specified by an InitialConfiguration and specified 1337 // from a static IP v4 config instead of manually patching them in in steps [3] and [5]. 1338 return newLp; 1339 } 1340 isParseableUrl(String url)1341 private static boolean isParseableUrl(String url) { 1342 // Verify that a URL has a reasonable format that can be parsed as per the URL constructor. 1343 // This does not use Patterns.WEB_URL as that pattern excludes URLs without TLDs, such as on 1344 // localhost. 1345 if (url == null) return false; 1346 try { 1347 new URL(url); 1348 return true; 1349 } catch (MalformedURLException e) { 1350 return false; 1351 } 1352 } 1353 addAllReachableDnsServers( LinkProperties lp, Iterable<InetAddress> dnses)1354 private static void addAllReachableDnsServers( 1355 LinkProperties lp, Iterable<InetAddress> dnses) { 1356 // TODO: Investigate deleting this reachability check. We should be 1357 // able to pass everything down to netd and let netd do evaluation 1358 // and RFC6724-style sorting. 1359 for (InetAddress dns : dnses) { 1360 if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) { 1361 lp.addDnsServer(dns); 1362 } 1363 } 1364 } 1365 1366 // Returns false if we have lost provisioning, true otherwise. handleLinkPropertiesUpdate(boolean sendCallbacks)1367 private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) { 1368 final LinkProperties newLp = assembleLinkProperties(); 1369 if (Objects.equals(newLp, mLinkProperties)) { 1370 return true; 1371 } 1372 1373 // Either success IPv4 or IPv6 provisioning triggers new LinkProperties update, 1374 // wait for the provisioning completion and record the latency. 1375 mIpProvisioningMetrics.setIPv4ProvisionedLatencyOnFirstTime(newLp.isIpv4Provisioned()); 1376 mIpProvisioningMetrics.setIPv6ProvisionedLatencyOnFirstTime(newLp.isIpv6Provisioned()); 1377 1378 final int delta = setLinkProperties(newLp); 1379 // Most of the attributes stored in the memory store are deduced from 1380 // the link properties, therefore when the properties update the memory 1381 // store record should be updated too. 1382 maybeSaveNetworkToIpMemoryStore(); 1383 if (sendCallbacks) { 1384 dispatchCallback(delta, newLp); 1385 } 1386 return (delta != PROV_CHANGE_LOST_PROVISIONING); 1387 } 1388 1389 @VisibleForTesting removeDoubleQuotes(@onNull String ssid)1390 static String removeDoubleQuotes(@NonNull String ssid) { 1391 final int length = ssid.length(); 1392 if ((length > 1) && (ssid.charAt(0) == '"') && (ssid.charAt(length - 1) == '"')) { 1393 return ssid.substring(1, length - 1); 1394 } 1395 return ssid; 1396 } 1397 getVendorSpecificIEs(@onNull ScanResultInfo scanResultInfo)1398 private List<ByteBuffer> getVendorSpecificIEs(@NonNull ScanResultInfo scanResultInfo) { 1399 ArrayList<ByteBuffer> vendorSpecificPayloadList = new ArrayList<>(); 1400 for (InformationElement ie : scanResultInfo.getInformationElements()) { 1401 if (ie.getId() == VENDOR_SPECIFIC_IE_ID) { 1402 vendorSpecificPayloadList.add(ie.getPayload()); 1403 } 1404 } 1405 return vendorSpecificPayloadList; 1406 } 1407 detectUpstreamHotspotFromVendorIe()1408 private boolean detectUpstreamHotspotFromVendorIe() { 1409 if (mConfiguration.mScanResultInfo == null) return false; 1410 final ScanResultInfo scanResultInfo = mConfiguration.mScanResultInfo; 1411 final String ssid = scanResultInfo.getSsid(); 1412 final List<ByteBuffer> vendorSpecificPayloadList = getVendorSpecificIEs(scanResultInfo); 1413 1414 if (mConfiguration.mDisplayName == null 1415 || !removeDoubleQuotes(mConfiguration.mDisplayName).equals(ssid)) { 1416 return false; 1417 } 1418 1419 for (ByteBuffer payload : vendorSpecificPayloadList) { 1420 byte[] ouiAndType = new byte[4]; 1421 try { 1422 payload.get(ouiAndType); 1423 } catch (BufferUnderflowException e) { 1424 Log.e(mTag, "Couldn't parse vendor specific IE, buffer underflow"); 1425 return false; 1426 } 1427 for (byte[] pattern : METERED_IE_PATTERN_LIST) { 1428 if (Arrays.equals(pattern, ouiAndType)) { 1429 if (DBG) { 1430 Log.d(mTag, "detected upstream hotspot that matches OUI:" 1431 + HexDump.toHexString(ouiAndType)); 1432 } 1433 return true; 1434 } 1435 } 1436 } 1437 return false; 1438 } 1439 handleIPv4Success(DhcpResults dhcpResults)1440 private void handleIPv4Success(DhcpResults dhcpResults) { 1441 mDhcpResults = new DhcpResults(dhcpResults); 1442 final LinkProperties newLp = assembleLinkProperties(); 1443 final int delta = setLinkProperties(newLp); 1444 1445 if (mDhcpResults.vendorInfo == null && detectUpstreamHotspotFromVendorIe()) { 1446 mDhcpResults.vendorInfo = DhcpPacket.VENDOR_INFO_ANDROID_METERED; 1447 } 1448 1449 if (DBG) { 1450 Log.d(mTag, "onNewDhcpResults(" + Objects.toString(mDhcpResults) + ")"); 1451 Log.d(mTag, "handleIPv4Success newLp{" + newLp + "}"); 1452 } 1453 mCallback.onNewDhcpResults(mDhcpResults); 1454 maybeSaveNetworkToIpMemoryStore(); 1455 1456 dispatchCallback(delta, newLp); 1457 } 1458 handleIPv4Failure()1459 private void handleIPv4Failure() { 1460 // TODO: Investigate deleting this clearIPv4Address() call. 1461 // 1462 // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances 1463 // that could trigger a call to this function. If we missed handling 1464 // that message in StartedState for some reason we would still clear 1465 // any addresses upon entry to StoppedState. 1466 mInterfaceCtrl.clearIPv4Address(); 1467 mDhcpResults = null; 1468 if (DBG) { 1469 Log.d(mTag, "onNewDhcpResults(null)"); 1470 } 1471 mCallback.onNewDhcpResults(null); 1472 1473 handleProvisioningFailure(DisconnectCode.DC_PROVISIONING_FAIL); 1474 } 1475 handleProvisioningFailure(final DisconnectCode code)1476 private void handleProvisioningFailure(final DisconnectCode code) { 1477 final LinkProperties newLp = assembleLinkProperties(); 1478 int delta = setLinkProperties(newLp); 1479 // If we've gotten here and we're still not provisioned treat that as 1480 // a total loss of provisioning. 1481 // 1482 // Either (a) static IP configuration failed or (b) DHCPv4 failed AND 1483 // there was no usable IPv6 obtained before a non-zero provisioning 1484 // timeout expired. 1485 // 1486 // Regardless: GAME OVER. 1487 if (delta == PROV_CHANGE_STILL_NOT_PROVISIONED) { 1488 delta = PROV_CHANGE_LOST_PROVISIONING; 1489 } 1490 1491 dispatchCallback(delta, newLp); 1492 if (delta == PROV_CHANGE_LOST_PROVISIONING) { 1493 transitionToStoppingState(code); 1494 } 1495 } 1496 doImmediateProvisioningFailure(int failureType)1497 private void doImmediateProvisioningFailure(int failureType) { 1498 logError("onProvisioningFailure(): %s", failureType); 1499 recordMetric(failureType); 1500 mCallback.onProvisioningFailure(mLinkProperties); 1501 } 1502 startIPv4()1503 private boolean startIPv4() { 1504 // If we have a StaticIpConfiguration attempt to apply it and 1505 // handle the result accordingly. 1506 if (mConfiguration.mStaticIpConfig != null) { 1507 if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) { 1508 handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig)); 1509 } else { 1510 return false; 1511 } 1512 } else { 1513 if (mDhcpClient != null) { 1514 Log.wtf(mTag, "DhcpClient should never be non-null in startIPv4()"); 1515 } 1516 startDhcpClient(); 1517 } 1518 1519 return true; 1520 } 1521 startIPv6()1522 private boolean startIPv6() { 1523 return mInterfaceCtrl.setIPv6PrivacyExtensions(true) 1524 && mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode) 1525 && mInterfaceCtrl.enableIPv6(); 1526 } 1527 applyInitialConfig(InitialConfiguration config)1528 private boolean applyInitialConfig(InitialConfiguration config) { 1529 // TODO: also support specifying a static IPv4 configuration in InitialConfiguration. 1530 for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIpv6)) { 1531 if (!mInterfaceCtrl.addAddress(addr)) return false; 1532 } 1533 1534 return true; 1535 } 1536 startIpReachabilityMonitor()1537 private boolean startIpReachabilityMonitor() { 1538 try { 1539 mIpReachabilityMonitor = new IpReachabilityMonitor( 1540 mContext, 1541 mInterfaceParams, 1542 getHandler(), 1543 mLog, 1544 new IpReachabilityMonitor.Callback() { 1545 @Override 1546 public void notifyLost(InetAddress ip, String logMsg) { 1547 mCallback.onReachabilityLost(logMsg); 1548 } 1549 }, 1550 mConfiguration.mUsingMultinetworkPolicyTracker, 1551 mNetd); 1552 } catch (IllegalArgumentException iae) { 1553 // Failed to start IpReachabilityMonitor. Log it and call 1554 // onProvisioningFailure() immediately. 1555 // 1556 // See http://b/31038971. 1557 logError("IpReachabilityMonitor failure: %s", iae); 1558 mIpReachabilityMonitor = null; 1559 } 1560 1561 return (mIpReachabilityMonitor != null); 1562 } 1563 stopAllIP()1564 private void stopAllIP() { 1565 // We don't need to worry about routes, just addresses, because: 1566 // - disableIpv6() will clear autoconf IPv6 routes as well, and 1567 // - we don't get IPv4 routes from netlink 1568 // so we neither react to nor need to wait for changes in either. 1569 1570 mInterfaceCtrl.disableIPv6(); 1571 mInterfaceCtrl.clearAllAddresses(); 1572 } 1573 maybeSaveNetworkToIpMemoryStore()1574 private void maybeSaveNetworkToIpMemoryStore() { 1575 // TODO : implement this 1576 } 1577 maybeRestoreInterfaceMtu()1578 private void maybeRestoreInterfaceMtu() { 1579 InterfaceParams params = mDependencies.getInterfaceParams(mInterfaceName); 1580 if (params == null) { 1581 Log.w(mTag, "interface: " + mInterfaceName + " is gone"); 1582 return; 1583 } 1584 1585 if (params.index != mInterfaceParams.index) { 1586 Log.w(mTag, "interface: " + mInterfaceName + " has a different index: " + params.index); 1587 return; 1588 } 1589 1590 if (params.defaultMtu == mInterfaceParams.defaultMtu) return; 1591 1592 try { 1593 mNetd.interfaceSetMtu(mInterfaceName, mInterfaceParams.defaultMtu); 1594 } catch (RemoteException | ServiceSpecificException e) { 1595 logError("Couldn't reset MTU on " + mInterfaceName + " from " 1596 + params.defaultMtu + " to " + mInterfaceParams.defaultMtu, e); 1597 } 1598 } 1599 handleUpdateL2Information(@onNull Layer2InformationParcelable info)1600 private void handleUpdateL2Information(@NonNull Layer2InformationParcelable info) { 1601 mL2Key = info.l2Key; 1602 mCluster = info.cluster; 1603 1604 if (info.bssid == null || mCurrentBssid == null) { 1605 Log.wtf(mTag, "bssid in the parcelable or current tracked bssid should be non-null"); 1606 return; 1607 } 1608 1609 // If the BSSID has not changed, there is nothing to do. 1610 if (info.bssid.equals(mCurrentBssid)) return; 1611 1612 if (mIpReachabilityMonitor != null) { 1613 mIpReachabilityMonitor.probeAll(); 1614 } 1615 1616 // Check whether to refresh previous IP lease on L2 roaming happened. 1617 final String ssid = removeDoubleQuotes(mConfiguration.mDisplayName); 1618 if (DHCP_ROAMING_SSID_SET.contains(ssid) && mDhcpClient != null) { 1619 if (DBG) { 1620 Log.d(mTag, "L2 roaming happened from " + mCurrentBssid 1621 + " to " + info.bssid 1622 + " , SSID: " + ssid 1623 + " , starting refresh leased IP address"); 1624 } 1625 mDhcpClient.sendMessage(DhcpClient.CMD_REFRESH_LINKADDRESS); 1626 } 1627 mCurrentBssid = info.bssid; 1628 } 1629 1630 class StoppedState extends State { 1631 @Override enter()1632 public void enter() { 1633 stopAllIP(); 1634 mHasDisabledIPv6OnProvLoss = false; 1635 1636 mLinkObserver.clearInterfaceParams(); 1637 resetLinkProperties(); 1638 if (mStartTimeMillis > 0) { 1639 // Completed a life-cycle; send a final empty LinkProperties 1640 // (cleared in resetLinkProperties() above) and record an event. 1641 mCallback.onLinkPropertiesChange(mLinkProperties); 1642 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE); 1643 mStartTimeMillis = 0; 1644 } 1645 } 1646 1647 @Override processMessage(Message msg)1648 public boolean processMessage(Message msg) { 1649 switch (msg.what) { 1650 case CMD_TERMINATE_AFTER_STOP: 1651 stopStateMachineUpdaters(); 1652 quit(); 1653 break; 1654 1655 case CMD_STOP: 1656 break; 1657 1658 case CMD_START: 1659 mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj; 1660 transitionTo(mClearingIpAddressesState); 1661 break; 1662 1663 case EVENT_NETLINK_LINKPROPERTIES_CHANGED: 1664 handleLinkPropertiesUpdate(NO_CALLBACKS); 1665 break; 1666 1667 case CMD_UPDATE_TCP_BUFFER_SIZES: 1668 mTcpBufferSizes = (String) msg.obj; 1669 handleLinkPropertiesUpdate(NO_CALLBACKS); 1670 break; 1671 1672 case CMD_UPDATE_HTTP_PROXY: 1673 mHttpProxy = (ProxyInfo) msg.obj; 1674 handleLinkPropertiesUpdate(NO_CALLBACKS); 1675 break; 1676 1677 case CMD_UPDATE_L2KEY_CLUSTER: { 1678 final Pair<String, String> args = (Pair<String, String>) msg.obj; 1679 mL2Key = args.first; 1680 mCluster = args.second; 1681 break; 1682 } 1683 1684 case CMD_SET_MULTICAST_FILTER: 1685 mMulticastFiltering = (boolean) msg.obj; 1686 break; 1687 1688 case DhcpClient.CMD_ON_QUIT: 1689 // Everything is already stopped. 1690 logError("Unexpected CMD_ON_QUIT (already stopped)."); 1691 break; 1692 1693 default: 1694 return NOT_HANDLED; 1695 } 1696 1697 mMsgStateLogger.handled(this, getCurrentState()); 1698 return HANDLED; 1699 } 1700 } 1701 1702 class StoppingState extends State { 1703 @Override enter()1704 public void enter() { 1705 if (mDhcpClient == null) { 1706 // There's no DHCPv4 for which to wait; proceed to stopped. 1707 deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED)); 1708 } 1709 1710 // Restore the interface MTU to initial value if it has changed. 1711 maybeRestoreInterfaceMtu(); 1712 } 1713 1714 @Override processMessage(Message msg)1715 public boolean processMessage(Message msg) { 1716 switch (msg.what) { 1717 case CMD_JUMP_STOPPING_TO_STOPPED: 1718 transitionTo(mStoppedState); 1719 break; 1720 1721 case CMD_STOP: 1722 break; 1723 1724 case DhcpClient.CMD_CLEAR_LINKADDRESS: 1725 mInterfaceCtrl.clearIPv4Address(); 1726 break; 1727 1728 case DhcpClient.CMD_ON_QUIT: 1729 mDhcpClient = null; 1730 transitionTo(mStoppedState); 1731 break; 1732 1733 default: 1734 deferMessage(msg); 1735 } 1736 1737 mMsgStateLogger.handled(this, getCurrentState()); 1738 return HANDLED; 1739 } 1740 } 1741 isUsingPreconnection()1742 private boolean isUsingPreconnection() { 1743 return mConfiguration.mEnablePreconnection && mConfiguration.mStaticIpConfig == null; 1744 } 1745 startDhcpClient()1746 private void startDhcpClient() { 1747 // Start DHCPv4. 1748 mDhcpClient = mDependencies.makeDhcpClient(mContext, IpClient.this, mInterfaceParams, 1749 mDependencies.getDhcpClientDependencies(mIpMemoryStore, mIpProvisioningMetrics)); 1750 1751 // If preconnection is enabled, there is no need to ask Wi-Fi to disable powersaving 1752 // during DHCP, because the DHCP handshake will happen during association. In order to 1753 // ensure that future renews still do the DHCP action (if configured), 1754 // registerForPreDhcpNotification is called later when processing the CMD_*_PRECONNECTION 1755 // messages. 1756 if (!isUsingPreconnection()) mDhcpClient.registerForPreDhcpNotification(); 1757 mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP, new DhcpClient.Configuration(mL2Key, 1758 isUsingPreconnection())); 1759 } 1760 1761 class ClearingIpAddressesState extends State { 1762 @Override enter()1763 public void enter() { 1764 // Ensure that interface parameters are fetched on the handler thread so they are 1765 // properly ordered with other events, such as restoring the interface MTU on teardown. 1766 mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName); 1767 if (mInterfaceParams == null) { 1768 logError("Failed to find InterfaceParams for " + mInterfaceName); 1769 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND); 1770 deferMessage(obtainMessage(CMD_STOP, 1771 DisconnectCode.DC_INTERFACE_NOT_FOUND.getNumber())); 1772 return; 1773 } 1774 1775 mLinkObserver.setInterfaceParams(mInterfaceParams); 1776 1777 if (readyToProceed()) { 1778 deferMessage(obtainMessage(CMD_ADDRESSES_CLEARED)); 1779 } else { 1780 // Clear all IPv4 and IPv6 before proceeding to RunningState. 1781 // Clean up any leftover state from an abnormal exit from 1782 // tethering or during an IpClient restart. 1783 stopAllIP(); 1784 } 1785 1786 mCallback.setNeighborDiscoveryOffload(true); 1787 } 1788 1789 @Override processMessage(Message msg)1790 public boolean processMessage(Message msg) { 1791 switch (msg.what) { 1792 case CMD_ADDRESSES_CLEARED: 1793 transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState); 1794 break; 1795 1796 case EVENT_NETLINK_LINKPROPERTIES_CHANGED: 1797 handleLinkPropertiesUpdate(NO_CALLBACKS); 1798 if (readyToProceed()) { 1799 transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState); 1800 } 1801 break; 1802 1803 case CMD_STOP: 1804 case EVENT_PROVISIONING_TIMEOUT: 1805 // Fall through to StartedState. 1806 return NOT_HANDLED; 1807 1808 default: 1809 // It's safe to process messages out of order because the 1810 // only message that can both 1811 // a) be received at this time and 1812 // b) affect provisioning state 1813 // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above). 1814 deferMessage(msg); 1815 } 1816 return HANDLED; 1817 } 1818 readyToProceed()1819 private boolean readyToProceed() { 1820 return !mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address(); 1821 } 1822 } 1823 1824 class PreconnectingState extends State { 1825 @Override enter()1826 public void enter() { 1827 startDhcpClient(); 1828 } 1829 1830 @Override processMessage(Message msg)1831 public boolean processMessage(Message msg) { 1832 switch (msg.what) { 1833 case CMD_COMPLETE_PRECONNECTION: 1834 boolean success = (msg.arg1 == 1); 1835 mDhcpClient.registerForPreDhcpNotification(); 1836 if (!success) { 1837 mDhcpClient.sendMessage(DhcpClient.CMD_ABORT_PRECONNECTION); 1838 } 1839 // The link is ready for use. Advance to running state, start IPv6, etc. 1840 transitionTo(mRunningState); 1841 break; 1842 1843 case DhcpClient.CMD_START_PRECONNECTION: 1844 final Layer2PacketParcelable l2Packet = (Layer2PacketParcelable) msg.obj; 1845 mCallback.onPreconnectionStart(Collections.singletonList(l2Packet)); 1846 break; 1847 1848 case CMD_STOP: 1849 case EVENT_PROVISIONING_TIMEOUT: 1850 // Fall through to StartedState. 1851 return NOT_HANDLED; 1852 1853 default: 1854 deferMessage(msg); 1855 } 1856 return HANDLED; 1857 } 1858 } 1859 1860 class StartedState extends State { 1861 @Override enter()1862 public void enter() { 1863 mIpProvisioningMetrics.reset(); 1864 mStartTimeMillis = SystemClock.elapsedRealtime(); 1865 if (mConfiguration.mProvisioningTimeoutMs > 0) { 1866 final long alarmTime = SystemClock.elapsedRealtime() 1867 + mConfiguration.mProvisioningTimeoutMs; 1868 mProvisioningTimeoutAlarm.schedule(alarmTime); 1869 } 1870 } 1871 1872 @Override exit()1873 public void exit() { 1874 mProvisioningTimeoutAlarm.cancel(); 1875 1876 // Record metrics information once this provisioning has completed due to certain 1877 // reason (normal termination, provisioning timeout, lost provisioning and etc). 1878 mIpProvisioningMetrics.statsWrite(); 1879 } 1880 1881 @Override processMessage(Message msg)1882 public boolean processMessage(Message msg) { 1883 switch (msg.what) { 1884 case CMD_STOP: 1885 transitionToStoppingState(DisconnectCode.forNumber(msg.arg1)); 1886 break; 1887 1888 case CMD_UPDATE_L2KEY_CLUSTER: { 1889 final Pair<String, String> args = (Pair<String, String>) msg.obj; 1890 mL2Key = args.first; 1891 mCluster = args.second; 1892 // TODO : attributes should be saved to the memory store with 1893 // these new values if they differ from the previous ones. 1894 // If the state machine is in pure StartedState, then the values to input 1895 // are not known yet and should be updated when the LinkProperties are updated. 1896 // If the state machine is in RunningState (which is a child of StartedState) 1897 // then the next NUD check should be used to store the new values to avoid 1898 // inputting current values for what may be a different L3 network. 1899 break; 1900 } 1901 1902 case CMD_UPDATE_L2INFORMATION: 1903 handleUpdateL2Information((Layer2InformationParcelable) msg.obj); 1904 break; 1905 1906 case EVENT_PROVISIONING_TIMEOUT: 1907 handleProvisioningFailure(DisconnectCode.DC_PROVISIONING_TIMEOUT); 1908 break; 1909 1910 default: 1911 return NOT_HANDLED; 1912 } 1913 1914 mMsgStateLogger.handled(this, getCurrentState()); 1915 return HANDLED; 1916 } 1917 } 1918 1919 class RunningState extends State { 1920 private ConnectivityPacketTracker mPacketTracker; 1921 private boolean mDhcpActionInFlight; 1922 1923 @Override enter()1924 public void enter() { 1925 ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration(); 1926 apfConfig.apfCapabilities = mConfiguration.mApfCapabilities; 1927 apfConfig.multicastFilter = mMulticastFiltering; 1928 // Get the Configuration for ApfFilter from Context 1929 apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames(); 1930 apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList(); 1931 apfConfig.minRdnssLifetimeSec = mMinRdnssLifetimeSec; 1932 mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback); 1933 // TODO: investigate the effects of any multicast filtering racing/interfering with the 1934 // rest of this IP configuration startup. 1935 if (mApfFilter == null) { 1936 mCallback.setFallbackMulticastFilter(mMulticastFiltering); 1937 } 1938 1939 mPacketTracker = createPacketTracker(); 1940 if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName); 1941 1942 if (mConfiguration.mEnableIPv6 && !startIPv6()) { 1943 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6); 1944 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6); 1945 return; 1946 } 1947 1948 if (mConfiguration.mEnableIPv4 && !isUsingPreconnection() && !startIPv4()) { 1949 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4); 1950 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV4); 1951 return; 1952 } 1953 1954 final InitialConfiguration config = mConfiguration.mInitialConfig; 1955 if ((config != null) && !applyInitialConfig(config)) { 1956 // TODO introduce a new IpManagerEvent constant to distinguish this error case. 1957 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING); 1958 enqueueJumpToStoppingState(DisconnectCode.DC_INVALID_PROVISIONING); 1959 return; 1960 } 1961 1962 if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) { 1963 doImmediateProvisioningFailure( 1964 IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR); 1965 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPREACHABILITYMONITOR); 1966 return; 1967 } 1968 } 1969 1970 @Override exit()1971 public void exit() { 1972 stopDhcpAction(); 1973 1974 if (mIpReachabilityMonitor != null) { 1975 mIpReachabilityMonitor.stop(); 1976 mIpReachabilityMonitor = null; 1977 } 1978 1979 if (mDhcpClient != null) { 1980 mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP); 1981 mDhcpClient.doQuit(); 1982 } 1983 1984 if (mPacketTracker != null) { 1985 mPacketTracker.stop(); 1986 mPacketTracker = null; 1987 } 1988 1989 if (mApfFilter != null) { 1990 mApfFilter.shutdown(); 1991 mApfFilter = null; 1992 } 1993 1994 resetLinkProperties(); 1995 } 1996 enqueueJumpToStoppingState(final DisconnectCode code)1997 private void enqueueJumpToStoppingState(final DisconnectCode code) { 1998 deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING, code.getNumber())); 1999 } 2000 createPacketTracker()2001 private ConnectivityPacketTracker createPacketTracker() { 2002 try { 2003 return new ConnectivityPacketTracker( 2004 getHandler(), mInterfaceParams, mConnectivityPacketLog); 2005 } catch (IllegalArgumentException e) { 2006 return null; 2007 } 2008 } 2009 ensureDhcpAction()2010 private void ensureDhcpAction() { 2011 if (!mDhcpActionInFlight) { 2012 mCallback.onPreDhcpAction(); 2013 mDhcpActionInFlight = true; 2014 final long alarmTime = SystemClock.elapsedRealtime() 2015 + mConfiguration.mRequestedPreDhcpActionMs; 2016 mDhcpActionTimeoutAlarm.schedule(alarmTime); 2017 } 2018 } 2019 stopDhcpAction()2020 private void stopDhcpAction() { 2021 mDhcpActionTimeoutAlarm.cancel(); 2022 if (mDhcpActionInFlight) { 2023 mCallback.onPostDhcpAction(); 2024 mDhcpActionInFlight = false; 2025 } 2026 } 2027 2028 @Override processMessage(Message msg)2029 public boolean processMessage(Message msg) { 2030 switch (msg.what) { 2031 case CMD_JUMP_RUNNING_TO_STOPPING: 2032 case CMD_STOP: 2033 transitionToStoppingState(DisconnectCode.forNumber(msg.arg1)); 2034 break; 2035 2036 case CMD_START: 2037 logError("ALERT: START received in StartedState. Please fix caller."); 2038 break; 2039 2040 case CMD_CONFIRM: 2041 // TODO: Possibly introduce a second type of confirmation 2042 // that both probes (a) on-link neighbors and (b) does 2043 // a DHCPv4 RENEW. We used to do this on Wi-Fi framework 2044 // roams. 2045 if (mIpReachabilityMonitor != null) { 2046 mIpReachabilityMonitor.probeAll(); 2047 } 2048 break; 2049 2050 case EVENT_PRE_DHCP_ACTION_COMPLETE: 2051 // It's possible to reach here if, for example, someone 2052 // calls completedPreDhcpAction() after provisioning with 2053 // a static IP configuration. 2054 if (mDhcpClient != null) { 2055 mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE); 2056 } 2057 break; 2058 2059 case EVENT_NETLINK_LINKPROPERTIES_CHANGED: 2060 // EVENT_NETLINK_LINKPROPERTIES_CHANGED message will be received in both of 2061 // provisioning loss and normal user termination cases (e.g. turn off wifi or 2062 // switch to another wifi ssid), hence, checking the current interface link 2063 // state (down or up) helps distinguish the two cases: if the link state is 2064 // down, provisioning is only lost because the link is being torn down (for 2065 // example when turning off wifi), so treat it as a normal termination. 2066 if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) { 2067 final boolean linkStateUp = (msg.arg1 == ARG_LINKPROP_CHANGED_LINKSTATE_UP); 2068 transitionToStoppingState(linkStateUp ? DisconnectCode.DC_PROVISIONING_FAIL 2069 : DisconnectCode.DC_NORMAL_TERMINATION); 2070 } 2071 break; 2072 2073 case CMD_UPDATE_TCP_BUFFER_SIZES: 2074 mTcpBufferSizes = (String) msg.obj; 2075 // This cannot possibly change provisioning state. 2076 handleLinkPropertiesUpdate(SEND_CALLBACKS); 2077 break; 2078 2079 case CMD_UPDATE_HTTP_PROXY: 2080 mHttpProxy = (ProxyInfo) msg.obj; 2081 // This cannot possibly change provisioning state. 2082 handleLinkPropertiesUpdate(SEND_CALLBACKS); 2083 break; 2084 2085 case CMD_SET_MULTICAST_FILTER: { 2086 mMulticastFiltering = (boolean) msg.obj; 2087 if (mApfFilter != null) { 2088 mApfFilter.setMulticastFilter(mMulticastFiltering); 2089 } else { 2090 mCallback.setFallbackMulticastFilter(mMulticastFiltering); 2091 } 2092 break; 2093 } 2094 2095 case EVENT_READ_PACKET_FILTER_COMPLETE: { 2096 if (mApfFilter != null) { 2097 mApfFilter.setDataSnapshot((byte[]) msg.obj); 2098 } 2099 mApfDataSnapshotComplete.open(); 2100 break; 2101 } 2102 2103 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: { 2104 final int slot = msg.arg1; 2105 2106 if (mApfFilter != null) { 2107 if (msg.obj instanceof NattKeepalivePacketDataParcelable) { 2108 mApfFilter.addNattKeepalivePacketFilter(slot, 2109 (NattKeepalivePacketDataParcelable) msg.obj); 2110 } else if (msg.obj instanceof TcpKeepalivePacketDataParcelable) { 2111 mApfFilter.addTcpKeepalivePacketFilter(slot, 2112 (TcpKeepalivePacketDataParcelable) msg.obj); 2113 } 2114 } 2115 break; 2116 } 2117 2118 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: { 2119 final int slot = msg.arg1; 2120 if (mApfFilter != null) { 2121 mApfFilter.removeKeepalivePacketFilter(slot); 2122 } 2123 break; 2124 } 2125 2126 case EVENT_DHCPACTION_TIMEOUT: 2127 stopDhcpAction(); 2128 break; 2129 2130 case DhcpClient.CMD_PRE_DHCP_ACTION: 2131 if (mConfiguration.mRequestedPreDhcpActionMs > 0) { 2132 ensureDhcpAction(); 2133 } else { 2134 sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE); 2135 } 2136 break; 2137 2138 case DhcpClient.CMD_CLEAR_LINKADDRESS: 2139 mInterfaceCtrl.clearIPv4Address(); 2140 break; 2141 2142 case DhcpClient.CMD_CONFIGURE_LINKADDRESS: { 2143 final LinkAddress ipAddress = (LinkAddress) msg.obj; 2144 if (mInterfaceCtrl.setIPv4Address(ipAddress)) { 2145 mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED); 2146 } else { 2147 logError("Failed to set IPv4 address."); 2148 dispatchCallback(PROV_CHANGE_LOST_PROVISIONING, mLinkProperties); 2149 transitionToStoppingState(DisconnectCode.DC_PROVISIONING_FAIL); 2150 } 2151 break; 2152 } 2153 2154 // This message is only received when: 2155 // 2156 // a) initial address acquisition succeeds, 2157 // b) renew succeeds or is NAK'd, 2158 // c) rebind succeeds or is NAK'd, or 2159 // c) the lease expires, 2160 // 2161 // but never when initial address acquisition fails. The latter 2162 // condition is now governed by the provisioning timeout. 2163 case DhcpClient.CMD_POST_DHCP_ACTION: 2164 stopDhcpAction(); 2165 2166 switch (msg.arg1) { 2167 case DhcpClient.DHCP_SUCCESS: 2168 handleIPv4Success((DhcpResults) msg.obj); 2169 break; 2170 case DhcpClient.DHCP_FAILURE: 2171 handleIPv4Failure(); 2172 break; 2173 default: 2174 logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1); 2175 } 2176 break; 2177 2178 case DhcpClient.CMD_ON_QUIT: 2179 // DHCPv4 quit early for some reason. 2180 logError("Unexpected CMD_ON_QUIT."); 2181 mDhcpClient = null; 2182 break; 2183 2184 default: 2185 return NOT_HANDLED; 2186 } 2187 2188 mMsgStateLogger.handled(this, getCurrentState()); 2189 return HANDLED; 2190 } 2191 } 2192 2193 private static class MessageHandlingLogger { 2194 public String processedInState; 2195 public String receivedInState; 2196 reset()2197 public void reset() { 2198 processedInState = null; 2199 receivedInState = null; 2200 } 2201 handled(State processedIn, IState receivedIn)2202 public void handled(State processedIn, IState receivedIn) { 2203 processedInState = processedIn.getClass().getSimpleName(); 2204 receivedInState = receivedIn.getName(); 2205 } 2206 toString()2207 public String toString() { 2208 return String.format("rcvd_in=%s, proc_in=%s", 2209 receivedInState, processedInState); 2210 } 2211 } 2212 2213 // TODO: extract out into CollectionUtils. any(Iterable<T> coll, Predicate<T> fn)2214 static <T> boolean any(Iterable<T> coll, Predicate<T> fn) { 2215 for (T t : coll) { 2216 if (fn.test(t)) { 2217 return true; 2218 } 2219 } 2220 return false; 2221 } 2222 all(Iterable<T> coll, Predicate<T> fn)2223 static <T> boolean all(Iterable<T> coll, Predicate<T> fn) { 2224 return !any(coll, not(fn)); 2225 } 2226 not(Predicate<T> fn)2227 static <T> Predicate<T> not(Predicate<T> fn) { 2228 return (t) -> !fn.test(t); 2229 } 2230 join(String delimiter, Collection<T> coll)2231 static <T> String join(String delimiter, Collection<T> coll) { 2232 return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter)); 2233 } 2234 find(Iterable<T> coll, Predicate<T> fn)2235 static <T> T find(Iterable<T> coll, Predicate<T> fn) { 2236 for (T t: coll) { 2237 if (fn.test(t)) { 2238 return t; 2239 } 2240 } 2241 return null; 2242 } 2243 findAll(Collection<T> coll, Predicate<T> fn)2244 static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) { 2245 return coll.stream().filter(fn).collect(Collectors.toList()); 2246 } 2247 } 2248