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