blob: 5e0cfb234b21643319c5fb614c522c669b511529 [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
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080049 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070050 */
51 public TCP setSourcePort(final short sourcePort) {
52 this.sourcePort = sourcePort;
53 return this;
54 }
55
56 /**
57 * @return the destinationPort
58 */
59 public short getDestinationPort() {
60 return this.destinationPort;
61 }
62
63 /**
64 * @param destinationPort
65 * the destinationPort to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080066 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070067 */
68 public TCP setDestinationPort(final short destinationPort) {
69 this.destinationPort = destinationPort;
70 return this;
71 }
72
73 /**
74 * @return the checksum
75 */
76 public short getChecksum() {
77 return this.checksum;
78 }
79
80 public int getSequence() {
81 return this.sequence;
82 }
83
84 public TCP setSequence(final int seq) {
85 this.sequence = seq;
86 return this;
87 }
88
89 public int getAcknowledge() {
90 return this.acknowledge;
91 }
92
93 public TCP setAcknowledge(final int ack) {
94 this.acknowledge = ack;
95 return this;
96 }
97
98 public byte getDataOffset() {
99 return this.dataOffset;
100 }
101
102 public TCP setDataOffset(final byte offset) {
103 this.dataOffset = offset;
104 return this;
105 }
106
107 public short getFlags() {
108 return this.flags;
109 }
110
111 public TCP setFlags(final short flags) {
112 this.flags = flags;
113 return this;
114 }
115
116 public short getWindowSize() {
117 return this.windowSize;
118 }
119
120 public TCP setWindowSize(final short windowSize) {
121 this.windowSize = windowSize;
122 return this;
123 }
124
125 public short getTcpChecksum() {
126 return this.checksum;
127 }
128
129 public TCP setTcpChecksum(final short checksum) {
130 this.checksum = checksum;
131 return this;
132 }
133
134 @Override
135 public void resetChecksum() {
136 this.checksum = 0;
137 super.resetChecksum();
138 }
139
140 public short getUrgentPointer(final short urgentPointer) {
141 return this.urgentPointer;
142 }
143
144 public TCP setUrgentPointer(final short urgentPointer) {
145 this.urgentPointer = urgentPointer;
146 return this;
147 }
148
149 public byte[] getOptions() {
150 return this.options;
151 }
152
153 public TCP setOptions(final byte[] options) {
154 this.options = options;
155 this.dataOffset = (byte) (20 + options.length + 3 >> 2);
156 return this;
157 }
158
159 /**
160 * @param checksum
161 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800162 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700163 */
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}