[TestOnly] Move isExpectedUdpPacket into TetheringTester

isExpectedUdpPacket and isIcmpv6Type is similar util, put them in the
same place and have isExpectedIpPacket to share the ip/eth parsing code.

Test: atest EthernetTetheringTest
Change-Id: I3ede46f5ff1799f575fad7aca277f2bc0bf6c391
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 21eb899..85ed75c 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -26,7 +26,8 @@
 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.isIcmpv6Type;
+import static android.net.TetheringTester.isExpectedIcmpv6Packet;
+import static android.net.TetheringTester.isExpectedUdpPacket;
 import static android.system.OsConstants.IPPROTO_IP;
 import static android.system.OsConstants.IPPROTO_IPV6;
 import static android.system.OsConstants.IPPROTO_UDP;
@@ -82,10 +83,7 @@
 import com.android.net.module.util.bpf.Tether4Value;
 import com.android.net.module.util.bpf.TetherStatsKey;
 import com.android.net.module.util.bpf.TetherStatsValue;
-import com.android.net.module.util.structs.EthernetHeader;
-import com.android.net.module.util.structs.Ipv4Header;
 import com.android.net.module.util.structs.Ipv6Header;
-import com.android.net.module.util.structs.UdpHeader;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -332,7 +330,7 @@
         final long deadline = SystemClock.uptimeMillis() + timeoutMs;
         do {
             byte[] pkt = reader.popPacket(timeoutMs);
-            if (isIcmpv6Type(pkt, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return;
+            if (isExpectedIcmpv6Packet(pkt, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return;
 
             timeoutMs = deadline - SystemClock.uptimeMillis();
         } while (timeoutMs > 0);
@@ -832,14 +830,14 @@
         tester.verifyUpload(request, p -> {
             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
 
-            return isIcmpv6Type(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
+            return isExpectedIcmpv6Packet(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
         });
 
         ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
         tester.verifyDownload(reply, p -> {
             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
 
-            return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
+            return isExpectedIcmpv6Packet(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
         });
     }
 
@@ -872,28 +870,6 @@
     private static final ByteBuffer PAYLOAD3 =
             ByteBuffer.wrap(new byte[] { (byte) 0x9a, (byte) 0xbc });
 
-    private boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEther,
-            boolean isIpv4, @NonNull final ByteBuffer payload) {
-        final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
-
-        if (hasEther) {
-            if (Struct.parse(EthernetHeader.class, buf) == null) return false;
-        }
-
-        if (isIpv4) {
-            if (Struct.parse(Ipv4Header.class, buf) == null) return false;
-        } else {
-            if (Struct.parse(Ipv6Header.class, buf) == null) return false;
-        }
-
-        if (Struct.parse(UdpHeader.class, buf) == null) return false;
-
-        if (buf.remaining() != payload.limit()) return false;
-
-        return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
-                payload.array());
-    }
-
     @NonNull
     private ByteBuffer buildUdpPacket(
             @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/src/android/net/TetheringTester.java
index 9df636b..80265fa 100644
--- a/Tethering/tests/integration/src/android/net/TetheringTester.java
+++ b/Tethering/tests/integration/src/android/net/TetheringTester.java
@@ -18,11 +18,13 @@
 
 import static android.net.InetAddresses.parseNumericAddress;
 import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_UDP;
 
 import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
 import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
+import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
@@ -49,11 +51,13 @@
 import com.android.net.module.util.Struct;
 import com.android.net.module.util.structs.EthernetHeader;
 import com.android.net.module.util.structs.Icmpv6Header;
+import com.android.net.module.util.structs.Ipv4Header;
 import com.android.net.module.util.structs.Ipv6Header;
 import com.android.net.module.util.structs.LlaOption;
 import com.android.net.module.util.structs.NsHeader;
 import com.android.net.module.util.structs.PrefixInformationOption;
 import com.android.net.module.util.structs.RaHeader;
+import com.android.net.module.util.structs.UdpHeader;
 import com.android.networkstack.arp.ArpPacket;
 import com.android.testutils.TapPacketReader;
 
@@ -62,6 +66,7 @@
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 import java.util.concurrent.TimeoutException;
@@ -260,7 +265,7 @@
         // we get the router mac address from IPv4 ARP packet. See #getRouterMacAddressFromArp.
         for (int i = 0; i < READ_RA_ATTEMPTS; i++) {
             final byte[] raPacket = getDownloadPacket((p) -> {
-                return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
+                return isExpectedIcmpv6Packet(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
             });
             if (raPacket != null) return;
         }
@@ -270,7 +275,9 @@
 
     private List<PrefixInformationOption> getRaPrefixOptions(byte[] packet) {
         ByteBuffer buf = ByteBuffer.wrap(packet);
-        if (!isIcmpv6Type(buf, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return null;
+        if (!isExpectedIcmpv6Packet(buf, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) {
+            fail("Parsing RA packet fail");
+        }
 
         Struct.parse(RaHeader.class, buf);
         final ArrayList<PrefixInformationOption> pioList = new ArrayList<>();
@@ -298,7 +305,7 @@
         sendRsPacket(srcMac, dstMac);
 
         final byte[] raPacket = verifyPacketNotNull("Receive RA fail", getDownloadPacket(p -> {
-            return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
+            return isExpectedIcmpv6Packet(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
         }));
 
         final List<PrefixInformationOption> options = getRaPrefixOptions(raPacket);
@@ -316,7 +323,7 @@
             }
         }
 
-        fail("Could not get ipv6 address");
+        fail("No available ipv6 prefix");
         return null;
     }
 
@@ -360,23 +367,18 @@
         }
     }
 
-    public static boolean isIcmpv6Type(byte[] packet, boolean hasEth, int type) {
+    public static boolean isExpectedIcmpv6Packet(byte[] packet, boolean hasEth, int type) {
         final ByteBuffer buf = ByteBuffer.wrap(packet);
-        return isIcmpv6Type(buf, hasEth, type);
+        return isExpectedIcmpv6Packet(buf, hasEth, type);
     }
 
-    private static boolean isIcmpv6Type(ByteBuffer buf, boolean hasEth, int type) {
+    private static boolean isExpectedIcmpv6Packet(ByteBuffer buf, boolean hasEth, int type) {
         try {
-            if (hasEth) {
-                final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf);
-                if (ethHdr.etherType != ETHER_TYPE_IPV6) return false;
-            }
+            if (hasEth && !hasExpectedEtherHeader(buf, false /* isIpv4 */)) return false;
 
-            final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf);
-            if (ipv6Hdr.nextHeader != (byte) IPPROTO_ICMPV6) return false;
+            if (!hasExpectedIpHeader(buf, false /* isIpv4 */, IPPROTO_ICMPV6)) return false;
 
-            final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, buf);
-            return icmpv6Hdr.type == (short) type;
+            return Struct.parse(Icmpv6Header.class, buf).type == (short) type;
         } catch (Exception e) {
             // Parsing packet fail means it is not icmpv6 packet.
         }
@@ -384,6 +386,42 @@
         return false;
     }
 
+    private static boolean hasExpectedEtherHeader(@NonNull final ByteBuffer buf, boolean isIpv4)
+            throws Exception {
+        final int expected = isIpv4 ? ETHER_TYPE_IPV4 : ETHER_TYPE_IPV6;
+
+        return Struct.parse(EthernetHeader.class, buf).etherType == expected;
+    }
+
+    private static boolean hasExpectedIpHeader(@NonNull final ByteBuffer buf, boolean isIpv4,
+            int ipProto) throws Exception {
+        if (isIpv4) {
+            return Struct.parse(Ipv4Header.class, buf).protocol == (byte) ipProto;
+        } else {
+            return Struct.parse(Ipv6Header.class, buf).nextHeader == (byte) ipProto;
+        }
+    }
+
+    public static boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEth,
+            boolean isIpv4, @NonNull final ByteBuffer payload) {
+        final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
+        try {
+            if (hasEth && !hasExpectedEtherHeader(buf, isIpv4)) return false;
+
+            if (!hasExpectedIpHeader(buf, isIpv4, IPPROTO_UDP)) return false;
+
+            if (Struct.parse(UdpHeader.class, buf) == null) return false;
+        } catch (Exception e) {
+            // Parsing packet fail means it is not udp packet.
+            return false;
+        }
+
+        if (buf.remaining() != payload.limit()) return false;
+
+        return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
+                payload.array());
+    }
+
     private void sendUploadPacket(ByteBuffer packet) throws Exception {
         mDownstreamReader.sendResponse(packet);
     }