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