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