Fix javadoc failures in genius
[genius.git] / mdsalutil / mdsalutil-api / src / main / java / org / opendaylight / genius / mdsalutil / packet / ICMP.java
1 /*
2  * Copyright (c) 2013 - 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.genius.mdsalutil.packet;
10
11 import java.util.HashMap;
12 import java.util.LinkedHashMap;
13 import java.util.Map;
14 import org.apache.commons.lang3.tuple.ImmutablePair;
15 import org.apache.commons.lang3.tuple.Pair;
16 import org.opendaylight.openflowplugin.libraries.liblldp.BitBufferHelper;
17 import org.opendaylight.openflowplugin.libraries.liblldp.BufferException;
18 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
19 import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
20
21 /**
22  * Class that represents the ICMP packet objects.
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     @SuppressWarnings("serial")
32     private static final Map<String, Pair<Integer, Integer>> FIELD_COORDINATES
33         = new LinkedHashMap<String, Pair<Integer, Integer>>() { {
34                 put(TYPE, new ImmutablePair<>(0, 8));
35                 put(CODE, new ImmutablePair<>(8, 8));
36                 put(CHECKSUM, new ImmutablePair<>(16, 16));
37                 put(IDENTIFIER, new ImmutablePair<>(32, 16));
38                 put(SEQNUMBER, new ImmutablePair<>(48, 16));
39             }
40         };
41
42     /**
43      * Default constructor that creates and sets the hash map values.
44      */
45     public ICMP() {
46         fieldValues = new HashMap<>();
47         hdrFieldCoordMap = FIELD_COORDINATES;
48         hdrFieldsMap = fieldValues;
49     }
50
51     /**
52      * Constructor that sets the access level for the packet.
53      * @param writeAccess - boolean
54      */
55     public ICMP(boolean writeAccess) {
56         super(writeAccess);
57         fieldValues = new HashMap<>();
58         hdrFieldCoordMap = FIELD_COORDINATES;
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      * Returns the type field of the current ICMP packet.
84      *
85      * @return The type code of the current ICMP packet
86      */
87     public byte getType() {
88         return BitBufferHelper.getByte(fieldValues.get(TYPE));
89     }
90
91     /**
92      * Sets the ICMP code (type subtype) for the current ICMP object instance.
93      *
94      * @param code
95      *            The ICMP message type subtype
96      * @return This ICMP object
97      */
98     public ICMP setCode(byte code) {
99         byte[] icmpCode = BitBufferHelper.toByteArray(code);
100         fieldValues.put(CODE, icmpCode);
101         return this;
102     }
103
104     /**
105      * Gets the ICMP code (type subtype) for the current ICMP object instance.
106      *
107      * @return The ICMP message type subtype
108      */
109     public byte getCode() {
110         return BitBufferHelper.getByte(fieldValues.get(CODE));
111     }
112
113     /**
114      * Sets the ICMP checksum  for the current ICMP object instance.
115      * @param checksum - short
116      * @return ICMP
117      */
118     public ICMP setChecksum(short checksum) {
119         byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum);
120         fieldValues.put(CHECKSUM, icmpChecksum);
121         return this;
122     }
123
124     /**
125      * Sets the ICMP identifier for the current ICMP object instance.
126      * @param identifier - short
127      * @return ICMP
128      */
129     public ICMP setIdentifier(short identifier) {
130         byte[] icmpIdentifier = BitBufferHelper.toByteArray(identifier);
131         fieldValues.put(IDENTIFIER, icmpIdentifier);
132         return this;
133     }
134
135     /**
136      * Gets the ICMP identifier of the current ICMP object instance.
137      *
138      * @return short - identifier
139      */
140     public short getIdentifier() {
141         return BitBufferHelper.getShort(fieldValues.get(IDENTIFIER));
142     }
143
144     /**
145      * Sets the ICMP sequence number for the current ICMP object instance.
146      * @param seqNumber  sequence number
147      * @return sequence number
148      */
149     public ICMP setSequenceNumber(short seqNumber) {
150         byte[] icmpSeqNumber = BitBufferHelper.toByteArray(seqNumber);
151         fieldValues.put(SEQNUMBER, icmpSeqNumber);
152         return this;
153     }
154
155     /**
156      * Gets the ICMP sequence number of the current ICMP object instance.
157      *
158      * @return short - seqNumber
159      */
160     public short getSequenceNumber() {
161         return BitBufferHelper.getShort(fieldValues.get(SEQNUMBER));
162     }
163
164     /**
165      * Gets the header size in bits.
166      * @return The ICMP header size in bits
167      */
168     @Override
169     public int getHeaderSize() {
170         return 64;
171     }
172
173     /**
174      * Computes the ICMP checksum on the serialized ICMP message..
175      *
176      * @param data
177      *            The serialized data stream
178      * @param start
179      *            The byte index on the data stream from which the ICMP packet
180      *            starts
181      * @return The checksum
182      */
183     short computeChecksum(byte[] data, int start) {
184         int sum = 0;
185         int wordData;
186         int end = start + this.getHeaderSize() / Byte.SIZE;
187         if (rawPayload != null) {
188             end += rawPayload.length;
189         }
190         int checksumStartByte = start + getfieldOffset(CHECKSUM) / Byte.SIZE;
191         int even = end & ~1;
192
193         for (int i = start; i < even; i = i + 2) {
194             // Skip, if the current bytes are checkSum bytes
195             if (i == checksumStartByte) {
196                 continue;
197             }
198             wordData = (data[i] << 8 & 0xFF00) + (data[i + 1] & 0xFF);
199             sum = sum + wordData;
200         }
201         if (even < end) {
202             // Add the last octet with zero padding.
203             wordData = data[even] << 8 & 0xFF00;
204             sum = sum + wordData;
205         }
206
207         int carry = sum >>> 16;
208         int finalSum = (sum & 0xFFFF) + carry;
209         return (short) ~((short) finalSum & 0xFFFF);
210     }
211
212     @Override
213     protected void postSerializeCustomOperation(byte[] serializedBytes)
214             throws PacketException {
215         byte[] checkSum = BitBufferHelper
216                 .toByteArray(computeChecksum(serializedBytes, 0));
217         try {
218             BitBufferHelper.setBytes(serializedBytes, checkSum,
219                     getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
220         } catch (BufferException e) {
221             throw new PacketException(e.getMessage(), e);
222         }
223     }
224
225     @Override
226     protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
227         short computedChecksum = computeChecksum(data, endBitOffset / Byte.SIZE);
228         short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
229
230         if (computedChecksum != actualChecksum) {
231             corrupted = true;
232         }
233     }
234
235     /**
236      * Gets the checksum value stored.
237      * @return the checksum
238      */
239     public short getChecksum() {
240         return BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
241     }
242 }