1 /* 2 * Copyright (C) 2022 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; 18 19 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; 20 import static android.Manifest.permission.MANAGE_TEST_NETWORKS; 21 import static android.Manifest.permission.NETWORK_SETTINGS; 22 import static android.Manifest.permission.TETHER_PRIVILEGED; 23 import static android.content.pm.PackageManager.FEATURE_WIFI; 24 import static android.net.InetAddresses.parseNumericAddress; 25 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; 26 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; 27 import static android.net.TetheringManager.TETHERING_ETHERNET; 28 import static android.net.TetheringTester.buildTcpPacket; 29 import static android.net.TetheringTester.buildUdpPacket; 30 import static android.net.TetheringTester.isAddressIpv4; 31 import static android.net.TetheringTester.isExpectedIcmpPacket; 32 import static android.net.TetheringTester.isExpectedTcpPacket; 33 import static android.net.TetheringTester.isExpectedUdpPacket; 34 35 import static com.android.net.module.util.HexDump.dumpHexString; 36 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; 37 import static com.android.net.module.util.NetworkStackConstants.TCPHDR_ACK; 38 import static com.android.net.module.util.NetworkStackConstants.TCPHDR_SYN; 39 import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork; 40 import static com.android.testutils.TestPermissionUtil.runAsShell; 41 42 import static org.junit.Assert.assertEquals; 43 import static org.junit.Assert.assertFalse; 44 import static org.junit.Assert.assertNotNull; 45 import static org.junit.Assert.assertNull; 46 import static org.junit.Assert.assertTrue; 47 import static org.junit.Assert.fail; 48 import static org.junit.Assume.assumeFalse; 49 import static org.junit.Assume.assumeTrue; 50 51 import android.content.Context; 52 import android.content.pm.PackageManager; 53 import android.net.EthernetManager.TetheredInterfaceCallback; 54 import android.net.EthernetManager.TetheredInterfaceRequest; 55 import android.net.TetheringManager.StartTetheringCallback; 56 import android.net.TetheringManager.TetheringEventCallback; 57 import android.net.TetheringManager.TetheringRequest; 58 import android.net.TetheringTester.TetheredDevice; 59 import android.net.cts.util.CtsNetUtils; 60 import android.os.Handler; 61 import android.os.HandlerThread; 62 import android.os.SystemClock; 63 import android.util.Log; 64 65 import androidx.annotation.NonNull; 66 import androidx.test.platform.app.InstrumentationRegistry; 67 68 import com.android.modules.utils.build.SdkLevel; 69 import com.android.net.module.util.Struct; 70 import com.android.net.module.util.structs.Ipv6Header; 71 import com.android.testutils.HandlerUtils; 72 import com.android.testutils.TapPacketReader; 73 import com.android.testutils.TestNetworkTracker; 74 75 import org.junit.After; 76 import org.junit.Before; 77 78 import java.io.FileDescriptor; 79 import java.net.Inet4Address; 80 import java.net.Inet6Address; 81 import java.net.InetAddress; 82 import java.net.NetworkInterface; 83 import java.net.SocketException; 84 import java.nio.ByteBuffer; 85 import java.util.ArrayList; 86 import java.util.Arrays; 87 import java.util.Collection; 88 import java.util.Collections; 89 import java.util.List; 90 import java.util.Objects; 91 import java.util.Set; 92 import java.util.concurrent.CompletableFuture; 93 import java.util.concurrent.CountDownLatch; 94 import java.util.concurrent.TimeUnit; 95 import java.util.concurrent.TimeoutException; 96 97 /** 98 * TODO: Common variables or methods shared between CtsEthernetTetheringTest and 99 * MtsEthernetTetheringTest. 100 */ 101 public abstract class EthernetTetheringTestBase { 102 private static final String TAG = EthernetTetheringTestBase.class.getSimpleName(); 103 104 protected static final int TIMEOUT_MS = 5000; 105 // Used to check if any tethering interface is available. Choose 200ms to be request timeout 106 // because the average interface requested time on cuttlefish@acloud is around 10ms. 107 // See TetheredInterfaceRequester.getInterface, isInterfaceForTetheringAvailable. 108 private static final int AVAILABLE_TETHER_IFACE_REQUEST_TIMEOUT_MS = 200; 109 private static final int TETHER_REACHABILITY_ATTEMPTS = 20; 110 protected static final long WAIT_RA_TIMEOUT_MS = 2000; 111 112 // Address and NAT prefix definition. 113 protected static final MacAddress TEST_MAC = MacAddress.fromString("1:2:3:4:5:6"); 114 protected static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/24"); 115 protected static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64"); 116 protected static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8"); 117 protected static final InetAddress TEST_IP6_DNS = parseNumericAddress("2001:db8:1::888"); 118 119 protected static final Inet4Address REMOTE_IP4_ADDR = 120 (Inet4Address) parseNumericAddress("8.8.8.8"); 121 protected static final Inet6Address REMOTE_IP6_ADDR = 122 (Inet6Address) parseNumericAddress("2002:db8:1::515:ca"); 123 // The IPv6 network address translation of REMOTE_IP4_ADDR if pref64::/n is 64:ff9b::/96. 124 // For more information, see TetheringTester#PREF64_IPV4ONLY_ADDR, which assumes a prefix 125 // of 64:ff9b::/96. 126 protected static final Inet6Address REMOTE_NAT64_ADDR = 127 (Inet6Address) parseNumericAddress("64:ff9b::808:808"); 128 129 // LOCAL_PORT is used by public port and private port. Assume port 9876 has not been used yet 130 // before the testing that public port and private port are the same in the testing. Note that 131 // NAT port forwarding could be different between private port and public port. 132 protected static final short LOCAL_PORT = 9876; 133 protected static final short REMOTE_PORT = 433; 134 135 // Payload definition. 136 protected static final ByteBuffer EMPTY_PAYLOAD = ByteBuffer.wrap(new byte[0]); 137 private static final ByteBuffer TEST_REACHABILITY_PAYLOAD = 138 ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa }); 139 protected static final ByteBuffer RX_PAYLOAD = 140 ByteBuffer.wrap(new byte[] { (byte) 0x12, (byte) 0x34 }); 141 protected static final ByteBuffer TX_PAYLOAD = 142 ByteBuffer.wrap(new byte[] { (byte) 0x56, (byte) 0x78 }); 143 144 private static final Context sContext = 145 InstrumentationRegistry.getInstrumentation().getContext(); 146 protected static final EthernetManager sEm = sContext.getSystemService(EthernetManager.class); 147 private static final TetheringManager sTm = sContext.getSystemService(TetheringManager.class); 148 private static final PackageManager sPackageManager = sContext.getPackageManager(); 149 private static final CtsNetUtils sCtsNetUtils = new CtsNetUtils(sContext); 150 private static final List<String> sCallbackErrors = 151 Collections.synchronizedList(new ArrayList<>()); 152 153 // Late initialization in setUp() 154 private boolean mRunTests; 155 private HandlerThread mHandlerThread; 156 private Handler mHandler; 157 private TetheredInterfaceRequester mTetheredInterfaceRequester; 158 159 // Late initialization in initTetheringTester(). 160 private TapPacketReader mUpstreamReader; 161 private TestNetworkTracker mUpstreamTracker; 162 private TestNetworkInterface mDownstreamIface; 163 private TapPacketReader mDownstreamReader; 164 private MyTetheringEventCallback mTetheringEventCallback; 165 getContext()166 public Context getContext() { 167 return sContext; 168 } 169 170 @Before setUp()171 public void setUp() throws Exception { 172 mHandlerThread = new HandlerThread(getClass().getSimpleName()); 173 mHandlerThread.start(); 174 mHandler = new Handler(mHandlerThread.getLooper()); 175 176 mRunTests = isEthernetTetheringSupported(); 177 assumeTrue(mRunTests); 178 179 mTetheredInterfaceRequester = new TetheredInterfaceRequester(); 180 sCallbackErrors.clear(); 181 } 182 isEthernetTetheringSupported()183 private boolean isEthernetTetheringSupported() throws Exception { 184 if (sEm == null) return false; 185 186 return runAsShell(NETWORK_SETTINGS, TETHER_PRIVILEGED, () -> sTm.isTetheringSupported()); 187 } 188 maybeStopTapPacketReader(final TapPacketReader tapPacketReader)189 protected void maybeStopTapPacketReader(final TapPacketReader tapPacketReader) 190 throws Exception { 191 if (tapPacketReader != null) { 192 TapPacketReader reader = tapPacketReader; 193 mHandler.post(() -> reader.stop()); 194 } 195 } 196 maybeCloseTestInterface(final TestNetworkInterface testInterface)197 protected static void maybeCloseTestInterface(final TestNetworkInterface testInterface) 198 throws Exception { 199 if (testInterface != null) { 200 testInterface.getFileDescriptor().close(); 201 Log.d(TAG, "Deleted test interface " + testInterface.getInterfaceName()); 202 } 203 } 204 maybeUnregisterTetheringEventCallback( final MyTetheringEventCallback callback)205 protected static void maybeUnregisterTetheringEventCallback( 206 final MyTetheringEventCallback callback) throws Exception { 207 if (callback != null) { 208 callback.awaitInterfaceUntethered(); 209 callback.unregister(); 210 } 211 } 212 stopEthernetTethering(final MyTetheringEventCallback callback)213 protected void stopEthernetTethering(final MyTetheringEventCallback callback) { 214 runAsShell(TETHER_PRIVILEGED, () -> { 215 sTm.stopTethering(TETHERING_ETHERNET); 216 maybeUnregisterTetheringEventCallback(callback); 217 }); 218 } 219 cleanUp()220 protected void cleanUp() throws Exception { 221 setPreferTestNetworks(false); 222 223 if (mUpstreamTracker != null) { 224 runAsShell(MANAGE_TEST_NETWORKS, () -> { 225 mUpstreamTracker.teardown(); 226 mUpstreamTracker = null; 227 }); 228 } 229 if (mUpstreamReader != null) { 230 TapPacketReader reader = mUpstreamReader; 231 mHandler.post(() -> reader.stop()); 232 mUpstreamReader = null; 233 } 234 235 maybeStopTapPacketReader(mDownstreamReader); 236 mDownstreamReader = null; 237 // To avoid flaky which caused by the next test started but the previous interface is not 238 // untracked from EthernetTracker yet. Just delete the test interface without explicitly 239 // calling TetheringManager#stopTethering could let EthernetTracker untrack the test 240 // interface from server mode before tethering stopped. Thus, awaitInterfaceUntethered 241 // could not only make sure tethering is stopped but also guarantee the test interface is 242 // untracked from EthernetTracker. 243 maybeCloseTestInterface(mDownstreamIface); 244 mDownstreamIface = null; 245 maybeUnregisterTetheringEventCallback(mTetheringEventCallback); 246 mTetheringEventCallback = null; 247 248 runAsShell(NETWORK_SETTINGS, () -> mTetheredInterfaceRequester.release()); 249 setIncludeTestInterfaces(false); 250 } 251 252 @After tearDown()253 public void tearDown() throws Exception { 254 try { 255 if (mRunTests) cleanUp(); 256 } finally { 257 mHandlerThread.quitSafely(); 258 mHandlerThread.join(); 259 } 260 261 if (sCallbackErrors.size() > 0) { 262 fail("Some callbacks had errors: " + sCallbackErrors); 263 } 264 } 265 isInterfaceForTetheringAvailable()266 protected static boolean isInterfaceForTetheringAvailable() throws Exception { 267 // Before T, all ethernet interfaces could be used for server mode. Instead of 268 // waiting timeout, just checking whether the system currently has any 269 // ethernet interface is more reliable. 270 if (!SdkLevel.isAtLeastT()) { 271 return runAsShell(CONNECTIVITY_USE_RESTRICTED_NETWORKS, () -> sEm.isAvailable()); 272 } 273 274 // If previous test case doesn't release tethering interface successfully, the other tests 275 // after that test may be skipped as unexcepted. 276 // TODO: figure out a better way to check default tethering interface existenion. 277 final TetheredInterfaceRequester requester = new TetheredInterfaceRequester(); 278 try { 279 // Use short timeout (200ms) for requesting an existing interface, if any, because 280 // it should reurn faster than requesting a new tethering interface. Using default 281 // timeout (5000ms, TIMEOUT_MS) may make that total testing time is over 1 minute 282 // test module timeout on internal testing. 283 // TODO: if this becomes flaky, consider using default timeout (5000ms) and moving 284 // this check into #setUpOnce. 285 return requester.getInterface(AVAILABLE_TETHER_IFACE_REQUEST_TIMEOUT_MS) != null; 286 } catch (TimeoutException e) { 287 return false; 288 } finally { 289 runAsShell(NETWORK_SETTINGS, () -> { 290 requester.release(); 291 }); 292 } 293 } 294 setIncludeTestInterfaces(boolean include)295 protected static void setIncludeTestInterfaces(boolean include) { 296 runAsShell(NETWORK_SETTINGS, () -> { 297 sEm.setIncludeTestInterfaces(include); 298 }); 299 } 300 setPreferTestNetworks(boolean prefer)301 protected static void setPreferTestNetworks(boolean prefer) { 302 runAsShell(NETWORK_SETTINGS, () -> { 303 sTm.setPreferTestNetworks(prefer); 304 }); 305 } 306 getTetheredInterface()307 protected String getTetheredInterface() throws Exception { 308 return mTetheredInterfaceRequester.getInterface(); 309 } 310 requestTetheredInterface()311 protected CompletableFuture<String> requestTetheredInterface() throws Exception { 312 return mTetheredInterfaceRequester.requestInterface(); 313 } 314 waitForRouterAdvertisement(TapPacketReader reader, String iface, long timeoutMs)315 protected static void waitForRouterAdvertisement(TapPacketReader reader, String iface, 316 long timeoutMs) { 317 final long deadline = SystemClock.uptimeMillis() + timeoutMs; 318 do { 319 byte[] pkt = reader.popPacket(timeoutMs); 320 if (isExpectedIcmpPacket(pkt, true /* hasEth */, false /* isIpv4 */, 321 ICMPV6_ROUTER_ADVERTISEMENT)) { 322 return; 323 } 324 325 timeoutMs = deadline - SystemClock.uptimeMillis(); 326 } while (timeoutMs > 0); 327 fail("Did not receive router advertisement on " + iface + " after " 328 + timeoutMs + "ms idle"); 329 } 330 331 332 protected static final class MyTetheringEventCallback implements TetheringEventCallback { 333 private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1); 334 private final CountDownLatch mTetheringStoppedLatch = new CountDownLatch(1); 335 private final CountDownLatch mLocalOnlyStartedLatch = new CountDownLatch(1); 336 private final CountDownLatch mLocalOnlyStoppedLatch = new CountDownLatch(1); 337 private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1); 338 private final CountDownLatch mUpstreamLatch = new CountDownLatch(1); 339 private final CountDownLatch mCallbackRegisteredLatch = new CountDownLatch(1); 340 private final TetheringInterface mIface; 341 private final Network mExpectedUpstream; 342 343 private final boolean mAcceptAnyUpstream; 344 345 private volatile boolean mInterfaceWasTethered = false; 346 private volatile boolean mInterfaceWasLocalOnly = false; 347 private volatile boolean mUnregistered = false; 348 private volatile Collection<TetheredClient> mClients = null; 349 private volatile Network mUpstream = null; 350 351 // The dnsmasq in R might block netd for 20 seconds, which can also block tethering 352 // enable/disable for 20 seconds. To fix this, changing the timeouts from 5 seconds to 30 353 // seconds. See b/289881008. 354 private static final int EXPANDED_TIMEOUT_MS = 30000; 355 MyTetheringEventCallback(String iface)356 MyTetheringEventCallback(String iface) { 357 mIface = new TetheringInterface(TETHERING_ETHERNET, iface); 358 mExpectedUpstream = null; 359 mAcceptAnyUpstream = true; 360 } 361 MyTetheringEventCallback(String iface, @NonNull Network expectedUpstream)362 MyTetheringEventCallback(String iface, @NonNull Network expectedUpstream) { 363 Objects.requireNonNull(expectedUpstream); 364 mIface = new TetheringInterface(TETHERING_ETHERNET, iface); 365 mExpectedUpstream = expectedUpstream; 366 mAcceptAnyUpstream = false; 367 } 368 unregister()369 public void unregister() { 370 sTm.unregisterTetheringEventCallback(this); 371 mUnregistered = true; 372 } 373 @Override onTetheredInterfacesChanged(List<String> interfaces)374 public void onTetheredInterfacesChanged(List<String> interfaces) { 375 addCallbackError("Should only call callback that takes a Set<TetheringInterface>"); 376 } 377 378 @Override onTetheredInterfacesChanged(Set<TetheringInterface> interfaces)379 public void onTetheredInterfacesChanged(Set<TetheringInterface> interfaces) { 380 // Ignore stale callbacks registered by previous test cases. 381 if (mUnregistered) return; 382 383 if (!mInterfaceWasTethered && interfaces.contains(mIface)) { 384 // This interface is being tethered for the first time. 385 Log.d(TAG, "Tethering started: " + interfaces); 386 mInterfaceWasTethered = true; 387 mTetheringStartedLatch.countDown(); 388 } else if (mInterfaceWasTethered && !interfaces.contains(mIface)) { 389 Log.d(TAG, "Tethering stopped: " + interfaces); 390 mTetheringStoppedLatch.countDown(); 391 } 392 } 393 394 @Override onLocalOnlyInterfacesChanged(List<String> interfaces)395 public void onLocalOnlyInterfacesChanged(List<String> interfaces) { 396 addCallbackError("Should only call callback that takes a Set<TetheringInterface>"); 397 } 398 399 @Override onLocalOnlyInterfacesChanged(Set<TetheringInterface> interfaces)400 public void onLocalOnlyInterfacesChanged(Set<TetheringInterface> interfaces) { 401 // Ignore stale callbacks registered by previous test cases. 402 if (mUnregistered) return; 403 404 if (!mInterfaceWasLocalOnly && interfaces.contains(mIface)) { 405 // This interface is being put into local-only mode for the first time. 406 Log.d(TAG, "Local-only started: " + interfaces); 407 mInterfaceWasLocalOnly = true; 408 mLocalOnlyStartedLatch.countDown(); 409 } else if (mInterfaceWasLocalOnly && !interfaces.contains(mIface)) { 410 Log.d(TAG, "Local-only stopped: " + interfaces); 411 mLocalOnlyStoppedLatch.countDown(); 412 } 413 } 414 awaitInterfaceTethered()415 public void awaitInterfaceTethered() throws Exception { 416 assertTrue("Ethernet not tethered after " + EXPANDED_TIMEOUT_MS + "ms", 417 mTetheringStartedLatch.await(EXPANDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 418 } 419 awaitInterfaceLocalOnly()420 public void awaitInterfaceLocalOnly() throws Exception { 421 assertTrue("Ethernet not local-only after " + EXPANDED_TIMEOUT_MS + "ms", 422 mLocalOnlyStartedLatch.await(EXPANDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 423 } 424 425 // Used to check if the callback has registered. When the callback is registered, 426 // onSupportedTetheringTypes is celled in onCallbackStarted(). After 427 // onSupportedTetheringTypes called, drop the permission for registering callback. 428 // See MyTetheringEventCallback#register, TetheringManager#onCallbackStarted. 429 @Override onSupportedTetheringTypes(Set<Integer> supportedTypes)430 public void onSupportedTetheringTypes(Set<Integer> supportedTypes) { 431 // Used to check callback registered. 432 mCallbackRegisteredLatch.countDown(); 433 } 434 awaitCallbackRegistered()435 public void awaitCallbackRegistered() throws Exception { 436 if (!mCallbackRegisteredLatch.await(EXPANDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 437 fail("Did not receive callback registered signal after " + EXPANDED_TIMEOUT_MS 438 + "ms"); 439 } 440 } 441 awaitInterfaceUntethered()442 public void awaitInterfaceUntethered() throws Exception { 443 // Don't block teardown if the interface was never tethered. 444 // This is racy because the interface might become tethered right after this check, but 445 // that can only happen in tearDown if startTethering timed out, which likely means 446 // the test has already failed. 447 if (!mInterfaceWasTethered && !mInterfaceWasLocalOnly) return; 448 449 if (mInterfaceWasTethered) { 450 assertTrue(mIface + " not untethered after " + EXPANDED_TIMEOUT_MS + "ms", 451 mTetheringStoppedLatch.await(EXPANDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 452 } else if (mInterfaceWasLocalOnly) { 453 assertTrue(mIface + " not untethered after " + EXPANDED_TIMEOUT_MS + "ms", 454 mLocalOnlyStoppedLatch.await(EXPANDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 455 } else { 456 fail(mIface + " cannot be both tethered and local-only. Update this test class."); 457 } 458 } 459 460 @Override onError(String ifName, int error)461 public void onError(String ifName, int error) { 462 // Ignore stale callbacks registered by previous test cases. 463 if (mUnregistered) return; 464 465 addCallbackError("TetheringEventCallback got error:" + error + " on iface " + ifName); 466 } 467 468 @Override onClientsChanged(Collection<TetheredClient> clients)469 public void onClientsChanged(Collection<TetheredClient> clients) { 470 // Ignore stale callbacks registered by previous test cases. 471 if (mUnregistered) return; 472 473 Log.d(TAG, "Got clients changed: " + clients); 474 mClients = clients; 475 if (clients.size() > 0) { 476 mClientConnectedLatch.countDown(); 477 } 478 } 479 awaitClientConnected()480 public Collection<TetheredClient> awaitClientConnected() throws Exception { 481 assertTrue("Did not receive client connected callback after " 482 + EXPANDED_TIMEOUT_MS + "ms", 483 mClientConnectedLatch.await(EXPANDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 484 return mClients; 485 } 486 487 @Override onUpstreamChanged(Network network)488 public void onUpstreamChanged(Network network) { 489 // Ignore stale callbacks registered by previous test cases. 490 if (mUnregistered) return; 491 492 Log.d(TAG, "Got upstream changed: " + network); 493 mUpstream = network; 494 // The callback always updates the current tethering status when it's first registered. 495 // If the caller registers the callback before tethering starts, the null upstream 496 // would be updated. Filtering out the null case because it's not a valid upstream that 497 // we care about. 498 if (mUpstream == null) return; 499 if (mAcceptAnyUpstream || Objects.equals(mUpstream, mExpectedUpstream)) { 500 mUpstreamLatch.countDown(); 501 } 502 } 503 awaitUpstreamChanged(boolean throwTimeoutException)504 public Network awaitUpstreamChanged(boolean throwTimeoutException) throws Exception { 505 if (!mUpstreamLatch.await(EXPANDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 506 final String errorMessage = "Did not receive upstream " 507 + (mAcceptAnyUpstream ? "any" : mExpectedUpstream) 508 + " callback after " + EXPANDED_TIMEOUT_MS + "ms"; 509 510 if (throwTimeoutException) { 511 throw new TimeoutException(errorMessage); 512 } else { 513 fail(errorMessage); 514 } 515 } 516 return mUpstream; 517 } 518 } 519 addCallbackError(String error)520 private static void addCallbackError(String error) { 521 Log.e(TAG, error); 522 sCallbackErrors.add(error); 523 } 524 enableEthernetTethering(String iface, TetheringRequest request, Network expectedUpstream)525 protected static MyTetheringEventCallback enableEthernetTethering(String iface, 526 TetheringRequest request, Network expectedUpstream) throws Exception { 527 // Enable ethernet tethering with null expectedUpstream means the test accept any upstream 528 // after etherent tethering started. 529 final MyTetheringEventCallback callback; 530 if (expectedUpstream != null) { 531 callback = new MyTetheringEventCallback(iface, expectedUpstream); 532 } else { 533 callback = new MyTetheringEventCallback(iface); 534 } 535 runAsShell(NETWORK_SETTINGS, () -> { 536 sTm.registerTetheringEventCallback(c -> c.run() /* executor */, callback); 537 // Need to hold the shell permission until callback is registered. This helps to avoid 538 // the test become flaky. 539 callback.awaitCallbackRegistered(); 540 }); 541 final CountDownLatch tetheringStartedLatch = new CountDownLatch(1); 542 StartTetheringCallback startTetheringCallback = new StartTetheringCallback() { 543 @Override 544 public void onTetheringStarted() { 545 Log.d(TAG, "Ethernet tethering started"); 546 tetheringStartedLatch.countDown(); 547 } 548 549 @Override 550 public void onTetheringFailed(int resultCode) { 551 addCallbackError("Unexpectedly got onTetheringFailed"); 552 } 553 }; 554 Log.d(TAG, "Starting Ethernet tethering"); 555 runAsShell(TETHER_PRIVILEGED, () -> { 556 sTm.startTethering(request, c -> c.run() /* executor */, startTetheringCallback); 557 // Binder call is an async call. Need to hold the shell permission until tethering 558 // started. This helps to avoid the test become flaky. 559 if (!tetheringStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 560 fail("Did not receive tethering started callback after " + TIMEOUT_MS + "ms"); 561 } 562 }); 563 564 final int connectivityType = request.getConnectivityScope(); 565 switch (connectivityType) { 566 case CONNECTIVITY_SCOPE_GLOBAL: 567 callback.awaitInterfaceTethered(); 568 break; 569 case CONNECTIVITY_SCOPE_LOCAL: 570 callback.awaitInterfaceLocalOnly(); 571 break; 572 default: 573 fail("Unexpected connectivity type requested: " + connectivityType); 574 } 575 576 return callback; 577 } 578 enableEthernetTethering(String iface, Network expectedUpstream)579 protected static MyTetheringEventCallback enableEthernetTethering(String iface, 580 Network expectedUpstream) throws Exception { 581 return enableEthernetTethering(iface, 582 new TetheringRequest.Builder(TETHERING_ETHERNET) 583 .setShouldShowEntitlementUi(false).build(), expectedUpstream); 584 } 585 getMTU(TestNetworkInterface iface)586 protected int getMTU(TestNetworkInterface iface) throws SocketException { 587 NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName()); 588 assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif); 589 return nif.getMTU(); 590 } 591 makePacketReader(final TestNetworkInterface iface)592 protected TapPacketReader makePacketReader(final TestNetworkInterface iface) throws Exception { 593 FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor(); 594 return makePacketReader(fd, getMTU(iface)); 595 } 596 makePacketReader(FileDescriptor fd, int mtu)597 protected TapPacketReader makePacketReader(FileDescriptor fd, int mtu) { 598 final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu); 599 mHandler.post(() -> reader.start()); 600 HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); 601 return reader; 602 } 603 604 protected static final class TetheredInterfaceRequester implements TetheredInterfaceCallback { 605 private TetheredInterfaceRequest mRequest; 606 private final CompletableFuture<String> mFuture = new CompletableFuture<>(); 607 608 @Override onAvailable(String iface)609 public void onAvailable(String iface) { 610 Log.d(TAG, "Ethernet interface available: " + iface); 611 mFuture.complete(iface); 612 } 613 614 @Override onUnavailable()615 public void onUnavailable() { 616 mFuture.completeExceptionally(new IllegalStateException("onUnavailable received")); 617 } 618 requestInterface()619 public CompletableFuture<String> requestInterface() { 620 assertNull("BUG: more than one tethered interface request", mRequest); 621 Log.d(TAG, "Requesting tethered interface"); 622 mRequest = runAsShell(NETWORK_SETTINGS, () -> 623 sEm.requestTetheredInterface(c -> c.run() /* executor */, this)); 624 return mFuture; 625 } 626 getInterface(int timeout)627 public String getInterface(int timeout) throws Exception { 628 return requestInterface().get(timeout, TimeUnit.MILLISECONDS); 629 } 630 getInterface()631 public String getInterface() throws Exception { 632 return getInterface(TIMEOUT_MS); 633 } 634 release()635 public void release() { 636 if (mRequest != null) { 637 mFuture.obtrudeException(new IllegalStateException("Request already released")); 638 mRequest.release(); 639 mRequest = null; 640 } 641 } 642 } 643 createTestInterface()644 protected static TestNetworkInterface createTestInterface() throws Exception { 645 TestNetworkManager tnm = runAsShell(MANAGE_TEST_NETWORKS, () -> 646 sContext.getSystemService(TestNetworkManager.class)); 647 TestNetworkInterface iface = runAsShell(MANAGE_TEST_NETWORKS, () -> 648 tnm.createTapInterface()); 649 Log.d(TAG, "Created test interface " + iface.getInterfaceName()); 650 return iface; 651 } 652 createTestUpstream(final List<LinkAddress> addresses, final List<InetAddress> dnses)653 protected TestNetworkTracker createTestUpstream(final List<LinkAddress> addresses, 654 final List<InetAddress> dnses) throws Exception { 655 setPreferTestNetworks(true); 656 657 final LinkProperties lp = new LinkProperties(); 658 lp.setLinkAddresses(addresses); 659 lp.setDnsServers(dnses); 660 661 return runAsShell(MANAGE_TEST_NETWORKS, () -> initTestNetwork(sContext, lp, TIMEOUT_MS)); 662 } 663 sendDownloadPacketUdp(@onNull final InetAddress srcIp, @NonNull final InetAddress dstIp, @NonNull final TetheringTester tester, boolean is6To4)664 protected void sendDownloadPacketUdp(@NonNull final InetAddress srcIp, 665 @NonNull final InetAddress dstIp, @NonNull final TetheringTester tester, 666 boolean is6To4) throws Exception { 667 if (is6To4) { 668 assertFalse("CLAT download test must sends IPv6 packet", isAddressIpv4(srcIp, dstIp)); 669 } 670 671 // Expected received UDP packet IP protocol. While testing CLAT (is6To4 = true), the packet 672 // on downstream must be IPv4. Otherwise, the IP protocol of test packet is the same on 673 // both downstream and upstream. 674 final boolean isIpv4 = is6To4 ? true : isAddressIpv4(srcIp, dstIp); 675 676 final ByteBuffer testPacket = buildUdpPacket(srcIp, dstIp, REMOTE_PORT /* srcPort */, 677 LOCAL_PORT /* dstPort */, RX_PAYLOAD); 678 tester.verifyDownload(testPacket, p -> { 679 Log.d(TAG, "Packet in downstream: " + dumpHexString(p)); 680 return isExpectedUdpPacket(p, true /* hasEther */, isIpv4, RX_PAYLOAD); 681 }); 682 } 683 sendUploadPacketUdp(@onNull final MacAddress srcMac, @NonNull final MacAddress dstMac, @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp, @NonNull final TetheringTester tester, boolean is4To6)684 protected void sendUploadPacketUdp(@NonNull final MacAddress srcMac, 685 @NonNull final MacAddress dstMac, @NonNull final InetAddress srcIp, 686 @NonNull final InetAddress dstIp, @NonNull final TetheringTester tester, 687 boolean is4To6) throws Exception { 688 if (is4To6) { 689 assertTrue("CLAT upload test must sends IPv4 packet", isAddressIpv4(srcIp, dstIp)); 690 } 691 692 // Expected received UDP packet IP protocol. While testing CLAT (is4To6 = true), the packet 693 // on upstream must be IPv6. Otherwise, the IP protocol of test packet is the same on 694 // both downstream and upstream. 695 final boolean isIpv4 = is4To6 ? false : isAddressIpv4(srcIp, dstIp); 696 697 final ByteBuffer testPacket = buildUdpPacket(srcMac, dstMac, srcIp, dstIp, 698 LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, TX_PAYLOAD); 699 tester.verifyUpload(testPacket, p -> { 700 Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); 701 return isExpectedUdpPacket(p, false /* hasEther */, isIpv4, TX_PAYLOAD); 702 }); 703 } 704 sendDownloadPacketTcp(@onNull final InetAddress srcIp, @NonNull final InetAddress dstIp, short seq, short ack, byte tcpFlags, @NonNull final ByteBuffer payload, @NonNull final TetheringTester tester, boolean is6To4)705 protected void sendDownloadPacketTcp(@NonNull final InetAddress srcIp, 706 @NonNull final InetAddress dstIp, short seq, short ack, byte tcpFlags, 707 @NonNull final ByteBuffer payload, @NonNull final TetheringTester tester, 708 boolean is6To4) throws Exception { 709 if (is6To4) { 710 assertFalse("CLAT download test must sends IPv6 packet", isAddressIpv4(srcIp, dstIp)); 711 } 712 713 // Expected received TCP packet IP protocol. While testing CLAT (is6To4 = true), the packet 714 // on downstream must be IPv4. Otherwise, the IP protocol of test packet is the same on 715 // both downstream and upstream. 716 final boolean isIpv4 = is6To4 ? true : isAddressIpv4(srcIp, dstIp); 717 718 final ByteBuffer testPacket = buildTcpPacket(null /* srcMac */, null /* dstMac */, 719 srcIp, dstIp, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */, seq, ack, 720 tcpFlags, payload); 721 tester.verifyDownload(testPacket, p -> { 722 Log.d(TAG, "Packet in downstream: " + dumpHexString(p)); 723 724 return isExpectedTcpPacket(p, true /* hasEther */, isIpv4, seq, payload); 725 }); 726 } 727 sendUploadPacketTcp(@onNull final MacAddress srcMac, @NonNull final MacAddress dstMac, @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp, short seq, short ack, byte tcpFlags, @NonNull final ByteBuffer payload, @NonNull final TetheringTester tester, boolean is4To6)728 protected void sendUploadPacketTcp(@NonNull final MacAddress srcMac, 729 @NonNull final MacAddress dstMac, @NonNull final InetAddress srcIp, 730 @NonNull final InetAddress dstIp, short seq, short ack, byte tcpFlags, 731 @NonNull final ByteBuffer payload, @NonNull final TetheringTester tester, 732 boolean is4To6) throws Exception { 733 if (is4To6) { 734 assertTrue("CLAT upload test must sends IPv4 packet", isAddressIpv4(srcIp, dstIp)); 735 } 736 737 // Expected received TCP packet IP protocol. While testing CLAT (is4To6 = true), the packet 738 // on upstream must be IPv6. Otherwise, the IP protocol of test packet is the same on 739 // both downstream and upstream. 740 final boolean isIpv4 = is4To6 ? false : isAddressIpv4(srcIp, dstIp); 741 742 final ByteBuffer testPacket = buildTcpPacket(srcMac, dstMac, srcIp, dstIp, 743 LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, seq, ack, tcpFlags, 744 payload); 745 tester.verifyUpload(testPacket, p -> { 746 Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); 747 748 return isExpectedTcpPacket(p, false /* hasEther */, isIpv4, seq, payload); 749 }); 750 } 751 runTcpTest( @onNull final MacAddress uploadSrcMac, @NonNull final MacAddress uploadDstMac, @NonNull final InetAddress uploadSrcIp, @NonNull final InetAddress uploadDstIp, @NonNull final InetAddress downloadSrcIp, @NonNull final InetAddress downloadDstIp, @NonNull final TetheringTester tester, boolean isClat)752 protected void runTcpTest( 753 @NonNull final MacAddress uploadSrcMac, @NonNull final MacAddress uploadDstMac, 754 @NonNull final InetAddress uploadSrcIp, @NonNull final InetAddress uploadDstIp, 755 @NonNull final InetAddress downloadSrcIp, @NonNull final InetAddress downloadDstIp, 756 @NonNull final TetheringTester tester, boolean isClat) throws Exception { 757 // Three way handshake and data transfer. 758 // 759 // Server (base seq = 2000) Client (base seq = 1000) 760 // | | 761 // | [1] [SYN] SEQ = 1000 | 762 // |<---------------------------------------------------------| - 763 // | | ^ 764 // | [2] [SYN + ACK] SEQ = 2000, ACK = 1000+1 | | 765 // |--------------------------------------------------------->| three way handshake 766 // | | | 767 // | [3] [ACK] SEQ = 1001, ACK = 2000+1 | v 768 // |<---------------------------------------------------------| - 769 // | | ^ 770 // | [4] [ACK] SEQ = 1001, ACK = 2001, 2 byte payload | | 771 // |<---------------------------------------------------------| data transfer 772 // | | | 773 // | [5] [ACK] SEQ = 2001, ACK = 1001+2, 2 byte payload | v 774 // |--------------------------------------------------------->| - 775 // | | 776 // 777 778 // This test can only verify the packets are transferred end to end but TCP state. 779 // TODO: verify TCP state change via /proc/net/nf_conntrack or netlink conntrack event. 780 // [1] [UPLOAD] [SYN]: SEQ = 1000 781 sendUploadPacketTcp(uploadSrcMac, uploadDstMac, uploadSrcIp, uploadDstIp, 782 (short) 1000 /* seq */, (short) 0 /* ack */, TCPHDR_SYN, EMPTY_PAYLOAD, 783 tester, isClat /* is4To6 */); 784 785 // [2] [DONWLOAD] [SYN + ACK]: SEQ = 2000, ACK = 1001 786 sendDownloadPacketTcp(downloadSrcIp, downloadDstIp, (short) 2000 /* seq */, 787 (short) 1001 /* ack */, (byte) ((TCPHDR_SYN | TCPHDR_ACK) & 0xff), EMPTY_PAYLOAD, 788 tester, isClat /* is6To4 */); 789 790 // [3] [UPLOAD] [ACK]: SEQ = 1001, ACK = 2001 791 sendUploadPacketTcp(uploadSrcMac, uploadDstMac, uploadSrcIp, uploadDstIp, 792 (short) 1001 /* seq */, (short) 2001 /* ack */, TCPHDR_ACK, EMPTY_PAYLOAD, tester, 793 isClat /* is4To6 */); 794 795 // [4] [UPLOAD] [ACK]: SEQ = 1001, ACK = 2001, 2 byte payload 796 sendUploadPacketTcp(uploadSrcMac, uploadDstMac, uploadSrcIp, uploadDstIp, 797 (short) 1001 /* seq */, (short) 2001 /* ack */, TCPHDR_ACK, TX_PAYLOAD, 798 tester, isClat /* is4To6 */); 799 800 // [5] [DONWLOAD] [ACK]: SEQ = 2001, ACK = 1003, 2 byte payload 801 sendDownloadPacketTcp(downloadSrcIp, downloadDstIp, (short) 2001 /* seq */, 802 (short) 1003 /* ack */, TCPHDR_ACK, RX_PAYLOAD, tester, isClat /* is6To4 */); 803 804 // TODO: test BPF offload maps. 805 } 806 807 // TODO: remove ipv4 verification (is4To6 = false) once upstream connected notification race is 808 // fixed. See #runUdp4Test. 809 // 810 // This function sends a probe packet to downstream interface and exam the result from upstream 811 // interface to make sure ipv4 tethering is ready. Return the entire packet which received from 812 // upstream interface. 813 @NonNull probeV4TetheringConnectivity(TetheringTester tester, TetheredDevice tethered, boolean is4To6)814 protected byte[] probeV4TetheringConnectivity(TetheringTester tester, TetheredDevice tethered, 815 boolean is4To6) throws Exception { 816 final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr, 817 tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */, 818 REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, 819 TEST_REACHABILITY_PAYLOAD); 820 821 // Send a UDP packet from client and check the packet can be found on upstream interface. 822 for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) { 823 byte[] expectedPacket = tester.testUpload(probePacket, p -> { 824 Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); 825 // If is4To6 is true, the ipv4 probe packet would be translated to ipv6 by Clat and 826 // would see this translated ipv6 packet in upstream interface. 827 return isExpectedUdpPacket(p, false /* hasEther */, !is4To6 /* isIpv4 */, 828 TEST_REACHABILITY_PAYLOAD); 829 }); 830 if (expectedPacket != null) return expectedPacket; 831 } 832 833 fail("Can't verify " + (is4To6 ? "ipv4 to ipv6" : "ipv4") + " tethering connectivity after " 834 + TETHER_REACHABILITY_ATTEMPTS + " attempts"); 835 return null; 836 } 837 838 // TODO: remove triggering upstream reselection once test network can replace selected upstream 839 // network in Tethering module. maybeRetryTestedUpstreamChanged(final Network expectedUpstream, final TimeoutException fallbackException)840 private void maybeRetryTestedUpstreamChanged(final Network expectedUpstream, 841 final TimeoutException fallbackException) throws Exception { 842 // Fall back original exception because no way to reselect if there is no WIFI feature. 843 assertTrue(fallbackException.toString(), sPackageManager.hasSystemFeature(FEATURE_WIFI)); 844 845 // Try to toggle wifi network, if any, to reselect upstream network via default network 846 // switching. Because test network has higher priority than internet network, this can 847 // help selecting test network to be upstream network for testing. This tries to avoid 848 // the flaky upstream selection under multinetwork environment. Internet and test network 849 // upstream changed event order is not guaranteed. Once tethering selects non-test 850 // upstream {wifi, ..}, test network won't be selected anymore. If too many test cases 851 // trigger the reselection, the total test time may over test suite 1 minmute timeout. 852 // Probably need to disable/restore all internet networks in a common place of test 853 // process. Currently, EthernetTetheringTest is part of CTS test which needs wifi network 854 // connection if device has wifi feature. 855 // See Tethering#chooseUpstreamType 856 // TODO: toggle cellular network if the device has no WIFI feature. 857 Log.d(TAG, "Toggle WIFI to retry upstream selection"); 858 sCtsNetUtils.disableWifi(); 859 sCtsNetUtils.ensureWifiConnected(); 860 861 // Wait for expected upstream. 862 final CompletableFuture<Network> future = new CompletableFuture<>(); 863 final TetheringEventCallback callback = new TetheringEventCallback() { 864 @Override 865 public void onUpstreamChanged(Network network) { 866 Log.d(TAG, "Got upstream changed: " + network); 867 if (Objects.equals(expectedUpstream, network)) { 868 future.complete(network); 869 } 870 } 871 }; 872 try { 873 sTm.registerTetheringEventCallback(mHandler::post, callback); 874 assertEquals("onUpstreamChanged for unexpected network", expectedUpstream, 875 future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 876 } catch (TimeoutException e) { 877 throw new AssertionError("Did not receive upstream " + expectedUpstream 878 + " callback after " + TIMEOUT_MS + "ms"); 879 } finally { 880 sTm.unregisterTetheringEventCallback(callback); 881 } 882 } 883 initTetheringTester(List<LinkAddress> upstreamAddresses, List<InetAddress> upstreamDnses)884 protected TetheringTester initTetheringTester(List<LinkAddress> upstreamAddresses, 885 List<InetAddress> upstreamDnses) throws Exception { 886 assumeFalse(isInterfaceForTetheringAvailable()); 887 888 // MyTetheringEventCallback currently only support await first available upstream. Tethering 889 // may select internet network as upstream if test network is not available and not be 890 // preferred yet. Create test upstream network before enable tethering. 891 mUpstreamTracker = createTestUpstream(upstreamAddresses, upstreamDnses); 892 893 mDownstreamIface = createTestInterface(); 894 setIncludeTestInterfaces(true); 895 896 // Make sure EtherentTracker use "mDownstreamIface" as server mode interface. 897 assertEquals("TetheredInterfaceCallback for unexpected interface", 898 mDownstreamIface.getInterfaceName(), mTetheredInterfaceRequester.getInterface()); 899 900 mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(), 901 mUpstreamTracker.getNetwork()); 902 903 try { 904 assertEquals("onUpstreamChanged for test network", mUpstreamTracker.getNetwork(), 905 mTetheringEventCallback.awaitUpstreamChanged( 906 true /* throwTimeoutException */)); 907 } catch (TimeoutException e) { 908 // Due to race condition inside tethering module, test network may not be selected as 909 // tethering upstream. Force tethering retry upstream if possible. If it is not 910 // possible to retry, fail the test with the original timeout exception. 911 maybeRetryTestedUpstreamChanged(mUpstreamTracker.getNetwork(), e); 912 } 913 914 mDownstreamReader = makePacketReader(mDownstreamIface); 915 mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface()); 916 917 final ConnectivityManager cm = sContext.getSystemService(ConnectivityManager.class); 918 // Currently tethering don't have API to tell when ipv6 tethering is available. Thus, make 919 // sure tethering already have ipv6 connectivity before testing. 920 if (cm.getLinkProperties(mUpstreamTracker.getNetwork()).hasGlobalIpv6Address()) { 921 waitForRouterAdvertisement(mDownstreamReader, mDownstreamIface.getInterfaceName(), 922 WAIT_RA_TIMEOUT_MS); 923 } 924 925 return new TetheringTester(mDownstreamReader, mUpstreamReader); 926 } 927 928 @NonNull getClatIpv6Address(TetheringTester tester, TetheredDevice tethered)929 protected Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered) 930 throws Exception { 931 // Send an IPv4 UDP packet from client and check that a CLAT translated IPv6 UDP packet can 932 // be found on upstream interface. Get CLAT IPv6 address from the CLAT translated IPv6 UDP 933 // packet. 934 byte[] expectedPacket = probeV4TetheringConnectivity(tester, tethered, true /* is4To6 */); 935 936 // Above has guaranteed that the found packet is an IPv6 packet without ether header. 937 return Struct.parse(Ipv6Header.class, ByteBuffer.wrap(expectedPacket)).srcIp; 938 } 939 toList(T... array)940 protected <T> List<T> toList(T... array) { 941 return Arrays.asList(array); 942 } 943 } 944