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