• 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.DUMP;
20 import static android.Manifest.permission.LOG_COMPAT_CHANGE;
21 import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
22 import static android.net.InetAddresses.parseNumericAddress;
23 import static android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK;
24 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
25 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
26 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
27 import static android.net.TetheringManager.TETHERING_ETHERNET;
28 import static android.net.TetheringManager.TETHERING_VIRTUAL;
29 import static android.net.TetheringTester.TestDnsPacket;
30 import static android.net.TetheringTester.buildIcmpEchoPacketV4;
31 import static android.net.TetheringTester.buildUdpPacket;
32 import static android.net.TetheringTester.isExpectedIcmpPacket;
33 import static android.net.TetheringTester.isExpectedUdpDnsPacket;
34 import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_MATCH_NON_THREAD_LOCAL_NETWORKS;
35 import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
36 import static android.system.OsConstants.ICMP_ECHO;
37 import static android.system.OsConstants.ICMP_ECHOREPLY;
38 import static android.system.OsConstants.IPPROTO_UDP;
39 
40 import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
41 import static com.android.net.module.util.HexDump.dumpHexString;
42 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE;
43 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
44 import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
45 import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
46 import static com.android.net.module.util.NetworkStackConstants.UDP_HEADER_LEN;
47 import static com.android.testutils.DeviceInfoUtils.KVersion;
48 import static com.android.testutils.TestPermissionUtil.runAsShell;
49 
50 import static org.junit.Assert.assertEquals;
51 import static org.junit.Assert.assertFalse;
52 import static org.junit.Assert.assertNotNull;
53 import static org.junit.Assert.assertTrue;
54 import static org.junit.Assert.fail;
55 import static org.junit.Assume.assumeFalse;
56 import static org.junit.Assume.assumeTrue;
57 
58 import android.app.compat.CompatChanges;
59 import android.content.Context;
60 import android.net.TetheringManager.TetheringRequest;
61 import android.net.TetheringTester.TetheredDevice;
62 import android.os.Build;
63 import android.os.SystemClock;
64 import android.os.SystemProperties;
65 import android.os.VintfRuntimeInfo;
66 import android.util.Log;
67 import android.util.Pair;
68 
69 import androidx.annotation.NonNull;
70 import androidx.annotation.Nullable;
71 import androidx.test.filters.LargeTest;
72 import androidx.test.runner.AndroidJUnit4;
73 
74 import com.android.modules.utils.build.SdkLevel;
75 import com.android.net.module.util.BpfDump;
76 import com.android.net.module.util.Ipv6Utils;
77 import com.android.net.module.util.Struct;
78 import com.android.net.module.util.bpf.ClatEgress4Key;
79 import com.android.net.module.util.bpf.ClatEgress4Value;
80 import com.android.net.module.util.bpf.ClatIngress6Key;
81 import com.android.net.module.util.bpf.ClatIngress6Value;
82 import com.android.net.module.util.bpf.Tether4Key;
83 import com.android.net.module.util.bpf.Tether4Value;
84 import com.android.net.module.util.bpf.TetherStatsKey;
85 import com.android.net.module.util.bpf.TetherStatsValue;
86 import com.android.net.module.util.structs.Ipv4Header;
87 import com.android.net.module.util.structs.UdpHeader;
88 import com.android.testutils.AutoReleaseNetworkCallbackRule;
89 import com.android.testutils.DevSdkIgnoreRule;
90 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
91 import com.android.testutils.DeviceConfigRule;
92 import com.android.testutils.DeviceInfoUtils;
93 import com.android.testutils.DumpTestUtils;
94 import com.android.testutils.NetworkStackModuleTest;
95 import com.android.testutils.PollPacketReader;
96 import com.android.testutils.RecorderCallback.CallbackEntry;
97 import com.android.testutils.TestableNetworkCallback;
98 
99 import org.junit.After;
100 import org.junit.Rule;
101 import org.junit.Test;
102 import org.junit.runner.RunWith;
103 
104 import java.io.File;
105 import java.io.FileDescriptor;
106 import java.net.Inet4Address;
107 import java.net.Inet6Address;
108 import java.net.InetAddress;
109 import java.net.InterfaceAddress;
110 import java.net.NetworkInterface;
111 import java.nio.ByteBuffer;
112 import java.util.Arrays;
113 import java.util.Collection;
114 import java.util.HashMap;
115 import java.util.List;
116 import java.util.Map;
117 import java.util.Random;
118 import java.util.concurrent.TimeoutException;
119 
120 @RunWith(AndroidJUnit4.class)
121 @LargeTest
122 public class EthernetTetheringTest extends EthernetTetheringTestBase {
123     @Rule
124     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
125     // For manipulating feature flag before and after testing.
126     @Rule
127     public final DeviceConfigRule mDeviceConfigRule = new DeviceConfigRule();
128     @Rule
129     public final AutoReleaseNetworkCallbackRule
130             mNetworkCallbackRule = new AutoReleaseNetworkCallbackRule();
131 
132     private static final String TAG = EthernetTetheringTest.class.getSimpleName();
133 
134     private static final short DNS_PORT = 53;
135     private static final short ICMPECHO_ID = 0x0;
136     private static final short ICMPECHO_SEQ = 0x0;
137 
138     private static final int DUMP_POLLING_MAX_RETRY = 100;
139     private static final int DUMP_POLLING_INTERVAL_MS = 50;
140     // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
141     // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
142     private static final int UDP_STREAM_TS_MS = 2000;
143     // Give slack time for waiting UDP stream mode because handling conntrack event in user space
144     // may not in precise time. Used to reduce the flaky rate.
145     private static final int UDP_STREAM_SLACK_MS = 500;
146     // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
147     private static final int RX_UDP_PACKET_SIZE = 30;
148     private static final int RX_UDP_PACKET_COUNT = 456;
149     // Per TX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
150     private static final int TX_UDP_PACKET_SIZE = 30;
151     private static final int TX_UDP_PACKET_COUNT = 123;
152 
153     private static final String DUMPSYS_CLAT_RAWMAP_EGRESS4_ARG = "clatEgress4RawBpfMap";
154     private static final String DUMPSYS_CLAT_RAWMAP_INGRESS6_ARG = "clatIngress6RawBpfMap";
155     private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
156     private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
157     private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
158     private static final String LINE_DELIMITER = "\\n";
159 
160     // TODO: use class DnsPacket to build DNS query and reply message once DnsPacket supports
161     // building packet for given arguments.
162     private static final ByteBuffer DNS_QUERY = ByteBuffer.wrap(new byte[] {
163             // scapy.DNS(
164             //   id=0xbeef,
165             //   qr=0,
166             //   qd=scapy.DNSQR(qname="hello.example.com"))
167             //
168             /* Header */
169             (byte) 0xbe, (byte) 0xef, /* Transaction ID: 0xbeef */
170             (byte) 0x01, (byte) 0x00, /* Flags: rd */
171             (byte) 0x00, (byte) 0x01, /* Questions: 1 */
172             (byte) 0x00, (byte) 0x00, /* Answer RRs: 0 */
173             (byte) 0x00, (byte) 0x00, /* Authority RRs: 0 */
174             (byte) 0x00, (byte) 0x00, /* Additional RRs: 0 */
175             /* Queries */
176             (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
177             (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
178             (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
179             (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
180             (byte) 0x6f, (byte) 0x6d, (byte) 0x00, /* Name: hello.example.com */
181             (byte) 0x00, (byte) 0x01,              /* Type: A */
182             (byte) 0x00, (byte) 0x01               /* Class: IN */
183     });
184 
185     private static final byte[] DNS_REPLY = new byte[] {
186             // scapy.DNS(
187             //   id=0,
188             //   qr=1,
189             //   qd=scapy.DNSQR(qname="hello.example.com"),
190             //   an=scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4'))
191             //
192             /* Header */
193             (byte) 0x00, (byte) 0x00, /* Transaction ID: 0x0, must be updated by dns query id */
194             (byte) 0x81, (byte) 0x00, /* Flags: qr rd */
195             (byte) 0x00, (byte) 0x01, /* Questions: 1 */
196             (byte) 0x00, (byte) 0x01, /* Answer RRs: 1 */
197             (byte) 0x00, (byte) 0x00, /* Authority RRs: 0 */
198             (byte) 0x00, (byte) 0x00, /* Additional RRs: 0 */
199             /* Queries */
200             (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
201             (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
202             (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
203             (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
204             (byte) 0x6f, (byte) 0x6d, (byte) 0x00,              /* Name: hello.example.com */
205             (byte) 0x00, (byte) 0x01,                           /* Type: A */
206             (byte) 0x00, (byte) 0x01,                           /* Class: IN */
207             /* Answers */
208             (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
209             (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
210             (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
211             (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
212             (byte) 0x6f, (byte) 0x6d, (byte) 0x00,              /* Name: hello.example.com */
213             (byte) 0x00, (byte) 0x01,                           /* Type: A */
214             (byte) 0x00, (byte) 0x01,                           /* Class: IN */
215             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, /* Time to live: 0 */
216             (byte) 0x00, (byte) 0x04,                           /* Data length: 4 */
217             (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04  /* Address: 1.2.3.4 */
218     };
219 
220     // Shamelessly copied from TetheringConfiguration.
221     private static final String TETHERING_LOCAL_NETWORK_AGENT = "tethering_local_network_agent";
222 
223     @After
tearDown()224     public void tearDown() throws Exception {
225         super.tearDown();
226         // TODO: See b/318121782#comment4. Register an ethernet InterfaceStateListener, and wait for
227         // the callback to report client mode. This happens as soon as both
228         // TetheredInterfaceRequester and the tethering code itself have released the interface,
229         // i.e. after stopTethering() has completed.
230         Thread.sleep(3000);
231     }
232 
233     @Test
testVirtualEthernetAlreadyExists()234     public void testVirtualEthernetAlreadyExists() throws Exception {
235         // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
236         assumeFalse(isInterfaceForTetheringAvailable());
237 
238         TestNetworkInterface downstreamIface = null;
239         MyTetheringEventCallback tetheringEventCallback = null;
240         PollPacketReader downstreamReader = null;
241 
242         try {
243             downstreamIface = createTestInterface();
244             // This must be done now because as soon as setIncludeTestInterfaces(true) is called,
245             // the interface will be placed in client mode, which will delete the link-local
246             // address. At that point NetworkInterface.getByName() will cease to work on the
247             // interface, because starting in R NetworkInterface can no longer see interfaces
248             // without IP addresses.
249             int mtu = getMTU(downstreamIface);
250 
251             Log.d(TAG, "Including test interfaces");
252             setIncludeTestInterfaces(true);
253 
254             final String iface = mTetheredInterfaceRequester.getInterface();
255             assertEquals("TetheredInterfaceCallback for unexpected interface",
256                     downstreamIface.getInterfaceName(), iface);
257 
258             // Check virtual ethernet.
259             FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
260             downstreamReader = makePacketReader(fd, mtu);
261             tetheringEventCallback = enableEthernetTethering(downstreamIface.getInterfaceName(),
262                     null /* any upstream */);
263             checkTetheredClientCallbacks(
264                     downstreamReader, TETHERING_ETHERNET, tetheringEventCallback);
265         } finally {
266             maybeStopTapPacketReader(downstreamReader);
267             maybeCloseTestInterface(downstreamIface);
268             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
269         }
270     }
271 
272     @Test
testVirtualEthernet()273     public void testVirtualEthernet() throws Exception {
274         // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
275         assumeFalse(isInterfaceForTetheringAvailable());
276 
277         setIncludeTestInterfaces(true);
278 
279         TestNetworkInterface downstreamIface = null;
280         MyTetheringEventCallback tetheringEventCallback = null;
281         PollPacketReader downstreamReader = null;
282 
283         try {
284             downstreamIface = createTestInterface();
285 
286             final String iface = mTetheredInterfaceRequester.getInterface();
287             assertEquals("TetheredInterfaceCallback for unexpected interface",
288                     downstreamIface.getInterfaceName(), iface);
289 
290             // Check virtual ethernet.
291             FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
292             downstreamReader = makePacketReader(fd, getMTU(downstreamIface));
293             tetheringEventCallback = enableEthernetTethering(downstreamIface.getInterfaceName(),
294                     null /* any upstream */);
295             checkTetheredClientCallbacks(
296                     downstreamReader, TETHERING_ETHERNET, tetheringEventCallback);
297         } finally {
298             maybeStopTapPacketReader(downstreamReader);
299             maybeCloseTestInterface(downstreamIface);
300             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
301         }
302     }
303 
304     @Test
testStaticIpv4()305     public void testStaticIpv4() throws Exception {
306         assumeFalse(isInterfaceForTetheringAvailable());
307 
308         setIncludeTestInterfaces(true);
309 
310         TestNetworkInterface downstreamIface = null;
311         MyTetheringEventCallback tetheringEventCallback = null;
312         PollPacketReader downstreamReader = null;
313 
314         try {
315             downstreamIface = createTestInterface();
316 
317             final String iface = mTetheredInterfaceRequester.getInterface();
318             assertEquals("TetheredInterfaceCallback for unexpected interface",
319                     downstreamIface.getInterfaceName(), iface);
320 
321             assertInvalidStaticIpv4Request(iface, null, null);
322             assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
323             assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28");
324             assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28");
325             assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null);
326             assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28");
327             assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28");
328 
329             final String localAddr = "192.0.2.3/28";
330             final String clientAddr = "192.0.2.2/28";
331             tetheringEventCallback = enableTethering(iface,
332                     requestWithStaticIpv4(localAddr, clientAddr), null /* any upstream */);
333 
334             tetheringEventCallback.awaitInterfaceTethered();
335             assertInterfaceHasIpAddress(iface, localAddr);
336 
337             byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
338             byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
339 
340             FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
341             downstreamReader = makePacketReader(fd, getMTU(downstreamIface));
342             TetheringTester tester = new TetheringTester(downstreamReader);
343             DhcpResults dhcpResults = tester.runDhcp(client1);
344             assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
345 
346             try {
347                 tester.runDhcp(client2);
348                 fail("Only one client should get an IP address");
349             } catch (TimeoutException expected) { }
350         } finally {
351             maybeStopTapPacketReader(downstreamReader);
352             maybeCloseTestInterface(downstreamIface);
353             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
354         }
355     }
356 
expectLocalOnlyAddresses(String iface)357     private static void expectLocalOnlyAddresses(String iface) throws Exception {
358         final List<InterfaceAddress> interfaceAddresses =
359                 NetworkInterface.getByName(iface).getInterfaceAddresses();
360 
361         boolean foundIpv6Ula = false;
362         for (InterfaceAddress ia : interfaceAddresses) {
363             final InetAddress addr = ia.getAddress();
364             if (isIPv6ULA(addr)) {
365                 foundIpv6Ula = true;
366             }
367             final int prefixlen = ia.getNetworkPrefixLength();
368             final LinkAddress la = new LinkAddress(addr, prefixlen);
369             if (la.isIpv6() && la.isGlobalPreferred()) {
370                 fail("Found global IPv6 address on local-only interface: " + interfaceAddresses);
371             }
372         }
373 
374         assertTrue("Did not find IPv6 ULA on local-only interface " + iface,
375                 foundIpv6Ula);
376     }
377 
378     @Test
testLocalOnlyTethering()379     public void testLocalOnlyTethering() throws Exception {
380         assumeFalse(isInterfaceForTetheringAvailable());
381 
382         setIncludeTestInterfaces(true);
383 
384         TestNetworkInterface downstreamIface = null;
385         MyTetheringEventCallback tetheringEventCallback = null;
386         PollPacketReader downstreamReader = null;
387 
388         try {
389             downstreamIface = createTestInterface();
390 
391             final String iface = mTetheredInterfaceRequester.getInterface();
392             assertEquals("TetheredInterfaceCallback for unexpected interface",
393                     downstreamIface.getInterfaceName(), iface);
394 
395             final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
396                     .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
397             tetheringEventCallback = enableTethering(iface, request, null /* any upstream */);
398             tetheringEventCallback.awaitInterfaceLocalOnly();
399 
400             // makePacketReader only works after tethering is started, because until then the
401             // interface does not have an IP address, and unprivileged apps cannot see interfaces
402             // without IP addresses. This shouldn't be flaky because the TAP interface will buffer
403             // all packets even before the reader is started.
404             downstreamReader = makePacketReader(downstreamIface);
405 
406             waitForRouterAdvertisement(downstreamReader, iface, WAIT_RA_TIMEOUT_MS);
407             expectLocalOnlyAddresses(iface);
408 
409             // After testing the IPv6 local address, the DHCP server may still be in the process
410             // of being created. If the downstream interface is killed by the test while the
411             // DHCP server is starting, a DHCP server error may occur. To ensure that the DHCP
412             // server has started completely before finishing the test, also test the dhcp server
413             // by calling runDhcp.
414             final TetheringTester tester = new TetheringTester(downstreamReader);
415             tester.runDhcp(MacAddress.fromString("1:2:3:4:5:6").toByteArray());
416         } finally {
417             maybeStopTapPacketReader(downstreamReader);
418             maybeCloseTestInterface(downstreamIface);
419             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
420         }
421     }
422 
isAdbOverNetwork()423     private boolean isAdbOverNetwork() {
424         // If adb TCP port opened, this test may running by adb over network.
425         return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
426                 || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
427     }
428 
429     @Test
testPhysicalEthernet()430     public void testPhysicalEthernet() throws Exception {
431         assumeTrue(isInterfaceForTetheringAvailable());
432         // Do not run this test if adb is over network and ethernet is connected.
433         // It is likely the adb run over ethernet, the adb would break when ethernet is switching
434         // from client mode to server mode. See b/160389275.
435         assumeFalse(isAdbOverNetwork());
436 
437         MyTetheringEventCallback tetheringEventCallback = null;
438         try {
439             // Get an interface to use.
440             final String iface = mTetheredInterfaceRequester.getInterface();
441 
442             // Enable Ethernet tethering and check that it starts.
443             tetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */);
444         } finally {
445             stopEthernetTethering(tetheringEventCallback);
446         }
447         // There is nothing more we can do on a physical interface without connecting an actual
448         // client, which is not possible in this test.
449     }
450 
checkTetheredClientCallbacks(final PollPacketReader packetReader, final int tetheringType, final MyTetheringEventCallback tetheringEventCallback)451     private void checkTetheredClientCallbacks(final PollPacketReader packetReader,
452             final int tetheringType,
453             final MyTetheringEventCallback tetheringEventCallback) throws Exception {
454         // Create a fake client.
455         byte[] clientMacAddr = new byte[6];
456         new Random().nextBytes(clientMacAddr);
457 
458         TetheringTester tester = new TetheringTester(packetReader);
459         DhcpResults dhcpResults = tester.runDhcp(clientMacAddr);
460 
461         final Collection<TetheredClient> clients = tetheringEventCallback.awaitClientConnected();
462         assertEquals(1, clients.size());
463         final TetheredClient client = clients.iterator().next();
464 
465         // Check the MAC address.
466         assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
467         assertEquals(tetheringType, client.getTetheringType());
468 
469         // Check the hostname.
470         assertEquals(1, client.getAddresses().size());
471         TetheredClient.AddressInfo info = client.getAddresses().get(0);
472         assertEquals(TetheringTester.DHCP_HOSTNAME, info.getHostname());
473 
474         // Check the address is the one that was handed out in the DHCP ACK.
475         assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
476 
477         // Check that the lifetime is correct +/- 10s.
478         final long now = SystemClock.elapsedRealtime();
479         final long actualLeaseDuration = (info.getAddress().getExpirationTime() - now) / 1000;
480         final String msg = String.format("IP address should have lifetime of %d, got %d",
481                 dhcpResults.leaseDuration, actualLeaseDuration);
482         assertTrue(msg, Math.abs(dhcpResults.leaseDuration - actualLeaseDuration) < 10);
483     }
484 
assertLinkAddressMatches(LinkAddress l1, LinkAddress l2)485     public void assertLinkAddressMatches(LinkAddress l1, LinkAddress l2) {
486         // Check all fields except the deprecation and expiry times.
487         String msg = String.format("LinkAddresses do not match. expected: %s actual: %s", l1, l2);
488         assertTrue(msg, l1.isSameAddressAs(l2));
489         assertEquals("LinkAddress flags do not match", l1.getFlags(), l2.getFlags());
490         assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
491     }
492 
requestWithStaticIpv4(String local, String client)493     private TetheringRequest requestWithStaticIpv4(String local, String client) {
494         LinkAddress localAddr = local == null ? null : new LinkAddress(local);
495         LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
496         return new TetheringRequest.Builder(TETHERING_ETHERNET)
497                 .setStaticIpv4Addresses(localAddr, clientAddr)
498                 .setShouldShowEntitlementUi(false).build();
499     }
500 
assertInvalidStaticIpv4Request(String iface, String local, String client)501     private void assertInvalidStaticIpv4Request(String iface, String local, String client)
502             throws Exception {
503         try {
504             enableTethering(iface, requestWithStaticIpv4(local, client), null /* any upstream */);
505             fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
506         } catch (IllegalArgumentException | NullPointerException expected) { }
507     }
508 
assertInterfaceHasIpAddress(String iface, String expected)509     private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
510         LinkAddress expectedAddr = new LinkAddress(expected);
511         NetworkInterface nif = NetworkInterface.getByName(iface);
512         for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
513             final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
514             if (expectedAddr.equals(addr)) {
515                 return;
516             }
517         }
518         fail("Expected " + iface + " to have IP address " + expected + ", found "
519                 + nif.getInterfaceAddresses());
520     }
521 
522     @Test
testIcmpv6Echo()523     public void testIcmpv6Echo() throws Exception {
524         runPing6Test(initTetheringTester(toList(TEST_IP4_ADDR, TEST_IP6_ADDR),
525                 toList(TEST_IP4_DNS, TEST_IP6_DNS)));
526     }
527 
runPing6Test(TetheringTester tester)528     private void runPing6Test(TetheringTester tester) throws Exception {
529         TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
530         Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
531         ByteBuffer request = Ipv6Utils.buildEchoRequestPacket(tethered.macAddr,
532                 tethered.routerMacAddr, tethered.ipv6Addr, remoteIp6Addr);
533         tester.verifyUpload(request, p -> {
534             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
535 
536             return isExpectedIcmpPacket(p, false /* hasEth */, false /* isIpv4 */,
537                     ICMPV6_ECHO_REQUEST_TYPE);
538         });
539 
540         ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
541         tester.verifyDownload(reply, p -> {
542             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
543 
544             return isExpectedIcmpPacket(p, true /* hasEth */, false /* isIpv4 */,
545                     ICMPV6_ECHO_REPLY_TYPE);
546         });
547     }
548 
549     @Test
testTetherUdpV6()550     public void testTetherUdpV6() throws Exception {
551         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
552                 toList(TEST_IP6_DNS));
553         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
554         sendUploadPacketUdp(tethered.macAddr, tethered.routerMacAddr,
555                 tethered.ipv6Addr, REMOTE_IP6_ADDR, tester, false /* is4To6 */);
556         sendDownloadPacketUdp(REMOTE_IP6_ADDR, tethered.ipv6Addr, tester, false /* is6To4 */);
557 
558         // TODO: test BPF offload maps {rule, stats}.
559     }
560 
561 
562     /**
563      * Basic IPv4 UDP tethering test. Verify that UDP tethered packets are transferred no matter
564      * using which data path.
565      */
566     @Test
testTetherUdpV4()567     public void testTetherUdpV4() throws Exception {
568         // Test network topology:
569         //
570         //         public network (rawip)                 private network
571         //                   |                 UE                |
572         // +------------+    V    +------------+------------+    V    +------------+
573         // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
574         // +------------+         +------------+------------+         +------------+
575         // remote ip              public ip                           private ip
576         // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
577         //
578         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
579                 toList(TEST_IP4_DNS));
580         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
581 
582         // TODO: remove the connectivity verification for upstream connected notification race.
583         // Because async upstream connected notification can't guarantee the tethering routing is
584         // ready to use. Need to test tethering connectivity before testing.
585         // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
586         // from upstream. That can guarantee that the routing is ready. Long term plan is that
587         // refactors upstream connected notification from async to sync.
588         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
589 
590         final MacAddress srcMac = tethered.macAddr;
591         final MacAddress dstMac = tethered.routerMacAddr;
592         final InetAddress remoteIp = REMOTE_IP4_ADDR;
593         final InetAddress tetheringUpstreamIp = TEST_IP4_ADDR.getAddress();
594         final InetAddress clientIp = tethered.ipv4Addr;
595         sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
596         sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
597     }
598 
599     // Test network topology:
600     //
601     //            public network (rawip)                 private network
602     //                      |         UE (CLAT support)         |
603     // +---------------+    V    +------------+------------+    V    +------------+
604     // | NAT64 Gateway +---------+  Upstream  | Downstream +---------+   Client   |
605     // +---------------+         +------------+------------+         +------------+
606     // remote ip                 public ip                           private ip
607     // [64:ff9b::808:808]:443    [clat ipv6]:9876                    [TetheredDevice ipv4]:9876
608     //
609     // Note that CLAT IPv6 address is generated by ClatCoordinator. Get the CLAT IPv6 address by
610     // sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
611     // packet.
612     //
runClatUdpTest()613     private void runClatUdpTest() throws Exception {
614         // CLAT only starts on IPv6 only network.
615         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
616                 toList(TEST_IP6_DNS));
617         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
618 
619         // Get CLAT IPv6 address.
620         final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
621 
622         // Send an IPv4 UDP packet in original direction.
623         // IPv4 packet -- CLAT translation --> IPv6 packet
624         sendUploadPacketUdp(tethered.macAddr, tethered.routerMacAddr, tethered.ipv4Addr,
625                 REMOTE_IP4_ADDR, tester, true /* is4To6 */);
626 
627         // Send an IPv6 UDP packet in reply direction.
628         // IPv6 packet -- CLAT translation --> IPv4 packet
629         sendDownloadPacketUdp(REMOTE_NAT64_ADDR, clatIp6, tester, true /* is6To4 */);
630 
631         // TODO: test CLAT bpf maps.
632     }
633 
634     // TODO: support R device. See b/234727688.
635     @Test
636     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherClatUdp()637     public void testTetherClatUdp() throws Exception {
638         runClatUdpTest();
639     }
640 
641     @Test
testIcmpv4Echo()642     public void testIcmpv4Echo() throws Exception {
643         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
644                 toList(TEST_IP4_DNS));
645         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
646 
647         // TODO: remove the connectivity verification for upstream connected notification race.
648         // See the same reason in testTetherUdp4().
649         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
650 
651         final ByteBuffer request = buildIcmpEchoPacketV4(tethered.macAddr /* srcMac */,
652                 tethered.routerMacAddr /* dstMac */, tethered.ipv4Addr /* srcIp */,
653                 REMOTE_IP4_ADDR /* dstIp */, ICMP_ECHO, ICMPECHO_ID, ICMPECHO_SEQ);
654         tester.verifyUpload(request, p -> {
655             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
656 
657             return isExpectedIcmpPacket(p, false /* hasEth */, true /* isIpv4 */, ICMP_ECHO);
658         });
659 
660         final ByteBuffer reply = buildIcmpEchoPacketV4(REMOTE_IP4_ADDR /* srcIp*/,
661                 (Inet4Address) TEST_IP4_ADDR.getAddress() /* dstIp */, ICMP_ECHOREPLY, ICMPECHO_ID,
662                 ICMPECHO_SEQ);
663         tester.verifyDownload(reply, p -> {
664             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
665 
666             return isExpectedIcmpPacket(p, true /* hasEth */, true /* isIpv4 */, ICMP_ECHOREPLY);
667         });
668     }
669 
670     // TODO: support R device. See b/234727688.
671     @Test
672     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherClatIcmp()673     public void testTetherClatIcmp() throws Exception {
674         // CLAT only starts on IPv6 only network.
675         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
676                 toList(TEST_IP6_DNS));
677         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
678 
679         // Get CLAT IPv6 address.
680         final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
681 
682         // Send an IPv4 ICMP packet in original direction.
683         // IPv4 packet -- CLAT translation --> IPv6 packet
684         final ByteBuffer request = buildIcmpEchoPacketV4(tethered.macAddr /* srcMac */,
685                 tethered.routerMacAddr /* dstMac */, tethered.ipv4Addr /* srcIp */,
686                 (Inet4Address) REMOTE_IP4_ADDR /* dstIp */, ICMP_ECHO, ICMPECHO_ID, ICMPECHO_SEQ);
687         tester.verifyUpload(request, p -> {
688             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
689 
690             return isExpectedIcmpPacket(p, false /* hasEth */, false /* isIpv4 */,
691                     ICMPV6_ECHO_REQUEST_TYPE);
692         });
693 
694         // Send an IPv6 ICMP packet in reply direction.
695         // IPv6 packet -- CLAT translation --> IPv4 packet
696         final ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(
697                 (Inet6Address) REMOTE_NAT64_ADDR /* srcIp */, clatIp6 /* dstIp */);
698         tester.verifyDownload(reply, p -> {
699             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
700 
701             return isExpectedIcmpPacket(p, true /* hasEth */, true /* isIpv4 */, ICMP_ECHOREPLY);
702         });
703     }
704 
705     @NonNull
buildDnsReplyMessageById(short id)706     private ByteBuffer buildDnsReplyMessageById(short id) {
707         byte[] replyMessage = Arrays.copyOf(DNS_REPLY, DNS_REPLY.length);
708         // Assign transaction id of reply message pattern with a given DNS transaction id.
709         replyMessage[0] = (byte) ((id >> 8) & 0xff);
710         replyMessage[1] = (byte) (id & 0xff);
711         Log.d(TAG, "Built DNS reply: " + dumpHexString(replyMessage));
712 
713         return ByteBuffer.wrap(replyMessage);
714     }
715 
716     @NonNull
sendDownloadPacketDnsV4(@onNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp, short srcPort, short dstPort, short dnsId, @NonNull final TetheringTester tester)717     private void sendDownloadPacketDnsV4(@NonNull final Inet4Address srcIp,
718             @NonNull final Inet4Address dstIp, short srcPort, short dstPort, short dnsId,
719             @NonNull final TetheringTester tester) throws Exception {
720         // DNS response transaction id must be copied from DNS query. Used by the requester
721         // to match up replies to outstanding queries. See RFC 1035 section 4.1.1.
722         final ByteBuffer dnsReplyMessage = buildDnsReplyMessageById(dnsId);
723         final ByteBuffer testPacket = buildUdpPacket((InetAddress) srcIp,
724                 (InetAddress) dstIp, srcPort, dstPort, dnsReplyMessage);
725 
726         tester.verifyDownload(testPacket, p -> {
727             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
728             return isExpectedUdpDnsPacket(p, true /* hasEther */, true /* isIpv4 */,
729                     dnsReplyMessage);
730         });
731     }
732 
733     // Send IPv4 UDP DNS packet and return the forwarded DNS packet on upstream.
734     @NonNull
sendUploadPacketDnsV4(@onNull final MacAddress srcMac, @NonNull final MacAddress dstMac, @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp, short srcPort, short dstPort, @NonNull final TetheringTester tester)735     private byte[] sendUploadPacketDnsV4(@NonNull final MacAddress srcMac,
736             @NonNull final MacAddress dstMac, @NonNull final Inet4Address srcIp,
737             @NonNull final Inet4Address dstIp, short srcPort, short dstPort,
738             @NonNull final TetheringTester tester) throws Exception {
739         final ByteBuffer testPacket = buildUdpPacket(srcMac, dstMac, srcIp, dstIp,
740                 srcPort, dstPort, DNS_QUERY);
741 
742         return tester.verifyUpload(testPacket, p -> {
743             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
744             return isExpectedUdpDnsPacket(p, false /* hasEther */, true /* isIpv4 */,
745                     DNS_QUERY);
746         });
747     }
748 
749     @Test
testTetherUdpV4Dns()750     public void testTetherUdpV4Dns() throws Exception {
751         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
752                 toList(TEST_IP4_DNS));
753         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
754 
755         // TODO: remove the connectivity verification for upstream connected notification race.
756         // See the same reason in testTetherUdp4().
757         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
758 
759         // [1] Send DNS query.
760         // tethered device --> downstream --> dnsmasq forwarding --> upstream --> DNS server
761         //
762         // Need to extract DNS transaction id and source port from dnsmasq forwarded DNS query
763         // packet. dnsmasq forwarding creats new query which means UDP source port and DNS
764         // transaction id are changed from original sent DNS query. See forward_query() in
765         // external/dnsmasq/src/forward.c. Note that #TetheringTester.isExpectedUdpDnsPacket
766         // guarantees that |forwardedQueryPacket| is a valid DNS packet. So we can parse it as DNS
767         // packet.
768         final MacAddress srcMac = tethered.macAddr;
769         final MacAddress dstMac = tethered.routerMacAddr;
770         final Inet4Address clientIp = tethered.ipv4Addr;
771         final Inet4Address gatewayIp = tethered.ipv4Gatway;
772         final byte[] forwardedQueryPacket = sendUploadPacketDnsV4(srcMac, dstMac, clientIp,
773                 gatewayIp, LOCAL_PORT, DNS_PORT, tester);
774         final ByteBuffer buf = ByteBuffer.wrap(forwardedQueryPacket);
775         Struct.parse(Ipv4Header.class, buf);
776         final UdpHeader udpHeader = Struct.parse(UdpHeader.class, buf);
777         final TestDnsPacket dnsQuery = TestDnsPacket.getTestDnsPacket(buf);
778         assertNotNull(dnsQuery);
779         Log.d(TAG, "Forwarded UDP source port: " + udpHeader.srcPort + ", DNS query id: "
780                 + dnsQuery.getHeader().getId());
781 
782         // [2] Send DNS reply.
783         // DNS server --> upstream --> dnsmasq forwarding --> downstream --> tethered device
784         //
785         // DNS reply transaction id must be copied from DNS query. Used by the requester to match
786         // up replies to outstanding queries. See RFC 1035 section 4.1.1.
787         final Inet4Address remoteIp = (Inet4Address) TEST_IP4_DNS;
788         final Inet4Address tetheringUpstreamIp = (Inet4Address) TEST_IP4_ADDR.getAddress();
789         sendDownloadPacketDnsV4(remoteIp, tetheringUpstreamIp, DNS_PORT,
790                 (short) udpHeader.srcPort, (short) dnsQuery.getHeader().getId(), tester);
791     }
792 
793     @Test
testTetherTcpV4()794     public void testTetherTcpV4() throws Exception {
795         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
796                 toList(TEST_IP4_DNS));
797         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
798 
799         // TODO: remove the connectivity verification for upstream connected notification race.
800         // See the same reason in testTetherUdp4().
801         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
802 
803         runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
804                 tethered.ipv4Addr /* uploadSrcIp */, REMOTE_IP4_ADDR /* uploadDstIp */,
805                 REMOTE_IP4_ADDR /* downloadSrcIp */, TEST_IP4_ADDR.getAddress() /* downloadDstIp */,
806                 tester, false /* isClat */);
807     }
808 
809     @Test
testTetherTcpV6()810     public void testTetherTcpV6() throws Exception {
811         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
812                 toList(TEST_IP6_DNS));
813         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
814 
815         runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
816                 tethered.ipv6Addr /* uploadSrcIp */, REMOTE_IP6_ADDR /* uploadDstIp */,
817                 REMOTE_IP6_ADDR /* downloadSrcIp */, tethered.ipv6Addr /* downloadDstIp */,
818                 tester, false /* isClat */);
819     }
820 
821     // TODO: support R device. See b/234727688.
822     @Test
823     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherClatTcp()824     public void testTetherClatTcp() throws Exception {
825         // CLAT only starts on IPv6 only network.
826         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
827                 toList(TEST_IP6_DNS));
828         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
829 
830         // Get CLAT IPv6 address.
831         final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
832 
833         runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
834                 tethered.ipv4Addr /* uploadSrcIp */, REMOTE_IP4_ADDR /* uploadDstIp */,
835                 REMOTE_NAT64_ADDR /* downloadSrcIp */, clatIp6 /* downloadDstIp */,
836                 tester, true /* isClat */);
837     }
838 
839     private static final byte[] ZeroLengthDhcpPacket = new byte[] {
840             // scapy.Ether(
841             //   dst="ff:ff:ff:ff:ff:ff")
842             // scapy.IP(
843             //   dst="255.255.255.255")
844             // scapy.UDP(sport=68, dport=67)
845             /* Ethernet Header */
846             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
847             (byte) 0xe0, (byte) 0x4f, (byte) 0x43, (byte) 0xe6, (byte) 0xfb, (byte) 0xd2,
848             (byte) 0x08, (byte) 0x00,
849             /* Ip header */
850             (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x1c, (byte) 0x00, (byte) 0x01,
851             (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x11, (byte) 0xb6, (byte) 0x58,
852             (byte) 0x64, (byte) 0x4f, (byte) 0x60, (byte) 0x29, (byte) 0xff, (byte) 0xff,
853             (byte) 0xff, (byte) 0xff,
854             /* UDP header */
855             (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
856             (byte) 0x00, (byte) 0x08, (byte) 0x3a, (byte) 0xdf
857     };
858 
859     // This test requires the update in NetworkStackModule(See b/269692093).
860     @NetworkStackModuleTest
861     @Test
testTetherZeroLengthDhcpPacket()862     public void testTetherZeroLengthDhcpPacket() throws Exception {
863         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
864                 toList(TEST_IP4_DNS));
865         tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
866 
867         // Send a zero-length DHCP packet to upstream DHCP server.
868         final ByteBuffer packet = ByteBuffer.wrap(ZeroLengthDhcpPacket);
869         tester.sendUploadPacket(packet);
870 
871         // Send DHCPDISCOVER packet from another downstream tethered device to verify that
872         // upstream DHCP server doesn't close the listening socket and stop reading, then we
873         // can still receive the next DHCP packet from server.
874         final MacAddress macAddress = MacAddress.fromString("11:22:33:44:55:66");
875         assertTrue(tester.testDhcpServerAlive(macAddress));
876     }
877 
isUdpOffloadSupportedByKernel(final String kernelVersion)878     private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
879         final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
880         return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
881                 || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
882                 || current.isAtLeast(new KVersion(5, 4, 98));
883     }
884 
885     @Test
testIsUdpOffloadSupportedByKernel()886     public void testIsUdpOffloadSupportedByKernel() throws Exception {
887         assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
888         assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
889         assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
890         assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
891         assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
892 
893         assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
894         assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
895         assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
896         assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
897         assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
898 
899         assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
900         assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
901         assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
902     }
903 
assumeKernelSupportBpfOffloadUdpV4()904     private static void assumeKernelSupportBpfOffloadUdpV4() {
905         final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
906         assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload",
907                 isUdpOffloadSupportedByKernel(kernelVersion));
908     }
909 
910     @Test
testKernelSupportBpfOffloadUdpV4()911     public void testKernelSupportBpfOffloadUdpV4() throws Exception {
912         assumeKernelSupportBpfOffloadUdpV4();
913     }
914 
isTetherConfigBpfOffloadEnabled()915     private boolean isTetherConfigBpfOffloadEnabled() throws Exception {
916         final String dumpStr = runAsShell(DUMP, () ->
917                 DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short"));
918 
919         // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in
920         // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by
921         // RRO to override the enabled default value. Get the tethering config via dumpsys.
922         // $ dumpsys tethering
923         //   mIsBpfEnabled: true
924         boolean enabled = dumpStr.contains("mIsBpfEnabled: true");
925         if (!enabled) {
926             Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr);
927         }
928         return enabled;
929     }
930 
931     @Test
testTetherConfigBpfOffloadEnabled()932     public void testTetherConfigBpfOffloadEnabled() throws Exception {
933         assumeTrue(isTetherConfigBpfOffloadEnabled());
934     }
935 
936     @NonNull
dumpAndParseRawMap( Class<K> keyClass, Class<V> valueClass, @NonNull String service, @NonNull String[] args)937     private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
938             Class<K> keyClass, Class<V> valueClass, @NonNull String service, @NonNull String[] args)
939             throws Exception {
940         final String rawMapStr = runAsShell(DUMP, () ->
941                 DumpTestUtils.dumpService(service, args));
942         final HashMap<K, V> map = new HashMap<>();
943 
944         for (final String line : rawMapStr.split(LINE_DELIMITER)) {
945             final Pair<K, V> rule =
946                     BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
947             map.put(rule.first, rule.second);
948         }
949         return map;
950     }
951 
952     @Nullable
pollRawMapFromDump( Class<K> keyClass, Class<V> valueClass, @NonNull String service, @NonNull String[] args)953     private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
954             Class<K> keyClass, Class<V> valueClass, @NonNull String service, @NonNull String[] args)
955             throws Exception {
956         for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
957             final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, service, args);
958             if (!map.isEmpty()) return map;
959 
960             Thread.sleep(DUMP_POLLING_INTERVAL_MS);
961         }
962 
963         fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
964         return null;
965     }
966 
967     // Test network topology:
968     //
969     //         public network (rawip)                 private network
970     //                   |                 UE                |
971     // +------------+    V    +------------+------------+    V    +------------+
972     // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
973     // +------------+         +------------+------------+         +------------+
974     // remote ip              public ip                           private ip
975     // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
976     //
runUdp4Test()977     private void runUdp4Test() throws Exception {
978         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
979                 toList(TEST_IP4_DNS));
980         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
981 
982         // TODO: remove the connectivity verification for upstream connected notification race.
983         // Because async upstream connected notification can't guarantee the tethering routing is
984         // ready to use. Need to test tethering connectivity before testing.
985         // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
986         // from upstream. That can guarantee that the routing is ready. Long term plan is that
987         // refactors upstream connected notification from async to sync.
988         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
989 
990         final MacAddress srcMac = tethered.macAddr;
991         final MacAddress dstMac = tethered.routerMacAddr;
992         final InetAddress remoteIp = REMOTE_IP4_ADDR;
993         final InetAddress tetheringUpstreamIp = TEST_IP4_ADDR.getAddress();
994         final InetAddress clientIp = tethered.ipv4Addr;
995         sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
996         sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
997 
998         // Send second UDP packet in original direction.
999         // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
1000         // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
1001         // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
1002         // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
1003         // and apply ASSURED flag.
1004         // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
1005         // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
1006         Thread.sleep(UDP_STREAM_TS_MS);
1007         sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
1008 
1009         // Give a slack time for handling conntrack event in user space.
1010         Thread.sleep(UDP_STREAM_SLACK_MS);
1011 
1012         // [1] Verify IPv4 upstream rule map.
1013         final String[] upstreamArgs = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG,
1014                 DUMPSYS_RAWMAP_ARG_UPSTREAM4};
1015         final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
1016                 Tether4Key.class, Tether4Value.class, Context.TETHERING_SERVICE, upstreamArgs);
1017         assertNotNull(upstreamMap);
1018         assertEquals(1, upstreamMap.size());
1019 
1020         final Map.Entry<Tether4Key, Tether4Value> rule =
1021                 upstreamMap.entrySet().iterator().next();
1022 
1023         final Tether4Key upstream4Key = rule.getKey();
1024         assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
1025         assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
1026         assertEquals(LOCAL_PORT, upstream4Key.srcPort);
1027         assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
1028         assertEquals(REMOTE_PORT, upstream4Key.dstPort);
1029 
1030         final Tether4Value upstream4Value = rule.getValue();
1031         assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(),
1032                 InetAddress.getByAddress(upstream4Value.src46).getAddress()));
1033         assertEquals(LOCAL_PORT, upstream4Value.srcPort);
1034         assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
1035                 InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
1036         assertEquals(REMOTE_PORT, upstream4Value.dstPort);
1037 
1038         // [2] Verify stats map.
1039         // Transmit packets on both direction for verifying stats. Because we only care the
1040         // packet count in stats test, we just reuse the existing packets to increaes
1041         // the packet count on both direction.
1042 
1043         // Send packets on original direction.
1044         for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
1045             sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester,
1046                     false /* is4To6 */);
1047         }
1048 
1049         // Send packets on reply direction.
1050         for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
1051             sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
1052         }
1053 
1054         // Dump stats map to verify.
1055         final String[] statsArgs = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG,
1056                 DUMPSYS_RAWMAP_ARG_STATS};
1057         final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
1058                 TetherStatsKey.class, TetherStatsValue.class, Context.TETHERING_SERVICE, statsArgs);
1059         assertNotNull(statsMap);
1060         assertEquals(1, statsMap.size());
1061 
1062         final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
1063                 statsMap.entrySet().iterator().next();
1064 
1065         // TODO: verify the upstream index in TetherStatsKey.
1066 
1067         final TetherStatsValue statsValue = stats.getValue();
1068         assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
1069         assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
1070         assertEquals(0, statsValue.rxErrors);
1071         assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
1072         assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
1073         assertEquals(0, statsValue.txErrors);
1074     }
1075 
1076     // on S/Sv2 without a new enough DnsResolver apex, NetBpfLoad does not
1077     // get triggered, and thus no mainline programs get loaded.
isNetBpfLoadEnabled()1078     private boolean isNetBpfLoadEnabled() {
1079         if (SdkLevel.isAtLeastT()) return true;
1080         if (!SdkLevel.isAtLeastS()) return false;
1081 
1082         File f = new File("/apex/com.android.resolv/NetBpfLoad-S.flag");
1083         return f.isFile();
1084     }
1085 
1086     /**
1087      * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF.
1088      * Minimum test requirement:
1089      * 1. S+ device.
1090      * 2. Tethering config enables tethering BPF offload.
1091      * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel.
1092      *
1093      * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883
1094      */
1095     @Test
1096     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherBpfOffloadUdpV4()1097     public void testTetherBpfOffloadUdpV4() throws Exception {
1098         assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled());
1099         assumeKernelSupportBpfOffloadUdpV4();
1100         assumeTrue("Mainline NetBpfLoad not available", isNetBpfLoadEnabled());
1101 
1102         runUdp4Test();
1103     }
1104 
getClatEgress4Value(int clatIfaceIndex)1105     private ClatEgress4Value getClatEgress4Value(int clatIfaceIndex) throws Exception {
1106         // Command: dumpsys connectivity clatEgress4RawBpfMap
1107         final String[] args = new String[] {DUMPSYS_CLAT_RAWMAP_EGRESS4_ARG};
1108         final HashMap<ClatEgress4Key, ClatEgress4Value> egress4Map = pollRawMapFromDump(
1109                 ClatEgress4Key.class, ClatEgress4Value.class, Context.CONNECTIVITY_SERVICE, args);
1110         assertNotNull(egress4Map);
1111         for (Map.Entry<ClatEgress4Key, ClatEgress4Value> entry : egress4Map.entrySet()) {
1112             ClatEgress4Key key = entry.getKey();
1113             if (key.iif == clatIfaceIndex) {
1114                 return entry.getValue();
1115             }
1116         }
1117         return null;
1118     }
1119 
getClatIngress6Value(int ifaceIndex)1120     private ClatIngress6Value getClatIngress6Value(int ifaceIndex) throws Exception {
1121         // Command: dumpsys connectivity clatIngress6RawBpfMap
1122         final String[] args = new String[] {DUMPSYS_CLAT_RAWMAP_INGRESS6_ARG};
1123         final HashMap<ClatIngress6Key, ClatIngress6Value> ingress6Map = pollRawMapFromDump(
1124                 ClatIngress6Key.class, ClatIngress6Value.class, Context.CONNECTIVITY_SERVICE, args);
1125         assertNotNull(ingress6Map);
1126         for (Map.Entry<ClatIngress6Key, ClatIngress6Value> entry : ingress6Map.entrySet()) {
1127             ClatIngress6Key key = entry.getKey();
1128             if (key.iif == ifaceIndex) {
1129                 return entry.getValue();
1130             }
1131         }
1132         return null;
1133     }
1134 
1135     /**
1136      * Test network topology:
1137      *
1138      *            public network (rawip)                 private network
1139      *                      |         UE (CLAT support)         |
1140      * +---------------+    V    +------------+------------+    V    +------------+
1141      * | NAT64 Gateway +---------+  Upstream  | Downstream +---------+   Client   |
1142      * +---------------+         +------------+------------+         +------------+
1143      * remote ip                 public ip                           private ip
1144      * [64:ff9b::808:808]:443    [clat ipv6]:9876                    [TetheredDevice ipv4]:9876
1145      *
1146      * Note that CLAT IPv6 address is generated by ClatCoordinator. Get the CLAT IPv6 address by
1147      * sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
1148      * packet.
1149      */
1150     @Test
1151     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testTetherClatBpfOffloadUdp()1152     public void testTetherClatBpfOffloadUdp() throws Exception {
1153         assumeKernelSupportBpfOffloadUdpV4();
1154 
1155         // CLAT only starts on IPv6 only network.
1156         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
1157                 toList(TEST_IP6_DNS));
1158         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
1159 
1160         // Get CLAT IPv6 address.
1161         final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
1162 
1163         // Get current values before sending packets.
1164         final String ifaceName = getUpstreamInterfaceName();
1165         final int ifaceIndex = getIndexByName(ifaceName);
1166         final int clatIfaceIndex = getIndexByName("v4-" + ifaceName);
1167         final ClatEgress4Value oldEgress4 = getClatEgress4Value(clatIfaceIndex);
1168         final ClatIngress6Value oldIngress6 = getClatIngress6Value(ifaceIndex);
1169         assertNotNull(oldEgress4);
1170         assertNotNull(oldIngress6);
1171 
1172         // Send an IPv4 UDP packet in original direction.
1173         // IPv4 packet -- CLAT translation --> IPv6 packet
1174         for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
1175             sendUploadPacketUdp(tethered.macAddr, tethered.routerMacAddr, tethered.ipv4Addr,
1176                     REMOTE_IP4_ADDR, tester, true /* is4To6 */);
1177         }
1178 
1179         // Send an IPv6 UDP packet in reply direction.
1180         // IPv6 packet -- CLAT translation --> IPv4 packet
1181         for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
1182             sendDownloadPacketUdp(REMOTE_NAT64_ADDR, clatIp6, tester, true /* is6To4 */);
1183         }
1184 
1185         // Send fragmented IPv6 UDP packets in the reply direction.
1186         // IPv6 frament packet -- CLAT translation --> IPv4 fragment packet
1187         final int payloadLen = 1500;
1188         final int l2mtu = 1000;
1189         final int fragPktCnt = 2; // 1500 bytes of UDP payload were fragmented into two packets.
1190         final long fragRxBytes = payloadLen + UDP_HEADER_LEN + fragPktCnt * IPV4_HEADER_MIN_LEN;
1191         final byte[] payload = new byte[payloadLen];
1192         // Initialize the payload with random bytes.
1193         Random random = new Random();
1194         random.nextBytes(payload);
1195         sendDownloadFragmentedUdpPackets(REMOTE_NAT64_ADDR, clatIp6, tester,
1196                 ByteBuffer.wrap(payload), l2mtu);
1197 
1198         // After sending test packets, get stats again to verify their differences.
1199         final ClatEgress4Value newEgress4 = getClatEgress4Value(clatIfaceIndex);
1200         final ClatIngress6Value newIngress6 = getClatIngress6Value(ifaceIndex);
1201         assertNotNull(newEgress4);
1202         assertNotNull(newIngress6);
1203 
1204         assertEquals(RX_UDP_PACKET_COUNT + fragPktCnt, newIngress6.packets - oldIngress6.packets);
1205         assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE + fragRxBytes,
1206                 newIngress6.bytes - oldIngress6.bytes);
1207         assertEquals(TX_UDP_PACKET_COUNT, newEgress4.packets - oldEgress4.packets);
1208         // The increase in egress traffic equals the expected size of the translated UDP packets.
1209         // Calculation:
1210         // - Original UDP packet was TX_UDP_PACKET_SIZE bytes (IPv4 header + UDP header + payload).
1211         // - After CLAT translation, each packet is now:
1212         //     IPv6 header + unchanged UDP header + unchanged payload
1213         // Therefore, the total size of the translated UDP packet should be:
1214         //     TX_UDP_PACKET_SIZE + IPV6_HEADER_LEN - IPV4_HEADER_MIN_LEN
1215         assertEquals(
1216                 TX_UDP_PACKET_COUNT * (TX_UDP_PACKET_SIZE + IPV6_HEADER_LEN - IPV4_HEADER_MIN_LEN),
1217                 newEgress4.bytes - oldEgress4.bytes);
1218     }
1219 
1220     @Test
testTetheringVirtual()1221     public void testTetheringVirtual() throws Exception {
1222         assumeFalse(isInterfaceForTetheringAvailable());
1223         setIncludeTestInterfaces(true);
1224 
1225         TestNetworkInterface downstreamIface = null;
1226         MyTetheringEventCallback tetheringEventCallback = null;
1227         PollPacketReader downstreamReader = null;
1228         try {
1229             downstreamIface = createTestInterface();
1230             String iface = downstreamIface.getInterfaceName();
1231             final TetheringRequest request = new TetheringRequest.Builder(TETHERING_VIRTUAL)
1232                     .setConnectivityScope(CONNECTIVITY_SCOPE_GLOBAL)
1233                     .setInterfaceName(iface)
1234                     .build();
1235             tetheringEventCallback = enableTethering(iface, request, null /* any upstream */);
1236 
1237             FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
1238             downstreamReader = makePacketReader(fd, getMTU(downstreamIface));
1239             checkTetheredClientCallbacks(
1240                     downstreamReader, TETHERING_VIRTUAL, tetheringEventCallback);
1241         } finally {
1242             maybeStopTapPacketReader(downstreamReader);
1243             maybeCloseTestInterface(downstreamIface);
1244             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
1245         }
1246     }
1247 
1248     @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
1249     @Test
testLocalAgent_networkCallbacks()1250     public void testLocalAgent_networkCallbacks() throws Exception {
1251         final boolean isMatchNonThreadLocalNetworksEnabled = runAsShell(
1252                 READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE,
1253                 () -> CompatChanges.isChangeEnabled(ENABLE_MATCH_NON_THREAD_LOCAL_NETWORKS));
1254         assumeTrue(isMatchNonThreadLocalNetworksEnabled);
1255 
1256         mDeviceConfigRule.setConfig(NAMESPACE_TETHERING, TETHERING_LOCAL_NETWORK_AGENT, "1");
1257         assumeFalse(isInterfaceForTetheringAvailable());
1258         setIncludeTestInterfaces(true);
1259 
1260         TestNetworkInterface downstreamIface = null;
1261         MyTetheringEventCallback tetheringEventCallback = null;
1262 
1263         final TestableNetworkCallback networkCallback = new TestableNetworkCallback();
1264         final NetworkRequest networkRequest = new NetworkRequest.Builder()
1265                 .addCapability(NET_CAPABILITY_LOCAL_NETWORK).build();
1266         mNetworkCallbackRule.registerNetworkCallback(networkRequest, networkCallback);
1267 
1268         try {
1269             downstreamIface = createTestInterface();
1270 
1271             final String iface = mTetheredInterfaceRequester.getInterface();
1272             assertEquals("TetheredInterfaceCallback for unexpected interface",
1273                     downstreamIface.getInterfaceName(), iface);
1274 
1275             final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
1276                     .setConnectivityScope(CONNECTIVITY_SCOPE_GLOBAL).build();
1277             tetheringEventCallback = enableTethering(iface, request, null /* any upstream */);
1278             tetheringEventCallback.awaitInterfaceTethered();
1279 
1280             // Verify NetworkCallback works accordingly.
1281             final Network network = networkCallback.expect(CallbackEntry.AVAILABLE).getNetwork();
1282             final CallbackEntry.CapabilitiesChanged capEvent =
1283                     networkCallback.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED);
1284             assertEquals(network, capEvent.getNetwork());
1285             assertTrue(capEvent.getCaps().hasTransport(TRANSPORT_ETHERNET));
1286             assertTrue(capEvent.getCaps().hasCapability(NET_CAPABILITY_LOCAL_NETWORK));
1287         } finally {
1288             stopEthernetTethering(tetheringEventCallback);
1289             maybeCloseTestInterface(downstreamIface);
1290         }
1291     }
1292 }
1293