5075e58281132a4404ab8473be01e05ea5305115
[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 wordData;
150         int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte
151                 + rawPayload.length;
152         int checksumStartByte = start + getfieldOffset(CHECKSUM)
153                 / NetUtils.NumBitsInAByte;
154
155         for (int i = start; i <= (end - 1); i = i + 2) {
156             // Skip, if the current bytes are checkSum bytes
157             if (i == checksumStartByte) {
158                 continue;
159             }
160             wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF);
161             sum = sum + wordData;
162         }
163         carry = (sum >> 16) & 0xFF;
164         finalSum = (sum & 0xFFFF) + carry;
165         return (short) ~((short) finalSum & 0xFFFF);
166     }
167
168     @Override
169     protected void postSerializeCustomOperation(byte[] serializedBytes)
170             throws PacketException {
171         byte[] checkSum = BitBufferHelper
172                 .toByteArray(computeChecksum(serializedBytes, 0));
173         try {
174             BitBufferHelper.setBytes(serializedBytes, checkSum,
175                     getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
176         } catch (BufferException e) {
177             throw new PacketException(e.getMessage());
178         }
179     }
180
181     @Override
182     protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
183         short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte);
184         short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
185
186         if (computedChecksum != actualChecksum) {
187             corrupted = true;
188         }
189     }
190
191     /**
192      * Gets the checksum value stored
193      * @return the checksum
194      */
195     public short getChecksum() {
196         return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));
197     }
198 }