3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
10 package org.opendaylight.controller.sal.packet;
12 import java.util.HashMap;
13 import java.util.LinkedHashMap;
16 import org.apache.commons.lang3.tuple.ImmutablePair;
17 import org.apache.commons.lang3.tuple.Pair;
18 import org.opendaylight.controller.sal.utils.NetUtils;
21 * Class that represents the ICMP packet objects
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";
31 private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
32 private static final long serialVersionUID = 1L;
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));
43 * Default constructor that creates and sets the hash map values
47 fieldValues = new HashMap<String, byte[]>();
48 hdrFieldCoordMap = fieldCoordinates;
49 hdrFieldsMap = fieldValues;
53 * Constructor that sets the access level for the packet
55 public ICMP(boolean writeAccess) {
57 fieldValues = new HashMap<String, byte[]>();
58 hdrFieldCoordMap = fieldCoordinates;
59 hdrFieldsMap = fieldValues;
62 private final Map<String, byte[]> fieldValues;
65 public void setHeaderField(String headerField, byte[] readValue) {
66 hdrFieldsMap.put(headerField, readValue);
70 * Sets the type for the current ICMP message
73 * The ICMP message type
74 * @return This ICMP object
76 public ICMP setType(byte type) {
77 byte[] icmpType = BitBufferHelper.toByteArray(type);
78 fieldValues.put(TYPE, icmpType);
83 * Returns the type field of the current ICMP packet
85 * @return The type code of the current ICMP packet
87 public byte getType() {
88 return BitBufferHelper.getByte(fieldValues.get(TYPE));
92 * Sets the ICMP code (type subtype) for the current ICMP object instance
95 * The ICMP message type subtype
96 * @return This ICMP object
98 public ICMP setCode(byte code) {
99 byte[] icmpCode = BitBufferHelper.toByteArray(code);
100 fieldValues.put(CODE, icmpCode);
105 * Gets the ICMP code (type subtype) for the current ICMP object instance
107 * @return The ICMP message type subtype
109 public byte getCode() {
110 return BitBufferHelper.getByte(fieldValues.get(CODE));
114 * Sets the ICMP checksum for the current ICMP object instance
115 * @param short - checksum
118 public ICMP setChecksum(short checksum) {
119 byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum);
120 fieldValues.put(CHECKSUM, icmpChecksum);
125 * Sets the ICMP identifier for the current ICMP object instance
126 * @param short - identifier
129 public ICMP setIdentifier(short identifier) {
130 byte[] icmpIdentifier = BitBufferHelper.toByteArray(identifier);
131 fieldValues.put(IDENTIFIER, icmpIdentifier);
136 * Gets the ICMP identifier of the current ICMP object instance
138 * @return short - identifier
141 public short getIdentifier() {
142 return BitBufferHelper.getShort(fieldValues.get(IDENTIFIER));
146 * Sets the ICMP sequence number for the current ICMP object instance
147 * @param short - seqNumber
150 public ICMP setSequenceNumber(short seqNumber) {
151 byte[] icmpSeqNumber = BitBufferHelper.toByteArray(seqNumber);
152 fieldValues.put(SEQNUMBER, icmpSeqNumber);
157 * Gets the ICMP sequence number of the current ICMP object instance
159 * @return short - seqNumber
162 public short getSequenceNumber() {
163 return BitBufferHelper.getShort(fieldValues.get(SEQNUMBER));
167 * Gets the header size in bits
168 * @return The ICMP header size in bits
171 public int getHeaderSize() {
176 * Computes the ICMP checksum on the serialized ICMP message
181 * The byte index on the data stream from which the ICMP packet
183 * @return The checksum
185 short computeChecksum(byte[] data, int start) {
186 int sum = 0, carry = 0, finalSum = 0;
188 int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte;
189 if (rawPayload != null) {
190 end += rawPayload.length;
192 int checksumStartByte = start + getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte;
194 for (int i = start; i <= (end - 1); i = i + 2) {
195 // Skip, if the current bytes are checkSum bytes
196 if (i == checksumStartByte) {
199 wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF);
200 sum = sum + wordData;
202 carry = (sum >> 16) & 0xFF;
203 finalSum = (sum & 0xFFFF) + carry;
204 return (short) ~((short) finalSum & 0xFFFF);
208 protected void postSerializeCustomOperation(byte[] serializedBytes)
209 throws PacketException {
210 byte[] checkSum = BitBufferHelper
211 .toByteArray(computeChecksum(serializedBytes, 0));
213 BitBufferHelper.setBytes(serializedBytes, checkSum,
214 getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
215 } catch (BufferException e) {
216 throw new PacketException(e.getMessage());
221 protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
222 short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte);
223 short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
225 if (computedChecksum != actualChecksum) {
231 * Gets the checksum value stored
232 * @return the checksum
234 public short getChecksum() {
235 return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));