diff --git a/staticlibs/framework/com/android/net/module/util/IpUtils.java b/staticlibs/framework/com/android/net/module/util/IpUtils.java index 569733edad..18d96f30a0 100644 --- a/staticlibs/framework/com/android/net/module/util/IpUtils.java +++ b/staticlibs/framework/com/android/net/module/util/IpUtils.java @@ -16,6 +16,8 @@ package com.android.net.module.util; +import com.android.internal.annotations.VisibleForTesting; + import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; @@ -42,8 +44,9 @@ public class IpUtils { * payload) or ICMP checksum on the specified portion of a ByteBuffer. The seed * allows the checksum to commence with a specified value. */ - private static int checksum(ByteBuffer buf, int seed, int start, int end) { - int sum = seed; + @VisibleForTesting + public static int checksum(ByteBuffer buf, int seed, int start, int end) { + int sum = seed + 0xFFFF; // to make things work with empty / zero-filled buffer final int bufPosition = buf.position(); // set position of original ByteBuffer, so that the ShortBuffer @@ -69,13 +72,12 @@ public class IpUtils { b += 256; } - sum += b * 256; + sum += b * 256; // assumes bytebuffer is network order (ie. big endian) } - sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); - sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); - int negated = ~sum; - return intAbs((short) negated); + sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); // max sum is 0x1FFFE + sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); // max sum is 0xFFFF + return sum ^ 0xFFFF; // u16 bitwise negation } private static int pseudoChecksumIPv4( diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java index 20555b353b..d57023caf1 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java @@ -73,6 +73,20 @@ public class IpUtilsTest { // "hello") // print JavaPacketDefinition(str(packet)) + @Test + public void testEmptyAndZeroBufferChecksum() throws Exception { + ByteBuffer packet = ByteBuffer.wrap(new byte[] { (byte) 0x00, (byte) 0x00, }); + // the following should *not* return 0xFFFF + assertEquals(0, IpUtils.checksum(packet, 0, 0, 0)); + assertEquals(0, IpUtils.checksum(packet, 0, 0, 1)); + assertEquals(0, IpUtils.checksum(packet, 0, 0, 2)); + assertEquals(0, IpUtils.checksum(packet, 0, 1, 2)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 0, 0)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 0, 1)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 0, 2)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 1, 2)); + } + @Test public void testIpv6TcpChecksum() throws Exception { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) /