Merge "Statistics Northbound Test"
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / packet / ICMP.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 package org.opendaylight.controller.sal.packet;
11
12 import java.util.HashMap;
13 import java.util.LinkedHashMap;
14 import java.util.Map;
15
16 import org.apache.commons.lang3.tuple.ImmutablePair;
17 import org.apache.commons.lang3.tuple.Pair;
18 import org.opendaylight.controller.sal.utils.NetUtils;
19
20 /**
21  * Class that represents the ICMP packet objects
22  */
23
24 public class ICMP extends Packet {
25     private static final String TYPE = "Type";
26     private static final String CODE = "Code";
27     private static final String CHECKSUM = "Checksum";
28     private static final String IDENTIFIER = "Identifier";
29     private static final String SEQNUMBER = "SequenceNumber";
30
31     private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
32         private static final long serialVersionUID = 1L;
33         {
34             put(TYPE, new ImmutablePair<Integer, Integer>(0, 8));
35             put(CODE, new ImmutablePair<Integer, Integer>(8, 8));
36             put(CHECKSUM, new ImmutablePair<Integer, Integer>(16, 16));
37             put(IDENTIFIER, new ImmutablePair<Integer, Integer>(32, 16));
38             put(SEQNUMBER, new ImmutablePair<Integer, Integer>(48, 16));
39         }
40     };
41
42     /**
43      * Default constructor that creates and sets the hash map values
44      */
45     public ICMP() {
46         super();
47         fieldValues = new HashMap<String, byte[]>();
48         hdrFieldCoordMap = fieldCoordinates;
49         hdrFieldsMap = fieldValues;
50     }
51
52     /**
53      * Constructor that sets the access level for the packet
54      */
55     public ICMP(boolean writeAccess) {
56         super(writeAccess);
57         fieldValues = new HashMap<String, byte[]>();
58         hdrFieldCoordMap = fieldCoordinates;
59         hdrFieldsMap = fieldValues;
60     }
61
62     private final Map<String, byte[]> fieldValues;
63
64     @Override
65     public void setHeaderField(String headerField, byte[] readValue) {
66         hdrFieldsMap.put(headerField, readValue);
67     }
68
69     /**
70      * Sets the type for the current ICMP message
71      * 
72      * @param type
73      *            The ICMP message type
74      * @return This ICMP object
75      */
76     public ICMP setType(byte type) {
77         byte[] icmpType = BitBufferHelper.toByteArray(type);
78         fieldValues.put(TYPE, icmpType);
79         return this;
80     }
81
82     /**
83      * Sets the ICMP code (type subtype) for the current ICMP object instance
84      * 
85      * @param code
86      *            The ICMP message type subtype
87      * @return This ICMP object
88      */
89     public ICMP setCode(byte code) {
90         byte[] icmpCode = BitBufferHelper.toByteArray(code);
91         fieldValues.put(CODE, icmpCode);
92         return this;
93     }
94
95     /**
96      * Sets the ICMP checksum  for the current ICMP object instance
97      * @param short - checksum
98      * @return ICMP
99      */
100     public ICMP setChecksum(short checksum) {
101         byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum);
102         fieldValues.put(CHECKSUM, icmpChecksum);
103         return this;
104     }
105
106     /**
107      * Sets the ICMP identifier  for the current ICMP object instance
108      * @param short - identifier
109      * @return ICMP
110      */
111     public ICMP setIdentifier(short identifier) {
112         byte[] icmpIdentifier = BitBufferHelper.toByteArray(identifier);
113         fieldValues.put(IDENTIFIER, icmpIdentifier);
114         return this;
115     }
116
117     /**
118      * Sets the ICMP sequence number for the current ICMP object instance
119      * @param short - seqNumber
120      * @return ICMP
121      */
122     public ICMP setSequenceNumber(short seqNumber) {
123         byte[] icmpSeqNumber = BitBufferHelper.toByteArray(seqNumber);
124         fieldValues.put(SEQNUMBER, icmpSeqNumber);
125         return this;
126     }
127
128     /**
129      * Gets the header size in bits
130      * @return The ICMP header size in bits
131      */
132     @Override
133     public int getHeaderSize() {
134         return 64;
135     }
136
137     /**
138      * Computes the ICMP checksum on the serialized ICMP message
139      * 
140      * @param serialized
141      *            The data stream
142      * @param start
143      *            The byte index on the data stream from which the ICMP packet
144      *            starts
145      * @return The checksum
146      */
147     short computeChecksum(byte[] data, int start) {
148         int sum = 0, carry = 0, finalSum = 0;
149         int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte
150                 + rawPayload.length;
151         int checksumStartByte = start + getfieldOffset(CHECKSUM)
152                 / NetUtils.NumBitsInAByte;
153
154         for (int i = start; i <= (end - 1); i = i + 2) {
155             // Skip, if the current bytes are checkSum bytes
156             if (i == checksumStartByte) {
157                 continue;
158             }
159             StringBuffer sbuffer = new StringBuffer();
160             sbuffer.append(String.format("%02X", data[i]));
161             if (i < (data.length - 1)) {
162                 sbuffer.append(String.format("%02X", data[i + 1]));
163             }
164             sum += Integer.valueOf(sbuffer.toString(), 16);
165         }
166         carry = (sum >> 16) & 0xFF;
167         finalSum = (sum & 0xFFFF) + carry;
168         return (short) ~((short) finalSum & 0xFFFF);
169     }
170
171     @Override
172     protected void postSerializeCustomOperation(byte[] serializedBytes)
173             throws PacketException {
174         byte[] checkSum = BitBufferHelper
175                 .toByteArray(computeChecksum(serializedBytes, 0));
176         try {
177             BitBufferHelper.setBytes(serializedBytes, checkSum,
178                     getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
179         } catch (BufferException e) {
180             throw new PacketException(e.getMessage());
181         }
182     }
183
184     @Override
185     protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
186         short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte);
187         short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
188
189         if (computedChecksum != actualChecksum) {
190             corrupted = true;
191         }
192     }
193
194     /**
195      * Gets the checksum value stored
196      * @return the checksum
197      */
198     public short getChecksum() {
199         return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));
200     }
201 }