blob: 410be78f59b8a6ed48cb2d0c508ca231462cfc49 [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 -070018
19package org.onlab.packet;
20
21import java.nio.ByteBuffer;
HIGUCHI Yutad57cdc42015-09-04 14:59:06 -070022import java.util.Arrays;
alshabibc4901cd2014-09-05 16:50:40 -070023
Jian Li5fc14292015-12-04 11:30:46 -080024import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070025import static org.onlab.packet.PacketUtils.*;
26
alshabibc4901cd2014-09-05 16:50:40 -070027/**
Charles M.C. Chan197a0122015-04-08 18:15:34 +080028 * Implements TCP packet format.
alshabibc4901cd2014-09-05 16:50:40 -070029 */
30
31public class TCP extends BasePacket {
Jonathan Hart2a655752015-04-07 16:46:33 -070032
33 private static final short TCP_HEADER_LENGTH = 20;
34
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070035 protected int sourcePort;
36 protected int destinationPort;
alshabibc4901cd2014-09-05 16:50:40 -070037 protected int sequence;
38 protected int acknowledge;
39 protected byte dataOffset;
40 protected short flags;
41 protected short windowSize;
42 protected short checksum;
43 protected short urgentPointer;
44 protected byte[] options;
45
46 /**
Charles M.C. Chan197a0122015-04-08 18:15:34 +080047 * Gets TCP source port.
48 *
49 * @return TCP source port
alshabibc4901cd2014-09-05 16:50:40 -070050 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070051 public int getSourcePort() {
alshabibc4901cd2014-09-05 16:50:40 -070052 return this.sourcePort;
53 }
54
55 /**
Charles M.C. Chan197a0122015-04-08 18:15:34 +080056 * Sets TCP source port.
57 *
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070058 * @param sourcePort the sourcePort to set (unsigned 16 bits integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080059 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070060 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070061 public TCP setSourcePort(final int sourcePort) {
alshabibc4901cd2014-09-05 16:50:40 -070062 this.sourcePort = sourcePort;
63 return this;
64 }
65
66 /**
Charles M.C. Chan197a0122015-04-08 18:15:34 +080067 * Gets TCP destination port.
68 *
alshabibc4901cd2014-09-05 16:50:40 -070069 * @return the destinationPort
70 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070071 public int getDestinationPort() {
alshabibc4901cd2014-09-05 16:50:40 -070072 return this.destinationPort;
73 }
74
75 /**
Charles M.C. Chan197a0122015-04-08 18:15:34 +080076 * Sets TCP destination port.
77 *
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070078 * @param destinationPort the destinationPort to set (unsigned 16 bits integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080079 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070080 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070081 public TCP setDestinationPort(final int destinationPort) {
alshabibc4901cd2014-09-05 16:50:40 -070082 this.destinationPort = destinationPort;
83 return this;
84 }
85
86 /**
Charles M.C. Chan197a0122015-04-08 18:15:34 +080087 * Gets checksum.
88 *
alshabibc4901cd2014-09-05 16:50:40 -070089 * @return the checksum
90 */
91 public short getChecksum() {
92 return this.checksum;
93 }
94
Charles M.C. Chan197a0122015-04-08 18:15:34 +080095 /**
96 * Sets checksum.
97 *
98 * @param checksum the checksum to set
99 * @return this
100 */
101 public TCP setChecksum(final short checksum) {
102 this.checksum = checksum;
103 return this;
104 }
105
106 /**
107 * Gets sequence number.
108 *
109 * @return the sequence number
110 */
alshabibc4901cd2014-09-05 16:50:40 -0700111 public int getSequence() {
112 return this.sequence;
113 }
114
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800115 /**
116 * Sets sequence number.
117 *
118 * @param seq the sequence number to set
119 * @return this
120 */
alshabibc4901cd2014-09-05 16:50:40 -0700121 public TCP setSequence(final int seq) {
122 this.sequence = seq;
123 return this;
124 }
125
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800126 /**
127 * Gets acknowledge number.
128 *
129 * @return the acknowledge number
130 */
alshabibc4901cd2014-09-05 16:50:40 -0700131 public int getAcknowledge() {
132 return this.acknowledge;
133 }
134
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800135 /**
136 * Sets acknowledge number.
137 *
138 * @param ack the acknowledge number to set
139 * @return this
140 */
alshabibc4901cd2014-09-05 16:50:40 -0700141 public TCP setAcknowledge(final int ack) {
142 this.acknowledge = ack;
143 return this;
144 }
145
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800146 /**
147 * Gets offset.
148 *
149 * @return the offset
150 */
alshabibc4901cd2014-09-05 16:50:40 -0700151 public byte getDataOffset() {
152 return this.dataOffset;
153 }
154
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800155 /**
156 * Sets offset.
157 *
158 * @param offset the offset to set
159 * @return this
160 */
alshabibc4901cd2014-09-05 16:50:40 -0700161 public TCP setDataOffset(final byte offset) {
162 this.dataOffset = offset;
163 return this;
164 }
165
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800166 /**
167 * Gets TCP flags.
168 *
169 * @return the TCP flags
170 */
alshabibc4901cd2014-09-05 16:50:40 -0700171 public short getFlags() {
172 return this.flags;
173 }
174
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800175 /**
176 * Sets TCP flags.
177 *
178 * @param flags the TCP flags to set
179 * @return this
180 */
alshabibc4901cd2014-09-05 16:50:40 -0700181 public TCP setFlags(final short flags) {
182 this.flags = flags;
183 return this;
184 }
185
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800186 /**
187 * Gets TCP window size.
188 *
189 * @return the TCP window size
190 */
alshabibc4901cd2014-09-05 16:50:40 -0700191 public short getWindowSize() {
192 return this.windowSize;
193 }
194
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800195 /**
196 * Sets TCP window size.
197 *
198 * @param windowSize the TCP window size to set
199 * @return this
200 */
alshabibc4901cd2014-09-05 16:50:40 -0700201 public TCP setWindowSize(final short windowSize) {
202 this.windowSize = windowSize;
203 return this;
204 }
205
alshabibc4901cd2014-09-05 16:50:40 -0700206 @Override
207 public void resetChecksum() {
208 this.checksum = 0;
209 super.resetChecksum();
210 }
211
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800212 /**
213 * Gets urgent pointer.
214 *
215 * @return the urgent pointer
216 */
217 public short getUrgentPointer() {
alshabibc4901cd2014-09-05 16:50:40 -0700218 return this.urgentPointer;
219 }
220
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800221 /**
222 * Sets urgent pointer.
223 *
224 * @param urgentPointer the urgent pointer to set
225 * @return this
226 */
alshabibc4901cd2014-09-05 16:50:40 -0700227 public TCP setUrgentPointer(final short urgentPointer) {
228 this.urgentPointer = urgentPointer;
229 return this;
230 }
231
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800232 /**
233 * Gets TCP options.
234 *
235 * @return the TCP options
236 */
alshabibc4901cd2014-09-05 16:50:40 -0700237 public byte[] getOptions() {
238 return this.options;
239 }
240
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800241 /**
242 * Sets TCP options.
243 *
244 * @param options the options to set
245 * @return this
246 */
alshabibc4901cd2014-09-05 16:50:40 -0700247 public TCP setOptions(final byte[] options) {
248 this.options = options;
249 this.dataOffset = (byte) (20 + options.length + 3 >> 2);
250 return this;
251 }
252
253 /**
alshabibc4901cd2014-09-05 16:50:40 -0700254 * Serializes the packet. Will compute and set the following fields if they
255 * are set to specific values at the time serialize is called: -checksum : 0
256 * -length : 0
257 */
258 @Override
259 public byte[] serialize() {
260 int length;
261 if (this.dataOffset == 0) {
262 this.dataOffset = 5; // default header length
263 }
264 length = this.dataOffset << 2;
265 byte[] payloadData = null;
266 if (this.payload != null) {
267 this.payload.setParent(this);
268 payloadData = this.payload.serialize();
269 length += payloadData.length;
270 }
271
272 final byte[] data = new byte[length];
273 final ByteBuffer bb = ByteBuffer.wrap(data);
274
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700275 bb.putShort((short) (this.sourcePort & 0xffff));
276 bb.putShort((short) (this.destinationPort & 0xffff));
alshabibc4901cd2014-09-05 16:50:40 -0700277 bb.putInt(this.sequence);
278 bb.putInt(this.acknowledge);
279 bb.putShort((short) (this.flags | this.dataOffset << 12));
280 bb.putShort(this.windowSize);
281 bb.putShort(this.checksum);
282 bb.putShort(this.urgentPointer);
283 if (this.dataOffset > 5) {
284 int padding;
285 bb.put(this.options);
286 padding = (this.dataOffset << 2) - 20 - this.options.length;
287 for (int i = 0; i < padding; i++) {
288 bb.put((byte) 0);
289 }
290 }
291 if (payloadData != null) {
292 bb.put(payloadData);
293 }
294
295 if (this.parent != null && this.parent instanceof IPv4) {
296 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_TCP);
297 }
298
299 // compute checksum if needed
300 if (this.checksum == 0) {
301 bb.rewind();
302 int accumulation = 0;
303
304 // compute pseudo header mac
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800305 if (this.parent != null) {
306 if (this.parent instanceof IPv4) {
307 final IPv4 ipv4 = (IPv4) this.parent;
308 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
309 + (ipv4.getSourceAddress() & 0xffff);
310 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
311 + (ipv4.getDestinationAddress() & 0xffff);
312 accumulation += ipv4.getProtocol() & 0xff;
313 accumulation += length & 0xffff;
314 } else if (this.parent instanceof IPv6) {
315 final IPv6 ipv6 = (IPv6) this.parent;
316 final int bbLength =
317 Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
318 + 2 // nextHeader (with padding)
319 + 4; // length
320 final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
321 bbChecksum.put(ipv6.getSourceAddress());
322 bbChecksum.put(ipv6.getDestinationAddress());
323 bbChecksum.put((byte) 0); // padding
324 bbChecksum.put(ipv6.getNextHeader());
325 bbChecksum.putInt(length);
326 bbChecksum.rewind();
327 for (int i = 0; i < bbLength / 2; ++i) {
328 accumulation += 0xffff & bbChecksum.getShort();
329 }
330 }
alshabibc4901cd2014-09-05 16:50:40 -0700331 }
332
333 for (int i = 0; i < length / 2; ++i) {
334 accumulation += 0xffff & bb.getShort();
335 }
336 // pad to an even number of shorts
337 if (length % 2 > 0) {
338 accumulation += (bb.get() & 0xff) << 8;
339 }
340
341 accumulation = (accumulation >> 16 & 0xffff)
342 + (accumulation & 0xffff);
343 this.checksum = (short) (~accumulation & 0xffff);
344 bb.putShort(16, this.checksum);
345 }
346 return data;
347 }
348
Jonathan Hart2a655752015-04-07 16:46:33 -0700349
alshabibc4901cd2014-09-05 16:50:40 -0700350 /*
351 * (non-Javadoc)
352 *
353 * @see java.lang.Object#hashCode()
354 */
355 @Override
356 public int hashCode() {
357 final int prime = 5807;
358 int result = super.hashCode();
359 result = prime * result + this.checksum;
360 result = prime * result + this.destinationPort;
361 result = prime * result + this.sourcePort;
362 return result;
363 }
364
365 /*
366 * (non-Javadoc)
367 *
368 * @see java.lang.Object#equals(java.lang.Object)
369 */
370 @Override
371 public boolean equals(final Object obj) {
372 if (this == obj) {
373 return true;
374 }
375 if (!super.equals(obj)) {
376 return false;
377 }
378 if (!(obj instanceof TCP)) {
379 return false;
380 }
381 final TCP other = (TCP) obj;
382 // May want to compare fields based on the flags set
383 return this.checksum == other.checksum
384 && this.destinationPort == other.destinationPort
385 && this.sourcePort == other.sourcePort
386 && this.sequence == other.sequence
387 && this.acknowledge == other.acknowledge
388 && this.dataOffset == other.dataOffset
389 && this.flags == other.flags
390 && this.windowSize == other.windowSize
391 && this.urgentPointer == other.urgentPointer
HIGUCHI Yutad57cdc42015-09-04 14:59:06 -0700392 && (this.dataOffset == 5 || Arrays.equals(this.options, other.options));
alshabibc4901cd2014-09-05 16:50:40 -0700393 }
394
Jonathan Hart2a655752015-04-07 16:46:33 -0700395 /**
396 * Deserializer function for TCP packets.
397 *
398 * @return deserializer function
399 */
400 public static Deserializer<TCP> deserializer() {
401 return (data, offset, length) -> {
402 checkInput(data, offset, length, TCP_HEADER_LENGTH);
alshabibc4901cd2014-09-05 16:50:40 -0700403
Jonathan Hart2a655752015-04-07 16:46:33 -0700404 TCP tcp = new TCP();
405
406 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700407 tcp.sourcePort = (bb.getShort() & 0xffff);
408 tcp.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700409 tcp.sequence = bb.getInt();
410 tcp.acknowledge = bb.getInt();
411 tcp.flags = bb.getShort();
412 tcp.dataOffset = (byte) (tcp.flags >> 12 & 0xf);
413 tcp.flags = (short) (tcp.flags & 0x1ff);
414 tcp.windowSize = bb.getShort();
415 tcp.checksum = bb.getShort();
416 tcp.urgentPointer = bb.getShort();
417 if (tcp.dataOffset > 5) {
418 int optLength = (tcp.dataOffset << 2) - 20;
Charles Chan7796c112018-04-02 17:54:03 -0700419 checkHeaderLength(length, TCP_HEADER_LENGTH + optLength);
Jonathan Hart2a655752015-04-07 16:46:33 -0700420 tcp.options = new byte[optLength];
421 bb.get(tcp.options, 0, optLength);
422 }
423
424 tcp.payload = Data.deserializer()
425 .deserialize(data, bb.position(), bb.limit() - bb.position());
426 tcp.payload.setParent(tcp);
427 return tcp;
428 };
alshabibc4901cd2014-09-05 16:50:40 -0700429 }
Jian Li5fc14292015-12-04 11:30:46 -0800430
431 @Override
432 public String toString() {
433 return toStringHelper(getClass())
434 .add("sourcePort", Integer.toString(sourcePort))
435 .add("destinationPort", Integer.toString(destinationPort))
436 .add("sequence", Integer.toString(sequence))
437 .add("acknowledge", Integer.toString(acknowledge))
438 .add("dataOffset", Byte.toString(dataOffset))
439 .add("flags", Short.toString(flags))
440 .add("windowSize", Short.toString(windowSize))
441 .add("checksum", Short.toString(checksum))
442 .add("urgentPointer", Short.toString(urgentPointer))
443 .add("options", Arrays.toString(options))
444 .toString();
445 }
alshabibc4901cd2014-09-05 16:50:40 -0700446}