• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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