blob: 6b6c355e9baa9f214adf9e4956151b2706c8b8fd [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
Ray Milkey269ffb92014-04-03 14:43:30 -07002 * Copyright 2011, Big Switch Networks, Inc.
3 * Originally created by David Erickson, Stanford University
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain
7 * a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 **/
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080017
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070018package net.onrc.onos.core.packet;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080019
20import java.nio.ByteBuffer;
Pavlin Radoslavov35ef8e82014-04-09 16:39:12 -070021import java.util.Arrays;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080022
Pavlin Radoslavov1d595c02014-04-16 14:11:54 -070023import org.apache.commons.lang.ArrayUtils;
24
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080025/**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080026 * @author shudong.zhou@bigswitch.com
27 */
28public class TCP extends BasePacket {
29 protected short sourcePort;
30 protected short destinationPort;
31 protected int sequence;
32 protected int acknowledge;
33 protected byte dataOffset;
34 protected short flags;
35 protected short windowSize;
36 protected short checksum;
37 protected short urgentPointer;
38 protected byte[] options;
39
40 /**
41 * @return the sourcePort
42 */
43 public short getSourcePort() {
44 return sourcePort;
45 }
46
47 /**
48 * @param sourcePort the sourcePort to set
49 */
50 public TCP setSourcePort(short sourcePort) {
51 this.sourcePort = sourcePort;
52 return this;
53 }
54
55 /**
56 * @return the destinationPort
57 */
58 public short getDestinationPort() {
59 return destinationPort;
60 }
61
62 /**
63 * @param destinationPort the destinationPort to set
64 */
65 public TCP setDestinationPort(short destinationPort) {
66 this.destinationPort = destinationPort;
67 return this;
68 }
69
70 /**
71 * @return the checksum
72 */
73 public short getChecksum() {
74 return checksum;
75 }
Ray Milkey269ffb92014-04-03 14:43:30 -070076
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080077 public int getSequence() {
78 return this.sequence;
79 }
Ray Milkey269ffb92014-04-03 14:43:30 -070080
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080081 public TCP setSequence(int seq) {
82 this.sequence = seq;
83 return this;
84 }
Ray Milkey269ffb92014-04-03 14:43:30 -070085
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080086 public int getAcknowledge() {
87 return this.acknowledge;
88 }
Ray Milkey269ffb92014-04-03 14:43:30 -070089
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080090 public TCP setAcknowledge(int ack) {
91 this.acknowledge = ack;
92 return this;
93 }
Ray Milkey269ffb92014-04-03 14:43:30 -070094
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080095 public byte getDataOffset() {
96 return this.dataOffset;
97 }
Ray Milkey269ffb92014-04-03 14:43:30 -070098
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080099 public TCP setDataOffset(byte offset) {
100 this.dataOffset = offset;
101 return this;
102 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700103
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800104 public short getFlags() {
105 return this.flags;
106 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700107
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800108 public TCP setFlags(short flags) {
109 this.flags = flags;
110 return this;
111 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700112
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800113 public short getWindowSize() {
114 return this.windowSize;
115 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700116
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800117 public TCP setWindowSize(short windowSize) {
118 this.windowSize = windowSize;
119 return this;
120 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700121
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800122 public short getTcpChecksum() {
123 return this.checksum;
124 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700125
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800126 public TCP setTcpChecksum(short checksum) {
127 this.checksum = checksum;
128 return this;
129 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700130
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800131 @Override
132 public void resetChecksum() {
133 this.checksum = 0;
134 super.resetChecksum();
135 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700136
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800137 public short getUrgentPointer(short urgentPointer) {
138 return this.urgentPointer;
139 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700140
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800141 public TCP setUrgentPointer(short urgentPointer) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700142 this.urgentPointer = urgentPointer;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800143 return this;
144 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700145
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800146 public byte[] getOptions() {
Pavlin Radoslavov1d595c02014-04-16 14:11:54 -0700147 return ArrayUtils.clone(this.options);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800148 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700149
Pavlin Radoslavovc9bacee2014-04-11 19:02:17 -0700150 public TCP setOptions(final byte[] options) {
Pavlin Radoslavov1d595c02014-04-16 14:11:54 -0700151 this.options = ArrayUtils.clone(options);
152 if (this.options == null) {
Pavlin Radoslavov0a9d5c32014-04-15 17:45:23 -0700153 this.dataOffset = 0;
154 } else {
Pavlin Radoslavov1d595c02014-04-16 14:11:54 -0700155 this.dataOffset = (byte) ((20 + this.options.length + 3) >> 2);
Pavlin Radoslavov0a9d5c32014-04-15 17:45:23 -0700156 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800157 return this;
158 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700159
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800160 /**
161 * @param checksum the checksum to set
162 */
163 public TCP setChecksum(short checksum) {
164 this.checksum = checksum;
165 return this;
166 }
167
168 /**
169 * Serializes the packet. Will compute and set the following fields if they
170 * are set to specific values at the time serialize is called:
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 * -checksum : 0
172 * -length : 0
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800173 */
174 public byte[] serialize() {
175 int length;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700176 if (dataOffset == 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800177 dataOffset = 5; // default header length
Ray Milkeyb29e6262014-04-09 16:02:14 -0700178 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800179 length = dataOffset << 2;
180 byte[] payloadData = null;
181 if (payload != null) {
182 payload.setParent(this);
183 payloadData = payload.serialize();
184 length += payloadData.length;
185 }
186
187 byte[] data = new byte[length];
188 ByteBuffer bb = ByteBuffer.wrap(data);
189
190 bb.putShort(this.sourcePort);
191 bb.putShort(this.destinationPort);
192 bb.putInt(this.sequence);
193 bb.putInt(this.acknowledge);
194 bb.putShort((short) (this.flags | (dataOffset << 12)));
195 bb.putShort(this.windowSize);
196 bb.putShort(this.checksum);
197 bb.putShort(this.urgentPointer);
198 if (dataOffset > 5) {
199 int padding;
200 bb.put(options);
201 padding = (dataOffset << 2) - 20 - options.length;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700202 for (int i = 0; i < padding; i++) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800203 bb.put((byte) 0);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700204 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800205 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700206 if (payloadData != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800207 bb.put(payloadData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700208 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800209
Ray Milkeyb29e6262014-04-09 16:02:14 -0700210 if (this.parent != null && this.parent instanceof IPv4) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_TCP);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700212 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800213
214 // compute checksum if needed
215 if (this.checksum == 0) {
216 bb.rewind();
217 int accumulation = 0;
218
219 // compute pseudo header mac
220 if (this.parent != null && this.parent instanceof IPv4) {
221 IPv4 ipv4 = (IPv4) this.parent;
222 accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
223 + (ipv4.getSourceAddress() & 0xffff);
224 accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
225 + (ipv4.getDestinationAddress() & 0xffff);
226 accumulation += ipv4.getProtocol() & 0xff;
227 accumulation += length & 0xffff;
228 }
229
230 for (int i = 0; i < length / 2; ++i) {
231 accumulation += 0xffff & bb.getShort();
232 }
233 // pad to an even number of shorts
234 if (length % 2 > 0) {
235 accumulation += (bb.get() & 0xff) << 8;
236 }
237
238 accumulation = ((accumulation >> 16) & 0xffff)
239 + (accumulation & 0xffff);
240 this.checksum = (short) (~accumulation & 0xffff);
241 bb.putShort(16, this.checksum);
242 }
243 return data;
244 }
245
246 /* (non-Javadoc)
247 * @see java.lang.Object#hashCode()
248 */
249 @Override
250 public int hashCode() {
251 final int prime = 5807;
252 int result = super.hashCode();
253 result = prime * result + checksum;
254 result = prime * result + destinationPort;
255 result = prime * result + sourcePort;
256 return result;
257 }
258
259 /* (non-Javadoc)
260 * @see java.lang.Object#equals(java.lang.Object)
261 */
262 @Override
263 public boolean equals(Object obj) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700264 if (this == obj) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800265 return true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700266 }
267 if (!super.equals(obj)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800268 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700269 }
270 if (!(obj instanceof TCP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800271 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700272 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800273 TCP other = (TCP) obj;
274 // May want to compare fields based on the flags set
275 return (checksum == other.checksum) &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700276 (destinationPort == other.destinationPort) &&
277 (sourcePort == other.sourcePort) &&
278 (sequence == other.sequence) &&
279 (acknowledge == other.acknowledge) &&
280 (dataOffset == other.dataOffset) &&
281 (flags == other.flags) &&
282 (windowSize == other.windowSize) &&
283 (urgentPointer == other.urgentPointer) &&
Pavlin Radoslavov35ef8e82014-04-09 16:39:12 -0700284 (dataOffset == 5 || Arrays.equals(options, other.options));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800285 }
286
287 @Override
288 public IPacket deserialize(byte[] data, int offset, int length) {
289 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
290 this.sourcePort = bb.getShort();
291 this.destinationPort = bb.getShort();
292 this.sequence = bb.getInt();
293 this.acknowledge = bb.getInt();
294 this.flags = bb.getShort();
295 this.dataOffset = (byte) ((this.flags >> 12) & 0xf);
296 this.flags = (short) (this.flags & 0x1ff);
297 this.windowSize = bb.getShort();
298 this.checksum = bb.getShort();
299 this.urgentPointer = bb.getShort();
300 if (this.dataOffset > 5) {
301 int optLength = (dataOffset << 2) - 20;
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 if (bb.limit() < bb.position() + optLength) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800303 optLength = bb.limit() - bb.position();
304 }
305 try {
306 this.options = new byte[optLength];
307 bb.get(this.options, 0, optLength);
308 } catch (IndexOutOfBoundsException e) {
309 this.options = null;
310 }
311 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700312
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800313 this.payload = new Data();
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800315 this.payload.setParent(this);
316 return this;
317 }
318}