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