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