Ignore the checksum when comparing RAs for equality.

When comparing two RAs for equality, Ra#matches intentionally
ignores lifetimes. It should ignore the checksum instead, because
otherwise-identical packets with different lifetimes will almost
certainly have different checksums.

In order to avoid the generated APF program also matching the
checksum, we treat the checksum as if it were a lifetime, but
take care not to use its value when calculating mMinLifetime or
when checking the lifetimes in the APF program.

Bug: 27595799
Bug: 26238573
Change-Id: I526fdc17e99803a1ddec6275a3c542014434c429
diff --git a/services/core/java/com/android/server/connectivity/ApfFilter.java b/services/core/java/com/android/server/connectivity/ApfFilter.java
index 25c84e1..4696bd8 100644
--- a/services/core/java/com/android/server/connectivity/ApfFilter.java
+++ b/services/core/java/com/android/server/connectivity/ApfFilter.java
@@ -155,6 +155,9 @@
 
         // From RFC4861:
         private static final int ICMP6_RA_HEADER_LEN = 16;
+        private static final int ICMP6_RA_CHECKSUM_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
+        private static final int ICMP6_RA_CHECKSUM_LEN = 2;
         private static final int ICMP6_RA_OPTION_OFFSET =
                 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
         private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
@@ -216,9 +219,16 @@
             mPacket.clear();
             mLastSeen = curTime();
 
+            // Ignore the checksum.
+            int lastNonLifetimeStart = addNonLifetime(0,
+                    ICMP6_RA_CHECKSUM_OFFSET,
+                    ICMP6_RA_CHECKSUM_LEN);
+
             // Parse router lifetime
-            int lastNonLifetimeStart = addNonLifetime(0, ICMP6_RA_ROUTER_LIFETIME_OFFSET,
+            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
                     ICMP6_RA_ROUTER_LIFETIME_LEN);
+
             // Parse ICMP6 options
             mPacket.position(ICMP6_RA_OPTION_OFFSET);
             while (mPacket.hasRemaining()) {
@@ -282,6 +292,12 @@
             ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
             for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
                 int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
+
+                // The checksum is in mNonLifetimes, but it's not a lifetime.
+                if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
+                     continue;
+                }
+
                 int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
                 long val;
                 switch (lifetimeLength) {
@@ -329,6 +345,10 @@
                 if ((i + 1) < mNonLifetimes.size()) {
                     Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
                     int offset = nonLifetime.first + nonLifetime.second;
+                    // Skip the checksum.
+                    if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
+                        continue;
+                    }
                     int length = nextNonLifetime.first - offset;
                     switch (length) {
                         case 4: gen.addLoad32(Register.R0, offset); break;