blob: bed5ab9b63592db3149a0930fc206b9631cefb61 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
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 -070018package org.onlab.packet;
19
20import java.nio.ByteBuffer;
21
Jian Li5fc14292015-12-04 11:30:46 -080022import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070023import static org.onlab.packet.PacketUtils.*;
24
alshabibc4901cd2014-09-05 16:50:40 -070025/**
26 * Implements ICMP packet format.
alshabibc4901cd2014-09-05 16:50:40 -070027 */
28public class ICMP extends BasePacket {
29 protected byte icmpType;
30 protected byte icmpCode;
31 protected short checksum;
32
sangho5eaf0332015-03-09 15:08:12 -070033 public static final byte TYPE_ECHO_REQUEST = 0x08;
34 public static final byte TYPE_ECHO_REPLY = 0x00;
35 public static final byte SUBTYPE_ECHO_REPLY = 0x00;
36
Jonathan Hart2a655752015-04-07 16:46:33 -070037 public static final short ICMP_HEADER_LENGTH = 4;
38
alshabibc4901cd2014-09-05 16:50:40 -070039 /**
40 * @return the icmpType
41 */
42 public byte getIcmpType() {
43 return this.icmpType;
44 }
45
46 /**
Jian Li5fc14292015-12-04 11:30:46 -080047 * @param icmpType to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080048 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070049 */
50 public ICMP setIcmpType(final byte icmpType) {
51 this.icmpType = icmpType;
52 return this;
53 }
54
55 /**
56 * @return the icmp code
57 */
58 public byte getIcmpCode() {
59 return this.icmpCode;
60 }
61
62 /**
Jian Li5fc14292015-12-04 11:30:46 -080063 * @param icmpCode code to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080064 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070065 */
66 public ICMP setIcmpCode(final byte icmpCode) {
67 this.icmpCode = icmpCode;
68 return this;
69 }
70
71 /**
72 * @return the checksum
73 */
74 public short getChecksum() {
75 return this.checksum;
76 }
77
78 /**
Jian Li5fc14292015-12-04 11:30:46 -080079 * @param checksum 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
Jonathan Hart2a655752015-04-07 16:46:33 -0700137 @Override
138 public IPacket deserialize(final byte[] data, final int offset,
139 final int length) {
140 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
141 this.icmpType = bb.get();
142 this.icmpCode = bb.get();
143 this.checksum = bb.getShort();
144
145 this.payload = new Data();
146 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
147 - bb.position());
148 this.payload.setParent(this);
149 return this;
150 }
151
alshabibc4901cd2014-09-05 16:50:40 -0700152 /*
153 * (non-Javadoc)
154 *
155 * @see java.lang.Object#hashCode()
156 */
157 @Override
158 public int hashCode() {
159 final int prime = 5807;
160 int result = super.hashCode();
161 result = prime * result + this.icmpType;
162 result = prime * result + this.icmpCode;
163 result = prime * result + this.checksum;
164 return result;
165 }
166
167 /*
168 * (non-Javadoc)
169 *
170 * @see java.lang.Object#equals(java.lang.Object)
171 */
172 @Override
173 public boolean equals(final Object obj) {
174 if (this == obj) {
175 return true;
176 }
177 if (!super.equals(obj)) {
178 return false;
179 }
180 if (!(obj instanceof ICMP)) {
181 return false;
182 }
183 final ICMP other = (ICMP) obj;
184 if (this.icmpType != other.icmpType) {
185 return false;
186 }
187 if (this.icmpCode != other.icmpCode) {
188 return false;
189 }
190 if (this.checksum != other.checksum) {
191 return false;
192 }
193 return true;
194 }
195
Jonathan Hart2a655752015-04-07 16:46:33 -0700196 /**
197 * Deserializer function for ICMP packets.
198 *
199 * @return deserializer function
200 */
201 public static Deserializer<ICMP> deserializer() {
202 return (data, offset, length) -> {
203 checkInput(data, offset, length, ICMP_HEADER_LENGTH);
alshabibc4901cd2014-09-05 16:50:40 -0700204
Jonathan Hart2a655752015-04-07 16:46:33 -0700205 ICMP icmp = new ICMP();
206
207 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
208 icmp.icmpType = bb.get();
209 icmp.icmpCode = bb.get();
210 icmp.checksum = bb.getShort();
211
212 icmp.payload = Data.deserializer()
213 .deserialize(data, bb.position(), bb.limit()
214 - bb.position());
215 icmp.payload.setParent(icmp);
216 return icmp;
217 };
alshabibc4901cd2014-09-05 16:50:40 -0700218 }
Jian Li5fc14292015-12-04 11:30:46 -0800219
220 @Override
221 public String toString() {
222 return toStringHelper(getClass())
223 .add("icmpType", Byte.toString(icmpType))
224 .add("icmpCode", Byte.toString(icmpCode))
225 .add("checksum", Short.toString(checksum))
226 .toString();
227 }
Pier Ventre78e73f62016-12-02 19:59:28 -0800228
229 /**
230 * Builds an ICMP reply using the supplied ICMP request.
231 *
232 * @param ethRequest the Ethernet packet containing the ICMP ECHO request
233 * @return the Ethernet packet containing the ICMP ECHO reply
234 */
235 public static Ethernet buildIcmpReply(Ethernet ethRequest) {
236
237 if (ethRequest.getEtherType() != Ethernet.TYPE_IPV4) {
238 return null;
239 }
240
241 IPv4 ipRequest = (IPv4) ethRequest.getPayload();
242
243 if (ipRequest.getProtocol() != IPv4.PROTOCOL_ICMP) {
244 return null;
245 }
246
247 Ethernet ethReply = new Ethernet();
248 IPv4 ipReply = new IPv4();
249
250 int destAddress = ipRequest.getDestinationAddress();
251 ipReply.setDestinationAddress(ipRequest.getSourceAddress());
252 ipReply.setSourceAddress(destAddress);
253 ipReply.setTtl((byte) 64);
Charles Chane3e18de2017-10-24 15:21:16 -0700254 ipReply.setDiffServ(ipRequest.getDiffServ());
Pier Ventre78e73f62016-12-02 19:59:28 -0800255 ipReply.setChecksum((short) 0);
256 ipReply.setProtocol(IPv4.PROTOCOL_ICMP);
257
258 ICMP icmpRequest = (ICMP) ipRequest.getPayload();
259 ICMP icmpReply = new ICMP();
260
261 icmpReply.setPayload(icmpRequest.getPayload());
262 icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
263 icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
264 icmpReply.setChecksum((short) 0);
265 ipReply.setPayload(icmpReply);
266
267 ethReply.setEtherType(Ethernet.TYPE_IPV4);
268 ethReply.setVlanID(ethRequest.getVlanID());
269 ethReply.setDestinationMACAddress(ethRequest.getSourceMACAddress());
270 ethReply.setSourceMACAddress(ethRequest.getDestinationMACAddress());
271 ethReply.setPayload(ipReply);
272
273
274 return ethReply;
275 }
alshabibc4901cd2014-09-05 16:50:40 -0700276}