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