blob: f2f49e1bca9166a5c9fec213a9210f4fc51be552 [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
23/**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080024 * @author shudong.zhou@bigswitch.com
25 */
26public class TCP extends BasePacket {
27 protected short sourcePort;
28 protected short destinationPort;
29 protected int sequence;
30 protected int acknowledge;
31 protected byte dataOffset;
32 protected short flags;
33 protected short windowSize;
34 protected short checksum;
35 protected short urgentPointer;
36 protected byte[] options;
37
38 /**
39 * @return the sourcePort
40 */
41 public short getSourcePort() {
42 return sourcePort;
43 }
44
45 /**
46 * @param sourcePort the sourcePort to set
47 */
48 public TCP setSourcePort(short sourcePort) {
49 this.sourcePort = sourcePort;
50 return this;
51 }
52
53 /**
54 * @return the destinationPort
55 */
56 public short getDestinationPort() {
57 return destinationPort;
58 }
59
60 /**
61 * @param destinationPort the destinationPort to set
62 */
63 public TCP setDestinationPort(short destinationPort) {
64 this.destinationPort = destinationPort;
65 return this;
66 }
67
68 /**
69 * @return the checksum
70 */
71 public short getChecksum() {
72 return checksum;
73 }
Ray Milkey269ffb92014-04-03 14:43:30 -070074
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080075 public int getSequence() {
76 return this.sequence;
77 }
Ray Milkey269ffb92014-04-03 14:43:30 -070078
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080079 public TCP setSequence(int seq) {
80 this.sequence = seq;
81 return this;
82 }
Ray Milkey269ffb92014-04-03 14:43:30 -070083
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080084 public int getAcknowledge() {
85 return this.acknowledge;
86 }
Ray Milkey269ffb92014-04-03 14:43:30 -070087
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080088 public TCP setAcknowledge(int ack) {
89 this.acknowledge = ack;
90 return this;
91 }
Ray Milkey269ffb92014-04-03 14:43:30 -070092
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080093 public byte getDataOffset() {
94 return this.dataOffset;
95 }
Ray Milkey269ffb92014-04-03 14:43:30 -070096
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080097 public TCP setDataOffset(byte offset) {
98 this.dataOffset = offset;
99 return this;
100 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700101
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800102 public short getFlags() {
103 return this.flags;
104 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700105
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800106 public TCP setFlags(short flags) {
107 this.flags = flags;
108 return this;
109 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700110
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800111 public short getWindowSize() {
112 return this.windowSize;
113 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700114
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800115 public TCP setWindowSize(short windowSize) {
116 this.windowSize = windowSize;
117 return this;
118 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700119
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800120 public short getTcpChecksum() {
121 return this.checksum;
122 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700123
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800124 public TCP setTcpChecksum(short checksum) {
125 this.checksum = checksum;
126 return this;
127 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700128
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800129 @Override
130 public void resetChecksum() {
131 this.checksum = 0;
132 super.resetChecksum();
133 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700134
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800135 public short getUrgentPointer(short urgentPointer) {
136 return this.urgentPointer;
137 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700138
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800139 public TCP setUrgentPointer(short urgentPointer) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 this.urgentPointer = urgentPointer;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800141 return this;
142 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700143
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800144 public byte[] getOptions() {
145 return this.options;
146 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700147
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800148 public TCP setOptions(byte[] options) {
149 this.options = options;
150 this.dataOffset = (byte) ((20 + options.length + 3) >> 2);
151 return this;
152 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700153
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800154 /**
155 * @param checksum the checksum to set
156 */
157 public TCP setChecksum(short checksum) {
158 this.checksum = checksum;
159 return this;
160 }
161
162 /**
163 * Serializes the packet. Will compute and set the following fields if they
164 * are set to specific values at the time serialize is called:
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 * -checksum : 0
166 * -length : 0
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800167 */
168 public byte[] serialize() {
169 int length;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700170 if (dataOffset == 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800171 dataOffset = 5; // default header length
Ray Milkeyb29e6262014-04-09 16:02:14 -0700172 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800173 length = dataOffset << 2;
174 byte[] payloadData = null;
175 if (payload != null) {
176 payload.setParent(this);
177 payloadData = payload.serialize();
178 length += payloadData.length;
179 }
180
181 byte[] data = new byte[length];
182 ByteBuffer bb = ByteBuffer.wrap(data);
183
184 bb.putShort(this.sourcePort);
185 bb.putShort(this.destinationPort);
186 bb.putInt(this.sequence);
187 bb.putInt(this.acknowledge);
188 bb.putShort((short) (this.flags | (dataOffset << 12)));
189 bb.putShort(this.windowSize);
190 bb.putShort(this.checksum);
191 bb.putShort(this.urgentPointer);
192 if (dataOffset > 5) {
193 int padding;
194 bb.put(options);
195 padding = (dataOffset << 2) - 20 - options.length;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700196 for (int i = 0; i < padding; i++) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800197 bb.put((byte) 0);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700198 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800199 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700200 if (payloadData != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800201 bb.put(payloadData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700202 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800203
Ray Milkeyb29e6262014-04-09 16:02:14 -0700204 if (this.parent != null && this.parent instanceof IPv4) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_TCP);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700206 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800207
208 // compute checksum if needed
209 if (this.checksum == 0) {
210 bb.rewind();
211 int accumulation = 0;
212
213 // compute pseudo header mac
214 if (this.parent != null && this.parent instanceof IPv4) {
215 IPv4 ipv4 = (IPv4) this.parent;
216 accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
217 + (ipv4.getSourceAddress() & 0xffff);
218 accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
219 + (ipv4.getDestinationAddress() & 0xffff);
220 accumulation += ipv4.getProtocol() & 0xff;
221 accumulation += length & 0xffff;
222 }
223
224 for (int i = 0; i < length / 2; ++i) {
225 accumulation += 0xffff & bb.getShort();
226 }
227 // pad to an even number of shorts
228 if (length % 2 > 0) {
229 accumulation += (bb.get() & 0xff) << 8;
230 }
231
232 accumulation = ((accumulation >> 16) & 0xffff)
233 + (accumulation & 0xffff);
234 this.checksum = (short) (~accumulation & 0xffff);
235 bb.putShort(16, this.checksum);
236 }
237 return data;
238 }
239
240 /* (non-Javadoc)
241 * @see java.lang.Object#hashCode()
242 */
243 @Override
244 public int hashCode() {
245 final int prime = 5807;
246 int result = super.hashCode();
247 result = prime * result + checksum;
248 result = prime * result + destinationPort;
249 result = prime * result + sourcePort;
250 return result;
251 }
252
253 /* (non-Javadoc)
254 * @see java.lang.Object#equals(java.lang.Object)
255 */
256 @Override
257 public boolean equals(Object obj) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700258 if (this == obj) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800259 return true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700260 }
261 if (!super.equals(obj)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800262 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700263 }
264 if (!(obj instanceof TCP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800265 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700266 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800267 TCP other = (TCP) obj;
268 // May want to compare fields based on the flags set
269 return (checksum == other.checksum) &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 (destinationPort == other.destinationPort) &&
271 (sourcePort == other.sourcePort) &&
272 (sequence == other.sequence) &&
273 (acknowledge == other.acknowledge) &&
274 (dataOffset == other.dataOffset) &&
275 (flags == other.flags) &&
276 (windowSize == other.windowSize) &&
277 (urgentPointer == other.urgentPointer) &&
Pavlin Radoslavov35ef8e82014-04-09 16:39:12 -0700278 (dataOffset == 5 || Arrays.equals(options, other.options));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800279 }
280
281 @Override
282 public IPacket deserialize(byte[] data, int offset, int length) {
283 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
284 this.sourcePort = bb.getShort();
285 this.destinationPort = bb.getShort();
286 this.sequence = bb.getInt();
287 this.acknowledge = bb.getInt();
288 this.flags = bb.getShort();
289 this.dataOffset = (byte) ((this.flags >> 12) & 0xf);
290 this.flags = (short) (this.flags & 0x1ff);
291 this.windowSize = bb.getShort();
292 this.checksum = bb.getShort();
293 this.urgentPointer = bb.getShort();
294 if (this.dataOffset > 5) {
295 int optLength = (dataOffset << 2) - 20;
Ray Milkey269ffb92014-04-03 14:43:30 -0700296 if (bb.limit() < bb.position() + optLength) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800297 optLength = bb.limit() - bb.position();
298 }
299 try {
300 this.options = new byte[optLength];
301 bb.get(this.options, 0, optLength);
302 } catch (IndexOutOfBoundsException e) {
303 this.options = null;
304 }
305 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700306
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800307 this.payload = new Data();
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800309 this.payload.setParent(this);
310 return this;
311 }
312}