Fix NPE in ICMP.computeChecksum()
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / packet / ICMP.java
index d1f81c5775f5d9952d9ef1a2fcde2f22248de11f..b2a1cfe8c2824b8bfab8a4b737d949e9d67df446 100644 (file)
@@ -13,34 +13,29 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.sal.utils.NetUtils;
 
 /**
  * Class that represents the ICMP packet objects
- *
- *
  */
 
 public class ICMP extends Packet {
-    private static final String TYPECODE = "TypeCode";
+    private static final String TYPE = "Type";
     private static final String CODE = "Code";
-    private static final String HEADERCHECKSUM = "HeaderChecksum";
+    private static final String CHECKSUM = "Checksum";
     private static final String IDENTIFIER = "Identifier";
     private static final String SEQNUMBER = "SequenceNumber";
 
     private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
         private static final long serialVersionUID = 1L;
-
         {
-            put(TYPECODE, new ImmutablePair<Integer, Integer>(0, 8));
+            put(TYPE, new ImmutablePair<Integer, Integer>(0, 8));
             put(CODE, new ImmutablePair<Integer, Integer>(8, 8));
-            put(HEADERCHECKSUM, new ImmutablePair<Integer, Integer>(16, 16));
+            put(CHECKSUM, new ImmutablePair<Integer, Integer>(16, 16));
             put(IDENTIFIER, new ImmutablePair<Integer, Integer>(32, 16));
             put(SEQNUMBER, new ImmutablePair<Integer, Integer>(48, 16));
-
         }
     };
 
@@ -64,7 +59,7 @@ public class ICMP extends Packet {
         hdrFieldsMap = fieldValues;
     }
 
-    private Map<String, byte[]> fieldValues;
+    private final Map<String, byte[]> fieldValues;
 
     @Override
     public void setHeaderField(String headerField, byte[] readValue) {
@@ -72,13 +67,28 @@ public class ICMP extends Packet {
     }
 
     /**
-     * Sets the TypeCode of ICMP  for the current ICMP object instance
-     * @param short - typeCode
-     * @return ICMP
+     * Sets the type for the current ICMP message
+     *
+     * @param type
+     *            The ICMP message type
+     * @return This ICMP object
+     */
+    public ICMP setType(byte type) {
+        byte[] icmpType = BitBufferHelper.toByteArray(type);
+        fieldValues.put(TYPE, icmpType);
+        return this;
+    }
+
+    /**
+     * Sets the ICMP code (type subtype) for the current ICMP object instance
+     *
+     * @param code
+     *            The ICMP message type subtype
+     * @return This ICMP object
      */
-    public ICMP setTypeCode(short typeCode) {
-        byte[] icmpTypeCode = BitBufferHelper.toByteArray(typeCode);
-        fieldValues.put(TYPECODE, icmpTypeCode);
+    public ICMP setCode(byte code) {
+        byte[] icmpCode = BitBufferHelper.toByteArray(code);
+        fieldValues.put(CODE, icmpCode);
         return this;
     }
 
@@ -89,7 +99,7 @@ public class ICMP extends Packet {
      */
     public ICMP setChecksum(short checksum) {
         byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum);
-        fieldValues.put(HEADERCHECKSUM, icmpChecksum);
+        fieldValues.put(CHECKSUM, icmpChecksum);
         return this;
     }
 
@@ -115,13 +125,75 @@ public class ICMP extends Packet {
         return this;
     }
 
+    /**
+     * Gets the header size in bits
+     * @return The ICMP header size in bits
+     */
+    @Override
+    public int getHeaderSize() {
+        return 64;
+    }
+
+    /**
+     * Computes the ICMP checksum on the serialized ICMP message
+     *
+     * @param serialized
+     *            The data stream
+     * @param start
+     *            The byte index on the data stream from which the ICMP packet
+     *            starts
+     * @return The checksum
+     */
+    short computeChecksum(byte[] data, int start) {
+        int sum = 0, carry = 0, finalSum = 0;
+        int wordData;
+        int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte;
+        if (rawPayload != null) {
+            end += rawPayload.length;
+        }
+        int checksumStartByte = start + getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte;
+
+        for (int i = start; i <= (end - 1); i = i + 2) {
+            // Skip, if the current bytes are checkSum bytes
+            if (i == checksumStartByte) {
+                continue;
+            }
+            wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF);
+            sum = sum + wordData;
+        }
+        carry = (sum >> 16) & 0xFF;
+        finalSum = (sum & 0xFFFF) + carry;
+        return (short) ~((short) finalSum & 0xFFFF);
+    }
+
     @Override
-    public int hashCode() {
-        return HashCodeBuilder.reflectionHashCode(this);
+    protected void postSerializeCustomOperation(byte[] serializedBytes)
+            throws PacketException {
+        byte[] checkSum = BitBufferHelper
+                .toByteArray(computeChecksum(serializedBytes, 0));
+        try {
+            BitBufferHelper.setBytes(serializedBytes, checkSum,
+                    getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
+        } catch (BufferException e) {
+            throw new PacketException(e.getMessage());
+        }
     }
 
     @Override
-    public boolean equals(Object obj) {
-        return EqualsBuilder.reflectionEquals(this, obj);
+    protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
+        short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte);
+        short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
+
+        if (computedChecksum != actualChecksum) {
+            corrupted = true;
+        }
+    }
+
+    /**
+     * Gets the checksum value stored
+     * @return the checksum
+     */
+    public short getChecksum() {
+        return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));
     }
 }