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