blob: d07a9ba4831a25f965e2345266610fb6f866839f [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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
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.
27 *
alshabibc4901cd2014-09-05 16:50:40 -070028 */
29public class ICMP extends BasePacket {
30 protected byte icmpType;
31 protected byte icmpCode;
32 protected short checksum;
33
sangho5eaf0332015-03-09 15:08:12 -070034 public static final byte TYPE_ECHO_REQUEST = 0x08;
35 public static final byte TYPE_ECHO_REPLY = 0x00;
36 public static final byte SUBTYPE_ECHO_REPLY = 0x00;
37
Jonathan Hart2a655752015-04-07 16:46:33 -070038 public static final short ICMP_HEADER_LENGTH = 4;
39
alshabibc4901cd2014-09-05 16:50:40 -070040 /**
41 * @return the icmpType
42 */
43 public byte getIcmpType() {
44 return this.icmpType;
45 }
46
47 /**
48 * @param icmpType
49 * to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080050 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070051 */
52 public ICMP setIcmpType(final byte icmpType) {
53 this.icmpType = icmpType;
54 return this;
55 }
56
57 /**
58 * @return the icmp code
59 */
60 public byte getIcmpCode() {
61 return this.icmpCode;
62 }
63
64 /**
65 * @param icmpCode
66 * code to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080067 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070068 */
69 public ICMP setIcmpCode(final byte icmpCode) {
70 this.icmpCode = icmpCode;
71 return this;
72 }
73
74 /**
75 * @return the checksum
76 */
77 public short getChecksum() {
78 return this.checksum;
79 }
80
81 /**
82 * @param checksum
83 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080084 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070085 */
86 public ICMP setChecksum(final short checksum) {
87 this.checksum = checksum;
88 return this;
89 }
90
91 /**
92 * Serializes the packet. Will compute and set the following fields if they
93 * are set to specific values at the time serialize is called: -checksum : 0
94 * -length : 0
95 */
96 @Override
97 public byte[] serialize() {
98 int length = 4;
99 byte[] payloadData = null;
100 if (this.payload != null) {
101 this.payload.setParent(this);
102 payloadData = this.payload.serialize();
103 length += payloadData.length;
104 }
105
106 final byte[] data = new byte[length];
107 final ByteBuffer bb = ByteBuffer.wrap(data);
108
109 bb.put(this.icmpType);
110 bb.put(this.icmpCode);
111 bb.putShort(this.checksum);
112 if (payloadData != null) {
113 bb.put(payloadData);
114 }
115
116 if (this.parent != null && this.parent instanceof IPv4) {
117 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_ICMP);
118 }
119
120 // compute checksum if needed
121 if (this.checksum == 0) {
122 bb.rewind();
123 int accumulation = 0;
124
125 for (int i = 0; i < length / 2; ++i) {
126 accumulation += 0xffff & bb.getShort();
127 }
128 // pad to an even number of shorts
129 if (length % 2 > 0) {
130 accumulation += (bb.get() & 0xff) << 8;
131 }
132
133 accumulation = (accumulation >> 16 & 0xffff)
134 + (accumulation & 0xffff);
135 this.checksum = (short) (~accumulation & 0xffff);
136 bb.putShort(2, this.checksum);
137 }
138 return data;
139 }
140
Jonathan Hart2a655752015-04-07 16:46:33 -0700141 @Override
142 public IPacket deserialize(final byte[] data, final int offset,
143 final int length) {
144 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
145 this.icmpType = bb.get();
146 this.icmpCode = bb.get();
147 this.checksum = bb.getShort();
148
149 this.payload = new Data();
150 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
151 - bb.position());
152 this.payload.setParent(this);
153 return this;
154 }
155
alshabibc4901cd2014-09-05 16:50:40 -0700156 /*
157 * (non-Javadoc)
158 *
159 * @see java.lang.Object#hashCode()
160 */
161 @Override
162 public int hashCode() {
163 final int prime = 5807;
164 int result = super.hashCode();
165 result = prime * result + this.icmpType;
166 result = prime * result + this.icmpCode;
167 result = prime * result + this.checksum;
168 return result;
169 }
170
171 /*
172 * (non-Javadoc)
173 *
174 * @see java.lang.Object#equals(java.lang.Object)
175 */
176 @Override
177 public boolean equals(final Object obj) {
178 if (this == obj) {
179 return true;
180 }
181 if (!super.equals(obj)) {
182 return false;
183 }
184 if (!(obj instanceof ICMP)) {
185 return false;
186 }
187 final ICMP other = (ICMP) obj;
188 if (this.icmpType != other.icmpType) {
189 return false;
190 }
191 if (this.icmpCode != other.icmpCode) {
192 return false;
193 }
194 if (this.checksum != other.checksum) {
195 return false;
196 }
197 return true;
198 }
199
Jonathan Hart2a655752015-04-07 16:46:33 -0700200 /**
201 * Deserializer function for ICMP packets.
202 *
203 * @return deserializer function
204 */
205 public static Deserializer<ICMP> deserializer() {
206 return (data, offset, length) -> {
207 checkInput(data, offset, length, ICMP_HEADER_LENGTH);
alshabibc4901cd2014-09-05 16:50:40 -0700208
Jonathan Hart2a655752015-04-07 16:46:33 -0700209 ICMP icmp = new ICMP();
210
211 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
212 icmp.icmpType = bb.get();
213 icmp.icmpCode = bb.get();
214 icmp.checksum = bb.getShort();
215
216 icmp.payload = Data.deserializer()
217 .deserialize(data, bb.position(), bb.limit()
218 - bb.position());
219 icmp.payload.setParent(icmp);
220 return icmp;
221 };
alshabibc4901cd2014-09-05 16:50:40 -0700222 }
223}