• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.ACCESS_NETWORK_STATE;
20 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
21 import static android.Manifest.permission.DUMP;
22 import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
23 import static android.Manifest.permission.NETWORK_SETTINGS;
24 import static android.Manifest.permission.TETHER_PRIVILEGED;
25 import static android.net.InetAddresses.parseNumericAddress;
26 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
27 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
28 import static android.net.TetheringManager.TETHERING_ETHERNET;
29 import static android.net.TetheringTester.RemoteResponder;
30 import static android.system.OsConstants.IPPROTO_ICMPV6;
31 import static android.system.OsConstants.IPPROTO_IP;
32 import static android.system.OsConstants.IPPROTO_UDP;
33 
34 import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
35 import static com.android.net.module.util.HexDump.dumpHexString;
36 import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
37 import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
38 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
39 import static com.android.testutils.DeviceInfoUtils.KVersion;
40 import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
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.app.UiAutomation;
52 import android.content.Context;
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.os.Build;
60 import android.os.Handler;
61 import android.os.HandlerThread;
62 import android.os.SystemClock;
63 import android.os.SystemProperties;
64 import android.os.VintfRuntimeInfo;
65 import android.text.TextUtils;
66 import android.util.Base64;
67 import android.util.Log;
68 import android.util.Pair;
69 
70 import androidx.annotation.NonNull;
71 import androidx.annotation.Nullable;
72 import androidx.test.InstrumentationRegistry;
73 import androidx.test.filters.MediumTest;
74 import androidx.test.runner.AndroidJUnit4;
75 
76 import com.android.net.module.util.PacketBuilder;
77 import com.android.net.module.util.Struct;
78 import com.android.net.module.util.bpf.Tether4Key;
79 import com.android.net.module.util.bpf.Tether4Value;
80 import com.android.net.module.util.bpf.TetherStatsKey;
81 import com.android.net.module.util.bpf.TetherStatsValue;
82 import com.android.net.module.util.structs.EthernetHeader;
83 import com.android.net.module.util.structs.Icmpv6Header;
84 import com.android.net.module.util.structs.Ipv4Header;
85 import com.android.net.module.util.structs.Ipv6Header;
86 import com.android.net.module.util.structs.UdpHeader;
87 import com.android.testutils.DevSdkIgnoreRule;
88 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
89 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
90 import com.android.testutils.DeviceInfoUtils;
91 import com.android.testutils.DumpTestUtils;
92 import com.android.testutils.HandlerUtils;
93 import com.android.testutils.TapPacketReader;
94 import com.android.testutils.TestNetworkTracker;
95 
96 import org.junit.After;
97 import org.junit.Before;
98 import org.junit.Rule;
99 import org.junit.Test;
100 import org.junit.runner.RunWith;
101 
102 import java.io.FileDescriptor;
103 import java.net.Inet4Address;
104 import java.net.InetAddress;
105 import java.net.InterfaceAddress;
106 import java.net.NetworkInterface;
107 import java.net.SocketException;
108 import java.nio.ByteBuffer;
109 import java.nio.ByteOrder;
110 import java.util.Arrays;
111 import java.util.Collection;
112 import java.util.HashMap;
113 import java.util.List;
114 import java.util.Map;
115 import java.util.Objects;
116 import java.util.Random;
117 import java.util.Set;
118 import java.util.concurrent.CompletableFuture;
119 import java.util.concurrent.CountDownLatch;
120 import java.util.concurrent.TimeUnit;
121 import java.util.concurrent.TimeoutException;
122 
123 @RunWith(AndroidJUnit4.class)
124 @MediumTest
125 public class EthernetTetheringTest {
126     @Rule
127     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
128 
129     private static final String TAG = EthernetTetheringTest.class.getSimpleName();
130     private static final int TIMEOUT_MS = 5000;
131     private static final int TETHER_REACHABILITY_ATTEMPTS = 20;
132     private static final int DUMP_POLLING_MAX_RETRY = 100;
133     private static final int DUMP_POLLING_INTERVAL_MS = 50;
134     // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
135     // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
136     private static final int UDP_STREAM_TS_MS = 2000;
137     // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
138     private static final int RX_UDP_PACKET_SIZE = 30;
139     private static final int RX_UDP_PACKET_COUNT = 456;
140     // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
141     private static final int TX_UDP_PACKET_SIZE = 44;
142     private static final int TX_UDP_PACKET_COUNT = 123;
143 
144     private static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/8");
145     private static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64");
146     private static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8");
147     private static final InetAddress TEST_IP6_DNS = parseNumericAddress("2001:db8:1::888");
148     private static final ByteBuffer TEST_REACHABILITY_PAYLOAD =
149             ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa });
150 
151     private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
152     private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
153     private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
154     private static final String BASE64_DELIMITER = ",";
155     private static final String LINE_DELIMITER = "\\n";
156 
157     private final Context mContext = InstrumentationRegistry.getContext();
158     private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class);
159     private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class);
160 
161     private TestNetworkInterface mDownstreamIface;
162     private HandlerThread mHandlerThread;
163     private Handler mHandler;
164     private TapPacketReader mDownstreamReader;
165     private TapPacketReader mUpstreamReader;
166 
167     private TetheredInterfaceRequester mTetheredInterfaceRequester;
168     private MyTetheringEventCallback mTetheringEventCallback;
169 
170     private UiAutomation mUiAutomation =
171             InstrumentationRegistry.getInstrumentation().getUiAutomation();
172     private boolean mRunTests;
173 
174     private TestNetworkTracker mUpstreamTracker;
175 
176     @Before
setUp()177     public void setUp() throws Exception {
178         // Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive
179         // tethered client callbacks. The restricted networks permission is needed to ensure that
180         // EthernetManager#isAvailable will correctly return true on devices where Ethernet is
181         // marked restricted, like cuttlefish. The dump permission is needed to verify bpf related
182         // functions via dumpsys output.
183         mUiAutomation.adoptShellPermissionIdentity(
184                 MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE,
185                 CONNECTIVITY_USE_RESTRICTED_NETWORKS, DUMP);
186         mHandlerThread = new HandlerThread(getClass().getSimpleName());
187         mHandlerThread.start();
188         mHandler = new Handler(mHandlerThread.getLooper());
189 
190         mRunTests = isEthernetTetheringSupported();
191         assumeTrue(mRunTests);
192 
193         mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
194     }
195 
cleanUp()196     private void cleanUp() throws Exception {
197         mTm.setPreferTestNetworks(false);
198 
199         if (mUpstreamTracker != null) {
200             mUpstreamTracker.teardown();
201             mUpstreamTracker = null;
202         }
203         if (mUpstreamReader != null) {
204             TapPacketReader reader = mUpstreamReader;
205             mHandler.post(() -> reader.stop());
206             mUpstreamReader = null;
207         }
208 
209         mTm.stopTethering(TETHERING_ETHERNET);
210         if (mTetheringEventCallback != null) {
211             mTetheringEventCallback.awaitInterfaceUntethered();
212             mTetheringEventCallback.unregister();
213             mTetheringEventCallback = null;
214         }
215         if (mDownstreamReader != null) {
216             TapPacketReader reader = mDownstreamReader;
217             mHandler.post(() -> reader.stop());
218             mDownstreamReader = null;
219         }
220         mTetheredInterfaceRequester.release();
221         mEm.setIncludeTestInterfaces(false);
222         maybeDeleteTestInterface();
223     }
224 
225     @After
tearDown()226     public void tearDown() throws Exception {
227         try {
228             if (mRunTests) cleanUp();
229         } finally {
230             mHandlerThread.quitSafely();
231             mUiAutomation.dropShellPermissionIdentity();
232         }
233     }
234 
235     @Test
testVirtualEthernetAlreadyExists()236     public void testVirtualEthernetAlreadyExists() throws Exception {
237         // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
238         assumeFalse(mEm.isAvailable());
239 
240         mDownstreamIface = createTestInterface();
241         // This must be done now because as soon as setIncludeTestInterfaces(true) is called, the
242         // interface will be placed in client mode, which will delete the link-local address.
243         // At that point NetworkInterface.getByName() will cease to work on the interface, because
244         // starting in R NetworkInterface can no longer see interfaces without IP addresses.
245         int mtu = getMTU(mDownstreamIface);
246 
247         Log.d(TAG, "Including test interfaces");
248         mEm.setIncludeTestInterfaces(true);
249 
250         final String iface = mTetheredInterfaceRequester.getInterface();
251         assertEquals("TetheredInterfaceCallback for unexpected interface",
252                 mDownstreamIface.getInterfaceName(), iface);
253 
254         checkVirtualEthernet(mDownstreamIface, mtu);
255     }
256 
257     @Test
testVirtualEthernet()258     public void testVirtualEthernet() throws Exception {
259         // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
260         assumeFalse(mEm.isAvailable());
261 
262         CompletableFuture<String> futureIface = mTetheredInterfaceRequester.requestInterface();
263 
264         mEm.setIncludeTestInterfaces(true);
265 
266         mDownstreamIface = createTestInterface();
267 
268         final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
269         assertEquals("TetheredInterfaceCallback for unexpected interface",
270                 mDownstreamIface.getInterfaceName(), iface);
271 
272         checkVirtualEthernet(mDownstreamIface, getMTU(mDownstreamIface));
273     }
274 
275     @Test
testStaticIpv4()276     public void testStaticIpv4() throws Exception {
277         assumeFalse(mEm.isAvailable());
278 
279         mEm.setIncludeTestInterfaces(true);
280 
281         mDownstreamIface = createTestInterface();
282 
283         final String iface = mTetheredInterfaceRequester.getInterface();
284         assertEquals("TetheredInterfaceCallback for unexpected interface",
285                 mDownstreamIface.getInterfaceName(), iface);
286 
287         assertInvalidStaticIpv4Request(iface, null, null);
288         assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
289         assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28");
290         assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28");
291         assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null);
292         assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28");
293         assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28");
294 
295         final String localAddr = "192.0.2.3/28";
296         final String clientAddr = "192.0.2.2/28";
297         mTetheringEventCallback = enableEthernetTethering(iface,
298                 requestWithStaticIpv4(localAddr, clientAddr), null /* any upstream */);
299 
300         mTetheringEventCallback.awaitInterfaceTethered();
301         assertInterfaceHasIpAddress(iface, localAddr);
302 
303         byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
304         byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
305 
306         FileDescriptor fd = mDownstreamIface.getFileDescriptor().getFileDescriptor();
307         mDownstreamReader = makePacketReader(fd, getMTU(mDownstreamIface));
308         TetheringTester tester = new TetheringTester(mDownstreamReader);
309         DhcpResults dhcpResults = tester.runDhcp(client1);
310         assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
311 
312         try {
313             tester.runDhcp(client2);
314             fail("Only one client should get an IP address");
315         } catch (TimeoutException expected) { }
316 
317     }
318 
isRouterAdvertisement(byte[] pkt)319     private static boolean isRouterAdvertisement(byte[] pkt) {
320         if (pkt == null) return false;
321 
322         ByteBuffer buf = ByteBuffer.wrap(pkt);
323 
324         final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf);
325         if (ethHdr.etherType != ETHER_TYPE_IPV6) return false;
326 
327         final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf);
328         if (ipv6Hdr.nextHeader != (byte) IPPROTO_ICMPV6) return false;
329 
330         final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, buf);
331         return icmpv6Hdr.type == (short) ICMPV6_ROUTER_ADVERTISEMENT;
332     }
333 
expectRouterAdvertisement(TapPacketReader reader, String iface, long timeoutMs)334     private static void expectRouterAdvertisement(TapPacketReader reader, String iface,
335             long timeoutMs) {
336         final long deadline = SystemClock.uptimeMillis() + timeoutMs;
337         do {
338             byte[] pkt = reader.popPacket(timeoutMs);
339             if (isRouterAdvertisement(pkt)) return;
340             timeoutMs = deadline - SystemClock.uptimeMillis();
341         } while (timeoutMs > 0);
342         fail("Did not receive router advertisement on " + iface + " after "
343                 +  timeoutMs + "ms idle");
344     }
345 
expectLocalOnlyAddresses(String iface)346     private static void expectLocalOnlyAddresses(String iface) throws Exception {
347         final List<InterfaceAddress> interfaceAddresses =
348                 NetworkInterface.getByName(iface).getInterfaceAddresses();
349 
350         boolean foundIpv6Ula = false;
351         for (InterfaceAddress ia : interfaceAddresses) {
352             final InetAddress addr = ia.getAddress();
353             if (isIPv6ULA(addr)) {
354                 foundIpv6Ula = true;
355             }
356             final int prefixlen = ia.getNetworkPrefixLength();
357             final LinkAddress la = new LinkAddress(addr, prefixlen);
358             if (la.isIpv6() && la.isGlobalPreferred()) {
359                 fail("Found global IPv6 address on local-only interface: " + interfaceAddresses);
360             }
361         }
362 
363         assertTrue("Did not find IPv6 ULA on local-only interface " + iface,
364                 foundIpv6Ula);
365     }
366 
367     @Test
testLocalOnlyTethering()368     public void testLocalOnlyTethering() throws Exception {
369         assumeFalse(mEm.isAvailable());
370 
371         mEm.setIncludeTestInterfaces(true);
372 
373         mDownstreamIface = createTestInterface();
374 
375         final String iface = mTetheredInterfaceRequester.getInterface();
376         assertEquals("TetheredInterfaceCallback for unexpected interface",
377                 mDownstreamIface.getInterfaceName(), iface);
378 
379         final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
380                 .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
381         mTetheringEventCallback = enableEthernetTethering(iface, request,
382                 null /* any upstream */);
383         mTetheringEventCallback.awaitInterfaceLocalOnly();
384 
385         // makePacketReader only works after tethering is started, because until then the interface
386         // does not have an IP address, and unprivileged apps cannot see interfaces without IP
387         // addresses. This shouldn't be flaky because the TAP interface will buffer all packets even
388         // before the reader is started.
389         mDownstreamReader = makePacketReader(mDownstreamIface);
390 
391         expectRouterAdvertisement(mDownstreamReader, iface, 2000 /* timeoutMs */);
392         expectLocalOnlyAddresses(iface);
393     }
394 
isAdbOverNetwork()395     private boolean isAdbOverNetwork() {
396         // If adb TCP port opened, this test may running by adb over network.
397         return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
398                 || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
399     }
400 
401     @Test
testPhysicalEthernet()402     public void testPhysicalEthernet() throws Exception {
403         assumeTrue(mEm.isAvailable());
404         // Do not run this test if adb is over network and ethernet is connected.
405         // It is likely the adb run over ethernet, the adb would break when ethernet is switching
406         // from client mode to server mode. See b/160389275.
407         assumeFalse(isAdbOverNetwork());
408 
409         // Get an interface to use.
410         final String iface = mTetheredInterfaceRequester.getInterface();
411 
412         // Enable Ethernet tethering and check that it starts.
413         mTetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */);
414 
415         // There is nothing more we can do on a physical interface without connecting an actual
416         // client, which is not possible in this test.
417     }
418 
isEthernetTetheringSupported()419     private boolean isEthernetTetheringSupported() throws Exception {
420         final CompletableFuture<Boolean> future = new CompletableFuture<>();
421         final TetheringEventCallback callback = new TetheringEventCallback() {
422             @Override
423             public void onSupportedTetheringTypes(Set<Integer> supportedTypes) {
424                 future.complete(supportedTypes.contains(TETHERING_ETHERNET));
425             }
426         };
427 
428         try {
429             mTm.registerTetheringEventCallback(mHandler::post, callback);
430             return future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
431         } finally {
432             mTm.unregisterTetheringEventCallback(callback);
433         }
434     }
435 
436     private static final class MyTetheringEventCallback implements TetheringEventCallback {
437         private final TetheringManager mTm;
438         private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
439         private final CountDownLatch mTetheringStoppedLatch = new CountDownLatch(1);
440         private final CountDownLatch mLocalOnlyStartedLatch = new CountDownLatch(1);
441         private final CountDownLatch mLocalOnlyStoppedLatch = new CountDownLatch(1);
442         private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1);
443         private final CountDownLatch mUpstreamLatch = new CountDownLatch(1);
444         private final TetheringInterface mIface;
445         private final Network mExpectedUpstream;
446 
447         private boolean mAcceptAnyUpstream = false;
448 
449         private volatile boolean mInterfaceWasTethered = false;
450         private volatile boolean mInterfaceWasLocalOnly = false;
451         private volatile boolean mUnregistered = false;
452         private volatile Collection<TetheredClient> mClients = null;
453         private volatile Network mUpstream = null;
454 
MyTetheringEventCallback(TetheringManager tm, String iface)455         MyTetheringEventCallback(TetheringManager tm, String iface) {
456             this(tm, iface, null);
457             mAcceptAnyUpstream = true;
458         }
459 
MyTetheringEventCallback(TetheringManager tm, String iface, Network expectedUpstream)460         MyTetheringEventCallback(TetheringManager tm, String iface, Network expectedUpstream) {
461             mTm = tm;
462             mIface = new TetheringInterface(TETHERING_ETHERNET, iface);
463             mExpectedUpstream = expectedUpstream;
464         }
465 
unregister()466         public void unregister() {
467             mTm.unregisterTetheringEventCallback(this);
468             mUnregistered = true;
469         }
470         @Override
onTetheredInterfacesChanged(List<String> interfaces)471         public void onTetheredInterfacesChanged(List<String> interfaces) {
472             fail("Should only call callback that takes a Set<TetheringInterface>");
473         }
474 
475         @Override
onTetheredInterfacesChanged(Set<TetheringInterface> interfaces)476         public void onTetheredInterfacesChanged(Set<TetheringInterface> interfaces) {
477             // Ignore stale callbacks registered by previous test cases.
478             if (mUnregistered) return;
479 
480             if (!mInterfaceWasTethered && interfaces.contains(mIface)) {
481                 // This interface is being tethered for the first time.
482                 Log.d(TAG, "Tethering started: " + interfaces);
483                 mInterfaceWasTethered = true;
484                 mTetheringStartedLatch.countDown();
485             } else if (mInterfaceWasTethered && !interfaces.contains(mIface)) {
486                 Log.d(TAG, "Tethering stopped: " + interfaces);
487                 mTetheringStoppedLatch.countDown();
488             }
489         }
490 
491         @Override
onLocalOnlyInterfacesChanged(List<String> interfaces)492         public void onLocalOnlyInterfacesChanged(List<String> interfaces) {
493             fail("Should only call callback that takes a Set<TetheringInterface>");
494         }
495 
496         @Override
onLocalOnlyInterfacesChanged(Set<TetheringInterface> interfaces)497         public void onLocalOnlyInterfacesChanged(Set<TetheringInterface> interfaces) {
498             // Ignore stale callbacks registered by previous test cases.
499             if (mUnregistered) return;
500 
501             if (!mInterfaceWasLocalOnly && interfaces.contains(mIface)) {
502                 // This interface is being put into local-only mode for the first time.
503                 Log.d(TAG, "Local-only started: " + interfaces);
504                 mInterfaceWasLocalOnly = true;
505                 mLocalOnlyStartedLatch.countDown();
506             } else if (mInterfaceWasLocalOnly && !interfaces.contains(mIface)) {
507                 Log.d(TAG, "Local-only stopped: " + interfaces);
508                 mLocalOnlyStoppedLatch.countDown();
509             }
510         }
511 
awaitInterfaceTethered()512         public void awaitInterfaceTethered() throws Exception {
513             assertTrue("Ethernet not tethered after " + TIMEOUT_MS + "ms",
514                     mTetheringStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
515         }
516 
awaitInterfaceLocalOnly()517         public void awaitInterfaceLocalOnly() throws Exception {
518             assertTrue("Ethernet not local-only after " + TIMEOUT_MS + "ms",
519                     mLocalOnlyStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
520         }
521 
awaitInterfaceUntethered()522         public void awaitInterfaceUntethered() throws Exception {
523             // Don't block teardown if the interface was never tethered.
524             // This is racy because the interface might become tethered right after this check, but
525             // that can only happen in tearDown if startTethering timed out, which likely means
526             // the test has already failed.
527             if (!mInterfaceWasTethered && !mInterfaceWasLocalOnly) return;
528 
529             if (mInterfaceWasTethered) {
530                 assertTrue(mIface + " not untethered after " + TIMEOUT_MS + "ms",
531                         mTetheringStoppedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
532             } else if (mInterfaceWasLocalOnly) {
533                 assertTrue(mIface + " not untethered after " + TIMEOUT_MS + "ms",
534                         mLocalOnlyStoppedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
535             } else {
536                 fail(mIface + " cannot be both tethered and local-only. Update this test class.");
537             }
538         }
539 
540         @Override
onError(String ifName, int error)541         public void onError(String ifName, int error) {
542             // Ignore stale callbacks registered by previous test cases.
543             if (mUnregistered) return;
544 
545             fail("TetheringEventCallback got error:" + error + " on iface " + ifName);
546         }
547 
548         @Override
onClientsChanged(Collection<TetheredClient> clients)549         public void onClientsChanged(Collection<TetheredClient> clients) {
550             // Ignore stale callbacks registered by previous test cases.
551             if (mUnregistered) return;
552 
553             Log.d(TAG, "Got clients changed: " + clients);
554             mClients = clients;
555             if (clients.size() > 0) {
556                 mClientConnectedLatch.countDown();
557             }
558         }
559 
awaitClientConnected()560         public Collection<TetheredClient> awaitClientConnected() throws Exception {
561             assertTrue("Did not receive client connected callback after " + TIMEOUT_MS + "ms",
562                     mClientConnectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
563             return mClients;
564         }
565 
566         @Override
onUpstreamChanged(Network network)567         public void onUpstreamChanged(Network network) {
568             // Ignore stale callbacks registered by previous test cases.
569             if (mUnregistered) return;
570 
571             Log.d(TAG, "Got upstream changed: " + network);
572             mUpstream = network;
573             if (mAcceptAnyUpstream || Objects.equals(mUpstream, mExpectedUpstream)) {
574                 mUpstreamLatch.countDown();
575             }
576         }
577 
awaitUpstreamChanged()578         public Network awaitUpstreamChanged() throws Exception {
579             if (!mUpstreamLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
580                 fail("Did not receive upstream " + (mAcceptAnyUpstream ? "any" : mExpectedUpstream)
581                         + " callback after " + TIMEOUT_MS + "ms");
582             }
583             return mUpstream;
584         }
585     }
586 
enableEthernetTethering(String iface, TetheringRequest request, Network expectedUpstream)587     private MyTetheringEventCallback enableEthernetTethering(String iface,
588             TetheringRequest request, Network expectedUpstream) throws Exception {
589         // Enable ethernet tethering with null expectedUpstream means the test accept any upstream
590         // after etherent tethering started.
591         final MyTetheringEventCallback callback;
592         if (expectedUpstream != null) {
593             callback = new MyTetheringEventCallback(mTm, iface, expectedUpstream);
594         } else {
595             callback = new MyTetheringEventCallback(mTm, iface);
596         }
597         mTm.registerTetheringEventCallback(mHandler::post, callback);
598 
599         StartTetheringCallback startTetheringCallback = new StartTetheringCallback() {
600             @Override
601             public void onTetheringFailed(int resultCode) {
602                 fail("Unexpectedly got onTetheringFailed");
603             }
604         };
605         Log.d(TAG, "Starting Ethernet tethering");
606         mTm.startTethering(request, mHandler::post /* executor */,  startTetheringCallback);
607 
608         final int connectivityType = request.getConnectivityScope();
609         switch (connectivityType) {
610             case CONNECTIVITY_SCOPE_GLOBAL:
611                 callback.awaitInterfaceTethered();
612                 break;
613             case CONNECTIVITY_SCOPE_LOCAL:
614                 callback.awaitInterfaceLocalOnly();
615                 break;
616             default:
617                 fail("Unexpected connectivity type requested: " + connectivityType);
618         }
619 
620         return callback;
621     }
622 
enableEthernetTethering(String iface, Network expectedUpstream)623     private MyTetheringEventCallback enableEthernetTethering(String iface, Network expectedUpstream)
624             throws Exception {
625         return enableEthernetTethering(iface,
626                 new TetheringRequest.Builder(TETHERING_ETHERNET)
627                 .setShouldShowEntitlementUi(false).build(), expectedUpstream);
628     }
629 
getMTU(TestNetworkInterface iface)630     private int getMTU(TestNetworkInterface iface) throws SocketException {
631         NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName());
632         assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif);
633         return nif.getMTU();
634     }
635 
makePacketReader(final TestNetworkInterface iface)636     private TapPacketReader makePacketReader(final TestNetworkInterface iface) throws Exception {
637         FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
638         return makePacketReader(fd, getMTU(iface));
639     }
640 
makePacketReader(FileDescriptor fd, int mtu)641     private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
642         final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
643         mHandler.post(() -> reader.start());
644         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
645         return reader;
646     }
647 
checkVirtualEthernet(TestNetworkInterface iface, int mtu)648     private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
649         FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
650         mDownstreamReader = makePacketReader(fd, mtu);
651         mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName(),
652                 null /* any upstream */);
653         checkTetheredClientCallbacks(mDownstreamReader);
654     }
655 
checkTetheredClientCallbacks(TapPacketReader packetReader)656     private void checkTetheredClientCallbacks(TapPacketReader packetReader) throws Exception {
657         // Create a fake client.
658         byte[] clientMacAddr = new byte[6];
659         new Random().nextBytes(clientMacAddr);
660 
661         TetheringTester tester = new TetheringTester(packetReader);
662         DhcpResults dhcpResults = tester.runDhcp(clientMacAddr);
663 
664         final Collection<TetheredClient> clients = mTetheringEventCallback.awaitClientConnected();
665         assertEquals(1, clients.size());
666         final TetheredClient client = clients.iterator().next();
667 
668         // Check the MAC address.
669         assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
670         assertEquals(TETHERING_ETHERNET, client.getTetheringType());
671 
672         // Check the hostname.
673         assertEquals(1, client.getAddresses().size());
674         TetheredClient.AddressInfo info = client.getAddresses().get(0);
675         assertEquals(TetheringTester.DHCP_HOSTNAME, info.getHostname());
676 
677         // Check the address is the one that was handed out in the DHCP ACK.
678         assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
679 
680         // Check that the lifetime is correct +/- 10s.
681         final long now = SystemClock.elapsedRealtime();
682         final long actualLeaseDuration = (info.getAddress().getExpirationTime() - now) / 1000;
683         final String msg = String.format("IP address should have lifetime of %d, got %d",
684                 dhcpResults.leaseDuration, actualLeaseDuration);
685         assertTrue(msg, Math.abs(dhcpResults.leaseDuration - actualLeaseDuration) < 10);
686     }
687 
688     private static final class TetheredInterfaceRequester implements TetheredInterfaceCallback {
689         private final Handler mHandler;
690         private final EthernetManager mEm;
691 
692         private TetheredInterfaceRequest mRequest;
693         private final CompletableFuture<String> mFuture = new CompletableFuture<>();
694 
TetheredInterfaceRequester(Handler handler, EthernetManager em)695         TetheredInterfaceRequester(Handler handler, EthernetManager em) {
696             mHandler = handler;
697             mEm = em;
698         }
699 
700         @Override
onAvailable(String iface)701         public void onAvailable(String iface) {
702             Log.d(TAG, "Ethernet interface available: " + iface);
703             mFuture.complete(iface);
704         }
705 
706         @Override
onUnavailable()707         public void onUnavailable() {
708             mFuture.completeExceptionally(new IllegalStateException("onUnavailable received"));
709         }
710 
requestInterface()711         public CompletableFuture<String> requestInterface() {
712             assertNull("BUG: more than one tethered interface request", mRequest);
713             Log.d(TAG, "Requesting tethered interface");
714             mRequest = mEm.requestTetheredInterface(mHandler::post, this);
715             return mFuture;
716         }
717 
getInterface()718         public String getInterface() throws Exception {
719             return requestInterface().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
720         }
721 
release()722         public void release() {
723             if (mRequest != null) {
724                 mFuture.obtrudeException(new IllegalStateException("Request already released"));
725                 mRequest.release();
726                 mRequest = null;
727             }
728         }
729     }
730 
assertLinkAddressMatches(LinkAddress l1, LinkAddress l2)731     public void assertLinkAddressMatches(LinkAddress l1, LinkAddress l2) {
732         // Check all fields except the deprecation and expiry times.
733         String msg = String.format("LinkAddresses do not match. expected: %s actual: %s", l1, l2);
734         assertTrue(msg, l1.isSameAddressAs(l2));
735         assertEquals("LinkAddress flags do not match", l1.getFlags(), l2.getFlags());
736         assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
737     }
738 
requestWithStaticIpv4(String local, String client)739     private TetheringRequest requestWithStaticIpv4(String local, String client) {
740         LinkAddress localAddr = local == null ? null : new LinkAddress(local);
741         LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
742         return new TetheringRequest.Builder(TETHERING_ETHERNET)
743                 .setStaticIpv4Addresses(localAddr, clientAddr)
744                 .setShouldShowEntitlementUi(false).build();
745     }
746 
assertInvalidStaticIpv4Request(String iface, String local, String client)747     private void assertInvalidStaticIpv4Request(String iface, String local, String client)
748             throws Exception {
749         try {
750             enableEthernetTethering(iface, requestWithStaticIpv4(local, client),
751                     null /* any upstream */);
752             fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
753         } catch (IllegalArgumentException | NullPointerException expected) { }
754     }
755 
assertInterfaceHasIpAddress(String iface, String expected)756     private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
757         LinkAddress expectedAddr = new LinkAddress(expected);
758         NetworkInterface nif = NetworkInterface.getByName(iface);
759         for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
760             final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
761             if (expectedAddr.equals(addr)) {
762                 return;
763             }
764         }
765         fail("Expected " + iface + " to have IP address " + expected + ", found "
766                 + nif.getInterfaceAddresses());
767     }
768 
createTestInterface()769     private TestNetworkInterface createTestInterface() throws Exception {
770         TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
771         TestNetworkInterface iface = tnm.createTapInterface();
772         Log.d(TAG, "Created test interface " + iface.getInterfaceName());
773         return iface;
774     }
775 
maybeDeleteTestInterface()776     private void maybeDeleteTestInterface() throws Exception {
777         if (mDownstreamIface != null) {
778             mDownstreamIface.getFileDescriptor().close();
779             Log.d(TAG, "Deleted test interface " + mDownstreamIface.getInterfaceName());
780             mDownstreamIface = null;
781         }
782     }
783 
createTestUpstream(final List<LinkAddress> addresses)784     private TestNetworkTracker createTestUpstream(final List<LinkAddress> addresses)
785             throws Exception {
786         mTm.setPreferTestNetworks(true);
787 
788         return initTestNetwork(mContext, addresses, TIMEOUT_MS);
789     }
790 
791     @Test
testTestNetworkUpstream()792     public void testTestNetworkUpstream() throws Exception {
793         assumeFalse(mEm.isAvailable());
794 
795         // MyTetheringEventCallback currently only support await first available upstream. Tethering
796         // may select internet network as upstream if test network is not available and not be
797         // preferred yet. Create test upstream network before enable tethering.
798         mUpstreamTracker = createTestUpstream(toList(TEST_IP4_ADDR, TEST_IP6_ADDR));
799 
800         mDownstreamIface = createTestInterface();
801         mEm.setIncludeTestInterfaces(true);
802 
803         final String iface = mTetheredInterfaceRequester.getInterface();
804         assertEquals("TetheredInterfaceCallback for unexpected interface",
805                 mDownstreamIface.getInterfaceName(), iface);
806 
807         mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(),
808                 mUpstreamTracker.getNetwork());
809         assertEquals("onUpstreamChanged for unexpected network", mUpstreamTracker.getNetwork(),
810                 mTetheringEventCallback.awaitUpstreamChanged());
811 
812         mDownstreamReader = makePacketReader(mDownstreamIface);
813         // TODO: do basic forwarding test here.
814     }
815 
816     // Test network topology:
817     //
818     //         public network (rawip)                 private network
819     //                   |                 UE                |
820     // +------------+    V    +------------+------------+    V    +------------+
821     // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
822     // +------------+         +------------+------------+         +------------+
823     // remote ip              public ip                           private ip
824     // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
825     //
826     private static final Inet4Address REMOTE_IP4_ADDR =
827             (Inet4Address) parseNumericAddress("8.8.8.8");
828     // Used by public port and private port. Assume port 9876 has not been used yet before the
829     // testing that public port and private port are the same in the testing. Note that NAT port
830     // forwarding could be different between private port and public port.
831     private static final short LOCAL_PORT = 9876;
832     private static final short REMOTE_PORT = 433;
833     private static final byte TYPE_OF_SERVICE = 0;
834     private static final short ID = 27149;
835     private static final short ID2 = 27150;
836     private static final short ID3 = 27151;
837     private static final short FLAGS_AND_FRAGMENT_OFFSET = (short) 0x4000; // flags=DF, offset=0
838     private static final byte TIME_TO_LIVE = (byte) 0x40;
839     private static final ByteBuffer PAYLOAD =
840             ByteBuffer.wrap(new byte[] { (byte) 0x12, (byte) 0x34 });
841     private static final ByteBuffer PAYLOAD2 =
842             ByteBuffer.wrap(new byte[] { (byte) 0x56, (byte) 0x78 });
843     private static final ByteBuffer PAYLOAD3 =
844             ByteBuffer.wrap(new byte[] { (byte) 0x9a, (byte) 0xbc });
845 
isExpectedUdpPacket(@onNull final byte[] rawPacket, boolean hasEther, @NonNull final ByteBuffer payload)846     private boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEther,
847             @NonNull final ByteBuffer payload) {
848         final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
849 
850         if (hasEther) {
851             final EthernetHeader etherHeader = Struct.parse(EthernetHeader.class, buf);
852             if (etherHeader == null) return false;
853         }
854 
855         final Ipv4Header ipv4Header = Struct.parse(Ipv4Header.class, buf);
856         if (ipv4Header == null) return false;
857 
858         final UdpHeader udpHeader = Struct.parse(UdpHeader.class, buf);
859         if (udpHeader == null) return false;
860 
861         if (buf.remaining() != payload.limit()) return false;
862 
863         return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
864                 payload.array());
865     }
866 
867     @NonNull
buildUdpv4Packet(@ullable final MacAddress srcMac, @Nullable final MacAddress dstMac, short id, @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp, short srcPort, short dstPort, @Nullable final ByteBuffer payload)868     private ByteBuffer buildUdpv4Packet(@Nullable final MacAddress srcMac,
869             @Nullable final MacAddress dstMac, short id,
870             @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp,
871             short srcPort, short dstPort, @Nullable final ByteBuffer payload)
872             throws Exception {
873         final boolean hasEther = (srcMac != null && dstMac != null);
874         final int payloadLen = (payload == null) ? 0 : payload.limit();
875         final ByteBuffer buffer = PacketBuilder.allocate(hasEther, IPPROTO_IP, IPPROTO_UDP,
876                 payloadLen);
877         final PacketBuilder packetBuilder = new PacketBuilder(buffer);
878 
879         if (hasEther) packetBuilder.writeL2Header(srcMac, dstMac, (short) ETHER_TYPE_IPV4);
880         packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET,
881                 TIME_TO_LIVE, (byte) IPPROTO_UDP, srcIp, dstIp);
882         packetBuilder.writeUdpHeader(srcPort, dstPort);
883         if (payload != null) {
884             buffer.put(payload);
885             // in case data might be reused by caller, restore the position and
886             // limit of bytebuffer.
887             payload.clear();
888         }
889 
890         return packetBuilder.finalizePacket();
891     }
892 
893     @NonNull
buildUdpv4Packet(short id, @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp, short srcPort, short dstPort, @Nullable final ByteBuffer payload)894     private ByteBuffer buildUdpv4Packet(short id, @NonNull final Inet4Address srcIp,
895             @NonNull final Inet4Address dstIp, short srcPort, short dstPort,
896             @Nullable final ByteBuffer payload) throws Exception {
897         return buildUdpv4Packet(null /* srcMac */, null /* dstMac */, id, srcIp, dstIp, srcPort,
898                 dstPort, payload);
899     }
900 
901     // TODO: remove this verification once upstream connected notification race is fixed.
902     // See #runUdp4Test.
isIpv4TetherConnectivityVerified(TetheringTester tester, RemoteResponder remote, TetheredDevice tethered)903     private boolean isIpv4TetherConnectivityVerified(TetheringTester tester,
904             RemoteResponder remote, TetheredDevice tethered) throws Exception {
905         final ByteBuffer probePacket = buildUdpv4Packet(tethered.macAddr,
906                 tethered.routerMacAddr, ID, tethered.ipv4Addr /* srcIp */,
907                 REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /*dstPort */,
908                 TEST_REACHABILITY_PAYLOAD);
909 
910         // Send a UDP packet from client and check the packet can be found on upstream interface.
911         for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
912             tester.sendPacket(probePacket);
913             byte[] expectedPacket = remote.getNextMatchedPacket(p -> {
914                 Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
915                 return isExpectedUdpPacket(p, false /* hasEther */, TEST_REACHABILITY_PAYLOAD);
916             });
917             if (expectedPacket != null) return true;
918         }
919         return false;
920     }
921 
runUdp4Test(TetheringTester tester, RemoteResponder remote, boolean usingBpf)922     private void runUdp4Test(TetheringTester tester, RemoteResponder remote, boolean usingBpf)
923             throws Exception {
924         final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
925                 "1:2:3:4:5:6"));
926 
927         // TODO: remove the connectivity verification for upstream connected notification race.
928         // Because async upstream connected notification can't guarantee the tethering routing is
929         // ready to use. Need to test tethering connectivity before testing.
930         // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
931         // from upstream. That can guarantee that the routing is ready. Long term plan is that
932         // refactors upstream connected notification from async to sync.
933         assertTrue(isIpv4TetherConnectivityVerified(tester, remote, tethered));
934 
935         // Send a UDP packet in original direction.
936         final ByteBuffer originalPacket = buildUdpv4Packet(tethered.macAddr,
937                 tethered.routerMacAddr, ID, tethered.ipv4Addr /* srcIp */,
938                 REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /*dstPort */,
939                 PAYLOAD /* payload */);
940         tester.verifyUpload(remote, originalPacket, p -> {
941             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
942             return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD);
943         });
944 
945         // Send a UDP packet in reply direction.
946         final Inet4Address publicIp4Addr = (Inet4Address) TEST_IP4_ADDR.getAddress();
947         final ByteBuffer replyPacket = buildUdpv4Packet(ID2, REMOTE_IP4_ADDR /* srcIp */,
948                 publicIp4Addr /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /*dstPort */,
949                 PAYLOAD2 /* payload */);
950         remote.verifyDownload(tester, replyPacket, p -> {
951             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
952             return isExpectedUdpPacket(p, true/* hasEther */, PAYLOAD2);
953         });
954 
955         if (usingBpf) {
956             // Send second UDP packet in original direction.
957             // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
958             // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
959             // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
960             // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
961             // and apply ASSURED flag.
962             // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
963             // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
964             Thread.sleep(UDP_STREAM_TS_MS);
965             final ByteBuffer originalPacket2 = buildUdpv4Packet(tethered.macAddr,
966                     tethered.routerMacAddr, ID, tethered.ipv4Addr /* srcIp */,
967                     REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */,
968                     REMOTE_PORT /*dstPort */, PAYLOAD3 /* payload */);
969             tester.verifyUpload(remote, originalPacket2, p -> {
970                 Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
971                 return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD3);
972             });
973 
974             // [1] Verify IPv4 upstream rule map.
975             final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
976                     Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
977             assertNotNull(upstreamMap);
978             assertEquals(1, upstreamMap.size());
979 
980             final Map.Entry<Tether4Key, Tether4Value> rule =
981                     upstreamMap.entrySet().iterator().next();
982 
983             final Tether4Key upstream4Key = rule.getKey();
984             assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
985             assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
986             assertEquals(LOCAL_PORT, upstream4Key.srcPort);
987             assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
988             assertEquals(REMOTE_PORT, upstream4Key.dstPort);
989 
990             final Tether4Value upstream4Value = rule.getValue();
991             assertTrue(Arrays.equals(publicIp4Addr.getAddress(),
992                     InetAddress.getByAddress(upstream4Value.src46).getAddress()));
993             assertEquals(LOCAL_PORT, upstream4Value.srcPort);
994             assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
995                     InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
996             assertEquals(REMOTE_PORT, upstream4Value.dstPort);
997 
998             // [2] Verify stats map.
999             // Transmit packets on both direction for verifying stats. Because we only care the
1000             // packet count in stats test, we just reuse the existing packets to increaes
1001             // the packet count on both direction.
1002 
1003             // Send packets on original direction.
1004             for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
1005                 tester.verifyUpload(remote, originalPacket, p -> {
1006                     Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
1007                     return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD);
1008                 });
1009             }
1010 
1011             // Send packets on reply direction.
1012             for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
1013                 remote.verifyDownload(tester, replyPacket, p -> {
1014                     Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
1015                     return isExpectedUdpPacket(p, true/* hasEther */, PAYLOAD2);
1016                 });
1017             }
1018 
1019             // Dump stats map to verify.
1020             final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
1021                     TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
1022             assertNotNull(statsMap);
1023             assertEquals(1, statsMap.size());
1024 
1025             final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
1026                     statsMap.entrySet().iterator().next();
1027 
1028             // TODO: verify the upstream index in TetherStatsKey.
1029 
1030             final TetherStatsValue statsValue = stats.getValue();
1031             assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
1032             assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
1033             assertEquals(0, statsValue.rxErrors);
1034             assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
1035             assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
1036             assertEquals(0, statsValue.txErrors);
1037         }
1038     }
1039 
initializeTethering()1040     void initializeTethering() throws Exception {
1041         assumeFalse(mEm.isAvailable());
1042 
1043         // MyTetheringEventCallback currently only support await first available upstream. Tethering
1044         // may select internet network as upstream if test network is not available and not be
1045         // preferred yet. Create test upstream network before enable tethering.
1046         mUpstreamTracker = createTestUpstream(toList(TEST_IP4_ADDR));
1047 
1048         mDownstreamIface = createTestInterface();
1049         mEm.setIncludeTestInterfaces(true);
1050 
1051         final String iface = mTetheredInterfaceRequester.getInterface();
1052         assertEquals("TetheredInterfaceCallback for unexpected interface",
1053                 mDownstreamIface.getInterfaceName(), iface);
1054 
1055         mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(),
1056                 mUpstreamTracker.getNetwork());
1057         assertEquals("onUpstreamChanged for unexpected network", mUpstreamTracker.getNetwork(),
1058                 mTetheringEventCallback.awaitUpstreamChanged());
1059 
1060         mDownstreamReader = makePacketReader(mDownstreamIface);
1061         mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
1062     }
1063 
1064     @Test
1065     @IgnoreAfter(Build.VERSION_CODES.R)
testTetherUdpV4UpToR()1066     public void testTetherUdpV4UpToR() throws Exception {
1067         initializeTethering();
1068         runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
1069                 false /* usingBpf */);
1070     }
1071 
isUdpOffloadSupportedByKernel(final String kernelVersion)1072     private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
1073         final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
1074         return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
1075                 || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
1076                 || current.isAtLeast(new KVersion(5, 4, 98));
1077     }
1078 
1079     @Test
testIsUdpOffloadSupportedByKernel()1080     public void testIsUdpOffloadSupportedByKernel() throws Exception {
1081         assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
1082         assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
1083         assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
1084         assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
1085         assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
1086 
1087         assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
1088         assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
1089         assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
1090         assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
1091         assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
1092 
1093         assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
1094         assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
1095         assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
1096     }
1097 
1098     // TODO: refactor test testTetherUdpV4* into IPv4 UDP non-offload and offload tests.
1099     // That can be easier to know which feature is verified from test results.
1100     @Test
1101     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherUdpV4AfterR()1102     public void testTetherUdpV4AfterR() throws Exception {
1103         initializeTethering();
1104         final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
1105         boolean usingBpf = isUdpOffloadSupportedByKernel(kernelVersion);
1106         if (!usingBpf) {
1107             Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel "
1108                     + kernelVersion);
1109         }
1110         runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
1111                 usingBpf);
1112     }
1113 
1114     @Nullable
parseMapKeyValue( Class<K> keyClass, Class<V> valueClass, @NonNull String dumpStr)1115     private <K extends Struct, V extends Struct> Pair<K, V> parseMapKeyValue(
1116             Class<K> keyClass, Class<V> valueClass, @NonNull String dumpStr) {
1117         Log.w(TAG, "Parsing string: " + dumpStr);
1118 
1119         String[] keyValueStrs = dumpStr.split(BASE64_DELIMITER);
1120         if (keyValueStrs.length != 2 /* key + value */) {
1121             fail("The length is " + keyValueStrs.length + " but expect 2. "
1122                     + "Split string(s): " + TextUtils.join(",", keyValueStrs));
1123         }
1124 
1125         final byte[] keyBytes = Base64.decode(keyValueStrs[0], Base64.DEFAULT);
1126         Log.d(TAG, "keyBytes: " + dumpHexString(keyBytes));
1127         final ByteBuffer keyByteBuffer = ByteBuffer.wrap(keyBytes);
1128         keyByteBuffer.order(ByteOrder.nativeOrder());
1129         final K k = Struct.parse(keyClass, keyByteBuffer);
1130 
1131         final byte[] valueBytes = Base64.decode(keyValueStrs[1], Base64.DEFAULT);
1132         Log.d(TAG, "valueBytes: " + dumpHexString(valueBytes));
1133         final ByteBuffer valueByteBuffer = ByteBuffer.wrap(valueBytes);
1134         valueByteBuffer.order(ByteOrder.nativeOrder());
1135         final V v = Struct.parse(valueClass, valueByteBuffer);
1136 
1137         return new Pair<>(k, v);
1138     }
1139 
1140     @NonNull
dumpAndParseRawMap( Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)1141     private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
1142             Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
1143             throws Exception {
1144         final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
1145         final String rawMapStr = DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args);
1146         final HashMap<K, V> map = new HashMap<>();
1147 
1148         for (final String line : rawMapStr.split(LINE_DELIMITER)) {
1149             final Pair<K, V> rule = parseMapKeyValue(keyClass, valueClass, line.trim());
1150             map.put(rule.first, rule.second);
1151         }
1152         return map;
1153     }
1154 
1155     @Nullable
pollRawMapFromDump( Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)1156     private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
1157             Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
1158             throws Exception {
1159         for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
1160             final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
1161             if (!map.isEmpty()) return map;
1162 
1163             Thread.sleep(DUMP_POLLING_INTERVAL_MS);
1164         }
1165 
1166         fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
1167         return null;
1168     }
1169 
toList(T... array)1170     private <T> List<T> toList(T... array) {
1171         return Arrays.asList(array);
1172     }
1173 }
1174