blob: e832517ed3d5fc199876dbd6719b724ce31371e3 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
alshabibc4901cd2014-09-05 16:50:40 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
alshabibc4901cd2014-09-05 16:50:40 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
16
17
alshabibc4901cd2014-09-05 16:50:40 -070018
19package org.onlab.packet;
20
21import java.nio.ByteBuffer;
22
23/**
24 * Implements ICMP packet format.
25 *
alshabibc4901cd2014-09-05 16:50:40 -070026 */
27public class ICMP extends BasePacket {
28 protected byte icmpType;
29 protected byte icmpCode;
30 protected short checksum;
31
sangho5eaf0332015-03-09 15:08:12 -070032 public static final byte TYPE_ECHO_REQUEST = 0x08;
33 public static final byte TYPE_ECHO_REPLY = 0x00;
34 public static final byte SUBTYPE_ECHO_REPLY = 0x00;
35
alshabibc4901cd2014-09-05 16:50:40 -070036 /**
37 * @return the icmpType
38 */
39 public byte getIcmpType() {
40 return this.icmpType;
41 }
42
43 /**
44 * @param icmpType
45 * to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080046 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070047 */
48 public ICMP setIcmpType(final byte icmpType) {
49 this.icmpType = icmpType;
50 return this;
51 }
52
53 /**
54 * @return the icmp code
55 */
56 public byte getIcmpCode() {
57 return this.icmpCode;
58 }
59
60 /**
61 * @param icmpCode
62 * code to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080063 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070064 */
65 public ICMP setIcmpCode(final byte icmpCode) {
66 this.icmpCode = icmpCode;
67 return this;
68 }
69
70 /**
71 * @return the checksum
72 */
73 public short getChecksum() {
74 return this.checksum;
75 }
76
77 /**
78 * @param checksum
79 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080080 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070081 */
82 public ICMP setChecksum(final short checksum) {
83 this.checksum = checksum;
84 return this;
85 }
86
87 /**
88 * Serializes the packet. Will compute and set the following fields if they
89 * are set to specific values at the time serialize is called: -checksum : 0
90 * -length : 0
91 */
92 @Override
93 public byte[] serialize() {
94 int length = 4;
95 byte[] payloadData = null;
96 if (this.payload != null) {
97 this.payload.setParent(this);
98 payloadData = this.payload.serialize();
99 length += payloadData.length;
100 }
101
102 final byte[] data = new byte[length];
103 final ByteBuffer bb = ByteBuffer.wrap(data);
104
105 bb.put(this.icmpType);
106 bb.put(this.icmpCode);
107 bb.putShort(this.checksum);
108 if (payloadData != null) {
109 bb.put(payloadData);
110 }
111
112 if (this.parent != null && this.parent instanceof IPv4) {
113 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_ICMP);
114 }
115
116 // compute checksum if needed
117 if (this.checksum == 0) {
118 bb.rewind();
119 int accumulation = 0;
120
121 for (int i = 0; i < length / 2; ++i) {
122 accumulation += 0xffff & bb.getShort();
123 }
124 // pad to an even number of shorts
125 if (length % 2 > 0) {
126 accumulation += (bb.get() & 0xff) << 8;
127 }
128
129 accumulation = (accumulation >> 16 & 0xffff)
130 + (accumulation & 0xffff);
131 this.checksum = (short) (~accumulation & 0xffff);
132 bb.putShort(2, this.checksum);
133 }
134 return data;
135 }
136
137 /*
138 * (non-Javadoc)
139 *
140 * @see java.lang.Object#hashCode()
141 */
142 @Override
143 public int hashCode() {
144 final int prime = 5807;
145 int result = super.hashCode();
146 result = prime * result + this.icmpType;
147 result = prime * result + this.icmpCode;
148 result = prime * result + this.checksum;
149 return result;
150 }
151
152 /*
153 * (non-Javadoc)
154 *
155 * @see java.lang.Object#equals(java.lang.Object)
156 */
157 @Override
158 public boolean equals(final Object obj) {
159 if (this == obj) {
160 return true;
161 }
162 if (!super.equals(obj)) {
163 return false;
164 }
165 if (!(obj instanceof ICMP)) {
166 return false;
167 }
168 final ICMP other = (ICMP) obj;
169 if (this.icmpType != other.icmpType) {
170 return false;
171 }
172 if (this.icmpCode != other.icmpCode) {
173 return false;
174 }
175 if (this.checksum != other.checksum) {
176 return false;
177 }
178 return true;
179 }
180
181 @Override
182 public IPacket deserialize(final byte[] data, final int offset,
183 final int length) {
184 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
185 this.icmpType = bb.get();
186 this.icmpCode = bb.get();
187 this.checksum = bb.getShort();
188
189 this.payload = new Data();
190 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
191 - bb.position());
192 this.payload.setParent(this);
193 return this;
194 }
195}