diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 237a645c0d..21eb8998bc 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -26,7 +26,6 @@ import static android.net.InetAddresses.parseNumericAddress; import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_ETHERNET; -import static android.net.TetheringTester.RemoteResponder; import static android.net.TetheringTester.isIcmpv6Type; import static android.system.OsConstants.IPPROTO_IP; import static android.system.OsConstants.IPPROTO_IPV6; @@ -816,10 +815,10 @@ public class EthernetTetheringTest { mDownstreamReader = makePacketReader(mDownstreamIface); mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface()); - runPing6Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader)); + runPing6Test(new TetheringTester(mDownstreamReader, mUpstreamReader)); } - private void runPing6Test(TetheringTester tester, RemoteResponder remote) throws Exception { + private void runPing6Test(TetheringTester tester) throws Exception { // Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let // TetheringTester test ipv6 tethering connectivity before testing ipv6. // TODO: move to a common place to avoid that every IPv6 test needs to call this function. @@ -830,24 +829,18 @@ public class EthernetTetheringTest { Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222"); ByteBuffer request = Ipv6Utils.buildEchoRequestPacket(tethered.macAddr, tethered.routerMacAddr, tethered.ipv6Addr, remoteIp6Addr); - tester.sendPacket(request); - - final byte[] echoRequest = remote.getNextMatchedPacket((p) -> { + tester.verifyUpload(request, p -> { Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); return isIcmpv6Type(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE); }); - assertNotNull("No icmpv6 echo request in upstream", echoRequest); ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr); - remote.sendPacket(reply); - - final byte[] echoReply = tester.getNextMatchedPacket((p) -> { + tester.verifyDownload(reply, p -> { Log.d(TAG, "Packet in downstream: " + dumpHexString(p)); return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE); }); - assertNotNull("No icmpv6 echo reply in downstream", echoReply); } // Test network topology: @@ -964,7 +957,7 @@ public class EthernetTetheringTest { // TODO: remove this verification once upstream connected notification race is fixed. // See #runUdp4Test. private boolean isIpv4TetherConnectivityVerified(TetheringTester tester, - RemoteResponder remote, TetheredDevice tethered) throws Exception { + TetheredDevice tethered) throws Exception { final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr, tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */, REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, @@ -972,8 +965,7 @@ public class EthernetTetheringTest { // Send a UDP packet from client and check the packet can be found on upstream interface. for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) { - tester.sendPacket(probePacket); - byte[] expectedPacket = remote.getNextMatchedPacket(p -> { + byte[] expectedPacket = tester.testUpload(probePacket, p -> { Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, TEST_REACHABILITY_PAYLOAD); @@ -983,8 +975,7 @@ public class EthernetTetheringTest { return false; } - private void runUdp4Test(TetheringTester tester, RemoteResponder remote, boolean usingBpf) - throws Exception { + private void runUdp4Test(TetheringTester tester, boolean usingBpf) throws Exception { final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString( "1:2:3:4:5:6"), false /* hasIpv6 */); @@ -994,14 +985,14 @@ public class EthernetTetheringTest { // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes // from upstream. That can guarantee that the routing is ready. Long term plan is that // refactors upstream connected notification from async to sync. - assertTrue(isIpv4TetherConnectivityVerified(tester, remote, tethered)); + assertTrue(isIpv4TetherConnectivityVerified(tester, tethered)); // Send a UDP packet in original direction. final ByteBuffer originalPacket = buildUdpPacket(tethered.macAddr, tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */, REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, PAYLOAD /* payload */); - tester.verifyUpload(remote, originalPacket, p -> { + tester.verifyUpload(originalPacket, p -> { Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD); }); @@ -1011,7 +1002,7 @@ public class EthernetTetheringTest { final ByteBuffer replyPacket = buildUdpPacket(REMOTE_IP4_ADDR /* srcIp */, publicIp4Addr /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */, PAYLOAD2 /* payload */); - remote.verifyDownload(tester, replyPacket, p -> { + tester.verifyDownload(replyPacket, p -> { Log.d(TAG, "Packet in downstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2); }); @@ -1030,7 +1021,7 @@ public class EthernetTetheringTest { tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */, REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, PAYLOAD3 /* payload */); - tester.verifyUpload(remote, originalPacket2, p -> { + tester.verifyUpload(originalPacket2, p -> { Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD3); }); @@ -1066,7 +1057,7 @@ public class EthernetTetheringTest { // Send packets on original direction. for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) { - tester.verifyUpload(remote, originalPacket, p -> { + tester.verifyUpload(originalPacket, p -> { Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD); }); @@ -1074,7 +1065,7 @@ public class EthernetTetheringTest { // Send packets on reply direction. for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) { - remote.verifyDownload(tester, replyPacket, p -> { + tester.verifyDownload(replyPacket, p -> { Log.d(TAG, "Packet in downstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2); }); @@ -1130,8 +1121,7 @@ public class EthernetTetheringTest { @IgnoreAfter(Build.VERSION_CODES.R) public void testTetherUdpV4UpToR() throws Exception { initializeTethering(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS)); - runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader), - false /* usingBpf */); + runUdp4Test(new TetheringTester(mDownstreamReader, mUpstreamReader), false /* usingBpf */); } private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) { @@ -1172,8 +1162,7 @@ public class EthernetTetheringTest { Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel " + kernelVersion); } - runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader), - usingBpf); + runUdp4Test(new TetheringTester(mDownstreamReader, mUpstreamReader), usingBpf); } @Nullable @@ -1233,8 +1222,8 @@ public class EthernetTetheringTest { } @Nullable - private Inet6Address getClatIpv6Address(TetheringTester tester, - RemoteResponder remote, TetheredDevice tethered) throws Exception { + private Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered) + throws Exception { final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr, tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */, REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, @@ -1245,8 +1234,7 @@ public class EthernetTetheringTest { // packet. byte[] expectedPacket = null; for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) { - tester.sendPacket(probePacket); - expectedPacket = remote.getNextMatchedPacket(p -> { + expectedPacket = tester.verifyUpload(probePacket, p -> { Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */, TEST_REACHABILITY_PAYLOAD); @@ -1275,8 +1263,7 @@ public class EthernetTetheringTest { // sending out an IPv4 packet and extracting the source address from CLAT translated IPv6 // packet. // - private void runClatUdpTest(TetheringTester tester, RemoteResponder remote) - throws Exception { + private void runClatUdpTest(TetheringTester tester) throws Exception { // Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let // TetheringTester test ipv6 tethering connectivity before testing ipv6. // TODO: move to a common place to avoid that every IPv6 test needs to call this function. @@ -1286,7 +1273,7 @@ public class EthernetTetheringTest { "1:2:3:4:5:6"), true /* hasIpv6 */); // Get CLAT IPv6 address. - final Inet6Address clatAddr6 = getClatIpv6Address(tester, remote, tethered); + final Inet6Address clatAddr6 = getClatIpv6Address(tester, tethered); assertNotNull(clatAddr6); // Send an IPv4 UDP packet in original direction. @@ -1295,7 +1282,7 @@ public class EthernetTetheringTest { tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */, REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, PAYLOAD /* payload */); - tester.verifyUpload(remote, originalPacket, p -> { + tester.verifyUpload(originalPacket, p -> { Log.d(TAG, "Packet in upstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */, PAYLOAD); }); @@ -1305,7 +1292,7 @@ public class EthernetTetheringTest { final ByteBuffer replyPacket = buildUdpPacket(REMOTE_NAT64_ADDR /* srcIp */, clatAddr6 /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */, PAYLOAD2 /* payload */); - remote.verifyDownload(tester, replyPacket, p -> { + tester.verifyDownload(replyPacket, p -> { Log.d(TAG, "Packet in downstream: " + dumpHexString(p)); return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2); }); @@ -1318,8 +1305,7 @@ public class EthernetTetheringTest { public void testTetherClatUdp() throws Exception { // CLAT only starts on IPv6 only network. initializeTethering(toList(TEST_IP6_ADDR), toList(TEST_IP6_DNS)); - runClatUdpTest(new TetheringTester(mDownstreamReader), - new RemoteResponder(mUpstreamReader)); + runClatUdpTest(new TetheringTester(mDownstreamReader, mUpstreamReader)); } private List toList(T... array) { diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/src/android/net/TetheringTester.java index 458680ac36..9df636b4e9 100644 --- a/Tethering/tests/integration/src/android/net/TetheringTester.java +++ b/Tethering/tests/integration/src/android/net/TetheringTester.java @@ -42,6 +42,7 @@ import android.net.dhcp.DhcpPacket; import android.util.ArrayMap; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.net.module.util.Ipv6Utils; @@ -88,11 +89,17 @@ public final class TetheringTester { private final ArrayMap mTetheredDevices; private final TapPacketReader mDownstreamReader; + private final TapPacketReader mUpstreamReader; public TetheringTester(TapPacketReader downstream) { + this(downstream, null); + } + + public TetheringTester(TapPacketReader downstream, TapPacketReader upstream) { if (downstream == null) fail("Downstream reader could not be NULL"); mDownstreamReader = downstream; + mUpstreamReader = upstream; mTetheredDevices = new ArrayMap<>(); } @@ -170,7 +177,7 @@ public final class TetheringTester { } private DhcpPacket getNextDhcpPacket() throws Exception { - final byte[] packet = getNextMatchedPacket((p) -> { + final byte[] packet = getDownloadPacket((p) -> { // Test whether this is DHCP packet. try { DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2); @@ -213,7 +220,7 @@ public final class TetheringTester { tethered.ipv4Addr.getAddress() /* sender IP */, (short) ARP_REPLY); try { - sendPacket(arpReply); + sendUploadPacket(arpReply); } catch (Exception e) { fail("Failed to reply ARP for " + tethered.ipv4Addr); } @@ -227,9 +234,9 @@ public final class TetheringTester { tetherMac.toByteArray() /* srcMac */, routerIp.getAddress() /* target IP */, new byte[ETHER_ADDR_LEN] /* target HW address */, tetherIp.getAddress() /* sender IP */, (short) ARP_REQUEST); - sendPacket(arpProbe); + sendUploadPacket(arpProbe); - final byte[] packet = getNextMatchedPacket((p) -> { + final byte[] packet = getDownloadPacket((p) -> { final ArpPacket arpPacket = parseArpPacket(p); if (arpPacket == null || arpPacket.opCode != ARP_REPLY) return false; return arpPacket.targetIp.equals(tetherIp); @@ -252,7 +259,7 @@ public final class TetheringTester { // connectivity is ready. We don't extract the router mac address from RA because // we get the router mac address from IPv4 ARP packet. See #getRouterMacAddressFromArp. for (int i = 0; i < READ_RA_ATTEMPTS; i++) { - final byte[] raPacket = getNextMatchedPacket((p) -> { + final byte[] raPacket = getDownloadPacket((p) -> { return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT); }); if (raPacket != null) return; @@ -290,13 +297,10 @@ public final class TetheringTester { private Inet6Address runSlaac(MacAddress srcMac, MacAddress dstMac) throws Exception { sendRsPacket(srcMac, dstMac); - final byte[] raPacket = getNextMatchedPacket((p) -> { + final byte[] raPacket = verifyPacketNotNull("Receive RA fail", getDownloadPacket(p -> { return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT); - }); + })); - if (raPacket == null) { - fail("Could not get ra for prefix options"); - } final List options = getRaPrefixOptions(raPacket); for (PrefixInformationOption pio : options) { @@ -322,7 +326,7 @@ public final class TetheringTester { ByteBuffer rs = Ipv6Utils.buildRsPacket(srcMac, dstMac, (Inet6Address) LINK_LOCAL, IPV6_ADDR_ALL_NODES_MULTICAST, slla); - sendPacket(rs); + sendUploadPacket(rs); } private void maybeReplyNa(byte[] packet) { @@ -347,7 +351,7 @@ public final class TetheringTester { ByteBuffer ns = Ipv6Utils.buildNaPacket(tethered.macAddr, tethered.routerMacAddr, nsHdr.target, ipv6Hdr.srcIp, flags, nsHdr.target, tlla); try { - sendPacket(ns); + sendUploadPacket(ns); } catch (Exception e) { fail("Failed to reply NA for " + tethered.ipv6Addr); } @@ -380,11 +384,17 @@ public final class TetheringTester { return false; } - public void sendPacket(ByteBuffer packet) throws Exception { + private void sendUploadPacket(ByteBuffer packet) throws Exception { mDownstreamReader.sendResponse(packet); } - public byte[] getNextMatchedPacket(Predicate filter) { + private void sendDownloadPacket(ByteBuffer packet) throws Exception { + assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader); + + mUpstreamReader.sendResponse(packet); + } + + private byte[] getDownloadPacket(Predicate filter) { byte[] packet; while ((packet = mDownstreamReader.poll(PACKET_READ_TIMEOUT_MS)) != null) { if (filter.test(packet)) return packet; @@ -396,30 +406,34 @@ public final class TetheringTester { return null; } - public void verifyUpload(final RemoteResponder dst, final ByteBuffer packet, - final Predicate filter) throws Exception { - sendPacket(packet); - assertNotNull("Upload fail", dst.getNextMatchedPacket(filter)); + private byte[] getUploadPacket(Predicate filter) { + assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader); + + return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter); } - public static class RemoteResponder { - final TapPacketReader mUpstreamReader; - public RemoteResponder(TapPacketReader reader) { - mUpstreamReader = reader; - } + private @NonNull byte[] verifyPacketNotNull(String message, @Nullable byte[] packet) { + assertNotNull(message, packet); - public void sendPacket(ByteBuffer packet) throws Exception { - mUpstreamReader.sendResponse(packet); - } + return packet; + } - public byte[] getNextMatchedPacket(Predicate filter) throws Exception { - return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter); - } + public byte[] testUpload(final ByteBuffer packet, final Predicate filter) + throws Exception { + sendUploadPacket(packet); - public void verifyDownload(final TetheringTester dst, final ByteBuffer packet, - final Predicate filter) throws Exception { - sendPacket(packet); - assertNotNull("Download fail", dst.getNextMatchedPacket(filter)); - } + return getUploadPacket(filter); + } + + public byte[] verifyUpload(final ByteBuffer packet, final Predicate filter) + throws Exception { + return verifyPacketNotNull("Upload fail", testUpload(packet, filter)); + } + + public byte[] verifyDownload(final ByteBuffer packet, final Predicate filter) + throws Exception { + sendDownloadPacket(packet); + + return verifyPacketNotNull("Download fail", getDownloadPacket(filter)); } }