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