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 * Sets the ICMP code (type subtype) for the current ICMP object instance
86 * The ICMP message type subtype
87 * @return This ICMP object
89 public ICMP setCode(byte code) {
90 byte[] icmpCode = BitBufferHelper.toByteArray(code);
91 fieldValues.put(CODE, icmpCode);
96 * Sets the ICMP checksum for the current ICMP object instance
97 * @param short - checksum
100 public ICMP setChecksum(short checksum) {
101 byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum);
102 fieldValues.put(CHECKSUM, icmpChecksum);
107 * Sets the ICMP identifier for the current ICMP object instance
108 * @param short - identifier
111 public ICMP setIdentifier(short identifier) {
112 byte[] icmpIdentifier = BitBufferHelper.toByteArray(identifier);
113 fieldValues.put(IDENTIFIER, icmpIdentifier);
118 * Sets the ICMP sequence number for the current ICMP object instance
119 * @param short - seqNumber
122 public ICMP setSequenceNumber(short seqNumber) {
123 byte[] icmpSeqNumber = BitBufferHelper.toByteArray(seqNumber);
124 fieldValues.put(SEQNUMBER, icmpSeqNumber);
129 * Gets the header size in bits
130 * @return The ICMP header size in bits
133 public int getHeaderSize() {
138 * Computes the ICMP checksum on the serialized ICMP message
143 * The byte index on the data stream from which the ICMP packet
145 * @return The checksum
147 short computeChecksum(byte[] data, int start) {
148 int sum = 0, carry = 0, finalSum = 0;
150 int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte
152 int checksumStartByte = start + getfieldOffset(CHECKSUM)
153 / NetUtils.NumBitsInAByte;
155 for (int i = start; i <= (end - 1); i = i + 2) {
156 // Skip, if the current bytes are checkSum bytes
157 if (i == checksumStartByte) {
160 wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF);
161 sum = sum + wordData;
163 carry = (sum >> 16) & 0xFF;
164 finalSum = (sum & 0xFFFF) + carry;
165 return (short) ~((short) finalSum & 0xFFFF);
169 protected void postSerializeCustomOperation(byte[] serializedBytes)
170 throws PacketException {
171 byte[] checkSum = BitBufferHelper
172 .toByteArray(computeChecksum(serializedBytes, 0));
174 BitBufferHelper.setBytes(serializedBytes, checkSum,
175 getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
176 } catch (BufferException e) {
177 throw new PacketException(e.getMessage());
182 protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
183 short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte);
184 short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
186 if (computedChecksum != actualChecksum) {
192 * Gets the checksum value stored
193 * @return the checksum
195 public short getChecksum() {
196 return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));