Imported vpnservice as a subtree
[netvirt.git] / vpnservice / mdsalutil / mdsalutil-api / src / main / java / org / opendaylight / vpnservice / 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.vpnservice.mdsalutil.packet;
10
11 import java.util.HashMap;
12 import java.util.LinkedHashMap;
13 import java.util.Map;
14
15 import org.apache.commons.lang3.tuple.ImmutablePair;
16 import org.apache.commons.lang3.tuple.Pair;
17 import org.opendaylight.controller.liblldp.BitBufferHelper;
18 import org.opendaylight.controller.liblldp.BufferException;
19 import org.opendaylight.controller.liblldp.NetUtils;
20 import org.opendaylight.controller.liblldp.Packet;
21 import org.opendaylight.controller.liblldp.PacketException;
22
23 /**
24  * Class that represents the ICMP packet objects
25  */
26
27 public class ICMP extends Packet {
28     private static final String TYPE = "Type";
29     private static final String CODE = "Code";
30     private static final String CHECKSUM = "Checksum";
31     private static final String IDENTIFIER = "Identifier";
32     private static final String SEQNUMBER = "SequenceNumber";
33
34     private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
35         private static final long serialVersionUID = 1L;
36         {
37             put(TYPE, new ImmutablePair<Integer, Integer>(0, 8));
38             put(CODE, new ImmutablePair<Integer, Integer>(8, 8));
39             put(CHECKSUM, new ImmutablePair<Integer, Integer>(16, 16));
40             put(IDENTIFIER, new ImmutablePair<Integer, Integer>(32, 16));
41             put(SEQNUMBER, new ImmutablePair<Integer, Integer>(48, 16));
42         }
43     };
44
45     /**
46      * Default constructor that creates and sets the hash map values
47      */
48     public ICMP() {
49         super();
50         fieldValues = new HashMap<String, byte[]>();
51         hdrFieldCoordMap = fieldCoordinates;
52         hdrFieldsMap = fieldValues;
53     }
54
55     /**
56      * Constructor that sets the access level for the packet
57      * @param writeAccess - boolean
58      */
59     public ICMP(boolean writeAccess) {
60         super(writeAccess);
61         fieldValues = new HashMap<String, byte[]>();
62         hdrFieldCoordMap = fieldCoordinates;
63         hdrFieldsMap = fieldValues;
64     }
65
66     private final Map<String, byte[]> fieldValues;
67
68     @Override
69     public void setHeaderField(String headerField, byte[] readValue) {
70         hdrFieldsMap.put(headerField, readValue);
71     }
72
73     /**
74      * Sets the type for the current ICMP message
75      *
76      * @param type
77      *            The ICMP message type
78      * @return This ICMP object
79      */
80     public ICMP setType(byte type) {
81         byte[] icmpType = BitBufferHelper.toByteArray(type);
82         fieldValues.put(TYPE, icmpType);
83         return this;
84     }
85
86     /**
87      * Returns the type field of the current ICMP packet
88      *
89      * @return The type code of the current ICMP packet
90      */
91     public byte getType() {
92         return BitBufferHelper.getByte(fieldValues.get(TYPE));
93     }
94
95     /**
96      * Sets the ICMP code (type subtype) for the current ICMP object instance
97      *
98      * @param code
99      *            The ICMP message type subtype
100      * @return This ICMP object
101      */
102     public ICMP setCode(byte code) {
103         byte[] icmpCode = BitBufferHelper.toByteArray(code);
104         fieldValues.put(CODE, icmpCode);
105         return this;
106     }
107
108     /**
109      * Gets the ICMP code (type subtype) for the current ICMP object instance
110      *
111      * @return The ICMP message type subtype
112      */
113     public byte getCode() {
114         return BitBufferHelper.getByte(fieldValues.get(CODE));
115     }
116
117     /**
118      * Sets the ICMP checksum  for the current ICMP object instance
119      * @param checksum - short
120      * @return ICMP
121      */
122     public ICMP setChecksum(short checksum) {
123         byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum);
124         fieldValues.put(CHECKSUM, icmpChecksum);
125         return this;
126     }
127
128     /**
129      * Sets the ICMP identifier for the current ICMP object instance
130      * @param identifier - short
131      * @return ICMP
132      */
133     public ICMP setIdentifier(short identifier) {
134         byte[] icmpIdentifier = BitBufferHelper.toByteArray(identifier);
135         fieldValues.put(IDENTIFIER, icmpIdentifier);
136         return this;
137     }
138
139     /**
140      * Gets the ICMP identifier of the current ICMP object instance
141      *
142      * @return short - identifier
143      */
144
145     public short getIdentifier() {
146         return BitBufferHelper.getShort(fieldValues.get(IDENTIFIER));
147     }
148
149     /**
150      * Sets the ICMP sequence number for the current ICMP object instance
151      * @param seqNumber-short
152      * @return ICMP
153      */
154     public ICMP setSequenceNumber(short seqNumber) {
155         byte[] icmpSeqNumber = BitBufferHelper.toByteArray(seqNumber);
156         fieldValues.put(SEQNUMBER, icmpSeqNumber);
157         return this;
158     }
159
160     /**
161      * Gets the ICMP sequence number of the current ICMP object instance
162      *
163      * @return short - seqNumber
164      */
165
166     public short getSequenceNumber() {
167         return BitBufferHelper.getShort(fieldValues.get(SEQNUMBER));
168     }
169
170     /**
171      * Gets the header size in bits
172      * @return The ICMP header size in bits
173      */
174     @Override
175     public int getHeaderSize() {
176         return 64;
177     }
178
179     /**
180      * Computes the ICMP checksum on the serialized ICMP message
181      *
182      * @param data
183      *            The serialized data stream
184      * @param start
185      *            The byte index on the data stream from which the ICMP packet
186      *            starts
187      * @return The checksum
188      */
189     short computeChecksum(byte[] data, int start) {
190         int sum = 0, carry = 0, finalSum = 0;
191         int wordData;
192         int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte;
193         if (rawPayload != null) {
194             end += rawPayload.length;
195         }
196         int checksumStartByte = start + getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte;
197         int even = end & ~1;
198
199         for (int i = start; i < even; i = i + 2) {
200             // Skip, if the current bytes are checkSum bytes
201             if (i == checksumStartByte) {
202                 continue;
203             }
204             wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF);
205             sum = sum + wordData;
206         }
207         if (even < end) {
208             // Add the last octet with zero padding.
209             wordData = (data[even] << 8) & 0xFF00;
210             sum = sum + wordData;
211         }
212
213         carry = sum >>> 16;
214         finalSum = (sum & 0xFFFF) + carry;
215         return (short) ~((short) finalSum & 0xFFFF);
216     }
217
218     @Override
219     protected void postSerializeCustomOperation(byte[] serializedBytes)
220             throws PacketException {
221         byte[] checkSum = BitBufferHelper
222                 .toByteArray(computeChecksum(serializedBytes, 0));
223         try {
224             BitBufferHelper.setBytes(serializedBytes, checkSum,
225                     getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
226         } catch (BufferException e) {
227             throw new PacketException(e.getMessage());
228         }
229     }
230
231     @Override
232     protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
233         short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte);
234         short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
235
236         if (computedChecksum != actualChecksum) {
237             corrupted = true;
238         }
239     }
240
241     /**
242      * Gets the checksum value stored
243      * @return the checksum
244      */
245     public short getChecksum() {
246         return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));
247     }
248 }