blob: 0926a068bcf607af398c6e892c58814a9427da1e [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
alshabibc4901cd2014-09-05 16:50:40 -07009 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
Thomas Vachuska24c849c2014-10-27 09:53:05 -070012 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
alshabibc4901cd2014-09-05 16:50:40 -070017 * under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070018 */
19
20
alshabibc4901cd2014-09-05 16:50:40 -070021
22package org.onlab.packet;
23
24import java.nio.ByteBuffer;
25
26/**
27 *
alshabibc4901cd2014-09-05 16:50:40 -070028 */
29
30public class TCP extends BasePacket {
31 protected short sourcePort;
32 protected short destinationPort;
33 protected int sequence;
34 protected int acknowledge;
35 protected byte dataOffset;
36 protected short flags;
37 protected short windowSize;
38 protected short checksum;
39 protected short urgentPointer;
40 protected byte[] options;
41
42 /**
43 * @return the sourcePort
44 */
45 public short getSourcePort() {
46 return this.sourcePort;
47 }
48
49 /**
50 * @param sourcePort
51 * the sourcePort to set
52 */
53 public TCP setSourcePort(final short sourcePort) {
54 this.sourcePort = sourcePort;
55 return this;
56 }
57
58 /**
59 * @return the destinationPort
60 */
61 public short getDestinationPort() {
62 return this.destinationPort;
63 }
64
65 /**
66 * @param destinationPort
67 * the destinationPort to set
68 */
69 public TCP setDestinationPort(final short destinationPort) {
70 this.destinationPort = destinationPort;
71 return this;
72 }
73
74 /**
75 * @return the checksum
76 */
77 public short getChecksum() {
78 return this.checksum;
79 }
80
81 public int getSequence() {
82 return this.sequence;
83 }
84
85 public TCP setSequence(final int seq) {
86 this.sequence = seq;
87 return this;
88 }
89
90 public int getAcknowledge() {
91 return this.acknowledge;
92 }
93
94 public TCP setAcknowledge(final int ack) {
95 this.acknowledge = ack;
96 return this;
97 }
98
99 public byte getDataOffset() {
100 return this.dataOffset;
101 }
102
103 public TCP setDataOffset(final byte offset) {
104 this.dataOffset = offset;
105 return this;
106 }
107
108 public short getFlags() {
109 return this.flags;
110 }
111
112 public TCP setFlags(final short flags) {
113 this.flags = flags;
114 return this;
115 }
116
117 public short getWindowSize() {
118 return this.windowSize;
119 }
120
121 public TCP setWindowSize(final short windowSize) {
122 this.windowSize = windowSize;
123 return this;
124 }
125
126 public short getTcpChecksum() {
127 return this.checksum;
128 }
129
130 public TCP setTcpChecksum(final short checksum) {
131 this.checksum = checksum;
132 return this;
133 }
134
135 @Override
136 public void resetChecksum() {
137 this.checksum = 0;
138 super.resetChecksum();
139 }
140
141 public short getUrgentPointer(final short urgentPointer) {
142 return this.urgentPointer;
143 }
144
145 public TCP setUrgentPointer(final short urgentPointer) {
146 this.urgentPointer = urgentPointer;
147 return this;
148 }
149
150 public byte[] getOptions() {
151 return this.options;
152 }
153
154 public TCP setOptions(final byte[] options) {
155 this.options = options;
156 this.dataOffset = (byte) (20 + options.length + 3 >> 2);
157 return this;
158 }
159
160 /**
161 * @param checksum
162 * the checksum to set
163 */
164 public TCP setChecksum(final short checksum) {
165 this.checksum = checksum;
166 return this;
167 }
168
169 /**
170 * Serializes the packet. Will compute and set the following fields if they
171 * are set to specific values at the time serialize is called: -checksum : 0
172 * -length : 0
173 */
174 @Override
175 public byte[] serialize() {
176 int length;
177 if (this.dataOffset == 0) {
178 this.dataOffset = 5; // default header length
179 }
180 length = this.dataOffset << 2;
181 byte[] payloadData = null;
182 if (this.payload != null) {
183 this.payload.setParent(this);
184 payloadData = this.payload.serialize();
185 length += payloadData.length;
186 }
187
188 final byte[] data = new byte[length];
189 final ByteBuffer bb = ByteBuffer.wrap(data);
190
191 bb.putShort(this.sourcePort);
192 bb.putShort(this.destinationPort);
193 bb.putInt(this.sequence);
194 bb.putInt(this.acknowledge);
195 bb.putShort((short) (this.flags | this.dataOffset << 12));
196 bb.putShort(this.windowSize);
197 bb.putShort(this.checksum);
198 bb.putShort(this.urgentPointer);
199 if (this.dataOffset > 5) {
200 int padding;
201 bb.put(this.options);
202 padding = (this.dataOffset << 2) - 20 - this.options.length;
203 for (int i = 0; i < padding; i++) {
204 bb.put((byte) 0);
205 }
206 }
207 if (payloadData != null) {
208 bb.put(payloadData);
209 }
210
211 if (this.parent != null && this.parent instanceof IPv4) {
212 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_TCP);
213 }
214
215 // compute checksum if needed
216 if (this.checksum == 0) {
217 bb.rewind();
218 int accumulation = 0;
219
220 // compute pseudo header mac
221 if (this.parent != null && this.parent instanceof IPv4) {
222 final IPv4 ipv4 = (IPv4) this.parent;
223 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
224 + (ipv4.getSourceAddress() & 0xffff);
225 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
226 + (ipv4.getDestinationAddress() & 0xffff);
227 accumulation += ipv4.getProtocol() & 0xff;
228 accumulation += length & 0xffff;
229 }
230
231 for (int i = 0; i < length / 2; ++i) {
232 accumulation += 0xffff & bb.getShort();
233 }
234 // pad to an even number of shorts
235 if (length % 2 > 0) {
236 accumulation += (bb.get() & 0xff) << 8;
237 }
238
239 accumulation = (accumulation >> 16 & 0xffff)
240 + (accumulation & 0xffff);
241 this.checksum = (short) (~accumulation & 0xffff);
242 bb.putShort(16, this.checksum);
243 }
244 return data;
245 }
246
247 /*
248 * (non-Javadoc)
249 *
250 * @see java.lang.Object#hashCode()
251 */
252 @Override
253 public int hashCode() {
254 final int prime = 5807;
255 int result = super.hashCode();
256 result = prime * result + this.checksum;
257 result = prime * result + this.destinationPort;
258 result = prime * result + this.sourcePort;
259 return result;
260 }
261
262 /*
263 * (non-Javadoc)
264 *
265 * @see java.lang.Object#equals(java.lang.Object)
266 */
267 @Override
268 public boolean equals(final Object obj) {
269 if (this == obj) {
270 return true;
271 }
272 if (!super.equals(obj)) {
273 return false;
274 }
275 if (!(obj instanceof TCP)) {
276 return false;
277 }
278 final TCP other = (TCP) obj;
279 // May want to compare fields based on the flags set
280 return this.checksum == other.checksum
281 && this.destinationPort == other.destinationPort
282 && this.sourcePort == other.sourcePort
283 && this.sequence == other.sequence
284 && this.acknowledge == other.acknowledge
285 && this.dataOffset == other.dataOffset
286 && this.flags == other.flags
287 && this.windowSize == other.windowSize
288 && this.urgentPointer == other.urgentPointer
289 && (this.dataOffset == 5 || this.options.equals(other.options));
290 }
291
292 @Override
293 public IPacket deserialize(final byte[] data, final int offset,
294 final int length) {
295 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
296 this.sourcePort = bb.getShort();
297 this.destinationPort = bb.getShort();
298 this.sequence = bb.getInt();
299 this.acknowledge = bb.getInt();
300 this.flags = bb.getShort();
301 this.dataOffset = (byte) (this.flags >> 12 & 0xf);
302 this.flags = (short) (this.flags & 0x1ff);
303 this.windowSize = bb.getShort();
304 this.checksum = bb.getShort();
305 this.urgentPointer = bb.getShort();
306 if (this.dataOffset > 5) {
307 int optLength = (this.dataOffset << 2) - 20;
308 if (bb.limit() < bb.position() + optLength) {
309 optLength = bb.limit() - bb.position();
310 }
311 try {
312 this.options = new byte[optLength];
313 bb.get(this.options, 0, optLength);
314 } catch (final IndexOutOfBoundsException e) {
315 this.options = null;
316 }
317 }
318
319 this.payload = new Data();
320 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
321 - bb.position());
322 this.payload.setParent(this);
323 return this;
324 }
325}