ICMPv6 checksum calculation fixed in ICMPv6.java

Change-Id: I4ac4a9138e9256318c0345668e7692f2778c136e
diff --git a/utils/misc/src/main/java/org/onlab/packet/ICMP6.java b/utils/misc/src/main/java/org/onlab/packet/ICMP6.java
index bb4f204..fbbc9ef 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ICMP6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ICMP6.java
@@ -127,13 +127,35 @@
         }
 
         final byte[] data = new byte[HEADER_LENGTH + payloadLength];
-        final ByteBuffer bb = ByteBuffer.wrap(data);
+        final ByteBuffer bbData = ByteBuffer.wrap(data);
 
-        bb.put(this.icmpType);
-        bb.put(this.icmpCode);
-        bb.putShort(this.checksum);
+        // Creating ByteBuffer for checksum calculation
+        final byte[] checksumData =
+            new byte[IPv6.FIXED_HEADER_LENGTH + HEADER_LENGTH + payloadLength];
+        final ByteBuffer bbChecksum = ByteBuffer.wrap(checksumData);
+
+        //
+        // Creating IPv6 Pseudo Header for checksum calculation according
+        // to RFC 4443 and RFC 2460
+        //
+        bbChecksum.put(((IPv6) this.parent).getSourceAddress());
+        bbChecksum.put(((IPv6) this.parent).getDestinationAddress());
+        bbChecksum.putInt(HEADER_LENGTH + payloadLength);
+        bbChecksum.put((byte) 0);
+        bbChecksum.put((byte) 0);
+        bbChecksum.put((byte) 0);
+        bbChecksum.put(IPv6.PROTOCOL_ICMP6);
+        bbChecksum.put(this.icmpType);
+        bbChecksum.put(this.icmpCode);
+        bbChecksum.put((byte) 0);
+        bbChecksum.put((byte) 0);
+
+        bbData.put(this.icmpType);
+        bbData.put(this.icmpCode);
+        bbData.putShort(this.checksum);
         if (payloadData != null) {
-            bb.put(payloadData);
+            bbData.put(payloadData);
+            bbChecksum.put(payloadData);
         }
 
         if (this.parent != null && this.parent instanceof IPv6) {
@@ -142,21 +164,22 @@
 
         // compute checksum if needed
         if (this.checksum == 0) {
-            bb.rewind();
+            bbData.rewind();
+            bbChecksum.rewind();
             int accumulation = 0;
 
-            for (int i = 0; i < data.length / 2; ++i) {
-                accumulation += 0xffff & bb.getShort();
+            for (int i = 0; i < checksumData.length / 2; ++i) {
+                accumulation += 0xffff & bbChecksum.getShort();
             }
             // pad to an even number of shorts
-            if (data.length % 2 > 0) {
-                accumulation += (bb.get() & 0xff) << 8;
+            if (checksumData.length % 2 > 0) {
+                accumulation += (bbChecksum.get() & 0xff) << 8;
             }
 
             accumulation = (accumulation >> 16 & 0xffff)
                     + (accumulation & 0xffff);
             this.checksum = (short) (~accumulation & 0xffff);
-            bb.putShort(2, this.checksum);
+            bbData.putShort(2, this.checksum);
         }
         return data;
     }