blob: def194c0330ee25a9c07bcd479f91a2f16bff311 [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() {
Pavlin Radoslavov0a9d5c32014-04-15 17:45:23 -0700145 if (this.options == null) {
146 return null;
147 }
148 return this.options.clone();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800149 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700150
Pavlin Radoslavovc9bacee2014-04-11 19:02:17 -0700151 public TCP setOptions(final byte[] options) {
Pavlin Radoslavov0a9d5c32014-04-15 17:45:23 -0700152 if (options == null) {
153 this.options = null;
154 this.dataOffset = 0;
155 } else {
156 this.options = options.clone();
157 this.dataOffset = (byte) ((20 + options.length + 3) >> 2);
158 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800159 return this;
160 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700161
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800162 /**
163 * @param checksum the checksum to set
164 */
165 public TCP setChecksum(short checksum) {
166 this.checksum = checksum;
167 return this;
168 }
169
170 /**
171 * Serializes the packet. Will compute and set the following fields if they
172 * are set to specific values at the time serialize is called:
Ray Milkey269ffb92014-04-03 14:43:30 -0700173 * -checksum : 0
174 * -length : 0
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800175 */
176 public byte[] serialize() {
177 int length;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700178 if (dataOffset == 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800179 dataOffset = 5; // default header length
Ray Milkeyb29e6262014-04-09 16:02:14 -0700180 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800181 length = dataOffset << 2;
182 byte[] payloadData = null;
183 if (payload != null) {
184 payload.setParent(this);
185 payloadData = payload.serialize();
186 length += payloadData.length;
187 }
188
189 byte[] data = new byte[length];
190 ByteBuffer bb = ByteBuffer.wrap(data);
191
192 bb.putShort(this.sourcePort);
193 bb.putShort(this.destinationPort);
194 bb.putInt(this.sequence);
195 bb.putInt(this.acknowledge);
196 bb.putShort((short) (this.flags | (dataOffset << 12)));
197 bb.putShort(this.windowSize);
198 bb.putShort(this.checksum);
199 bb.putShort(this.urgentPointer);
200 if (dataOffset > 5) {
201 int padding;
202 bb.put(options);
203 padding = (dataOffset << 2) - 20 - options.length;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700204 for (int i = 0; i < padding; i++) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800205 bb.put((byte) 0);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700206 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800207 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700208 if (payloadData != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800209 bb.put(payloadData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700210 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800211
Ray Milkeyb29e6262014-04-09 16:02:14 -0700212 if (this.parent != null && this.parent instanceof IPv4) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_TCP);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700214 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800215
216 // compute checksum if needed
217 if (this.checksum == 0) {
218 bb.rewind();
219 int accumulation = 0;
220
221 // compute pseudo header mac
222 if (this.parent != null && this.parent instanceof IPv4) {
223 IPv4 ipv4 = (IPv4) this.parent;
224 accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
225 + (ipv4.getSourceAddress() & 0xffff);
226 accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
227 + (ipv4.getDestinationAddress() & 0xffff);
228 accumulation += ipv4.getProtocol() & 0xff;
229 accumulation += length & 0xffff;
230 }
231
232 for (int i = 0; i < length / 2; ++i) {
233 accumulation += 0xffff & bb.getShort();
234 }
235 // pad to an even number of shorts
236 if (length % 2 > 0) {
237 accumulation += (bb.get() & 0xff) << 8;
238 }
239
240 accumulation = ((accumulation >> 16) & 0xffff)
241 + (accumulation & 0xffff);
242 this.checksum = (short) (~accumulation & 0xffff);
243 bb.putShort(16, this.checksum);
244 }
245 return data;
246 }
247
248 /* (non-Javadoc)
249 * @see java.lang.Object#hashCode()
250 */
251 @Override
252 public int hashCode() {
253 final int prime = 5807;
254 int result = super.hashCode();
255 result = prime * result + checksum;
256 result = prime * result + destinationPort;
257 result = prime * result + sourcePort;
258 return result;
259 }
260
261 /* (non-Javadoc)
262 * @see java.lang.Object#equals(java.lang.Object)
263 */
264 @Override
265 public boolean equals(Object obj) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700266 if (this == obj) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800267 return true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700268 }
269 if (!super.equals(obj)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800270 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700271 }
272 if (!(obj instanceof TCP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800273 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700274 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800275 TCP other = (TCP) obj;
276 // May want to compare fields based on the flags set
277 return (checksum == other.checksum) &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 (destinationPort == other.destinationPort) &&
279 (sourcePort == other.sourcePort) &&
280 (sequence == other.sequence) &&
281 (acknowledge == other.acknowledge) &&
282 (dataOffset == other.dataOffset) &&
283 (flags == other.flags) &&
284 (windowSize == other.windowSize) &&
285 (urgentPointer == other.urgentPointer) &&
Pavlin Radoslavov35ef8e82014-04-09 16:39:12 -0700286 (dataOffset == 5 || Arrays.equals(options, other.options));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800287 }
288
289 @Override
290 public IPacket deserialize(byte[] data, int offset, int length) {
291 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
292 this.sourcePort = bb.getShort();
293 this.destinationPort = bb.getShort();
294 this.sequence = bb.getInt();
295 this.acknowledge = bb.getInt();
296 this.flags = bb.getShort();
297 this.dataOffset = (byte) ((this.flags >> 12) & 0xf);
298 this.flags = (short) (this.flags & 0x1ff);
299 this.windowSize = bb.getShort();
300 this.checksum = bb.getShort();
301 this.urgentPointer = bb.getShort();
302 if (this.dataOffset > 5) {
303 int optLength = (dataOffset << 2) - 20;
Ray Milkey269ffb92014-04-03 14:43:30 -0700304 if (bb.limit() < bb.position() + optLength) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800305 optLength = bb.limit() - bb.position();
306 }
307 try {
308 this.options = new byte[optLength];
309 bb.get(this.options, 0, optLength);
310 } catch (IndexOutOfBoundsException e) {
311 this.options = null;
312 }
313 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700314
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800315 this.payload = new Data();
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800317 this.payload.setParent(this);
318 return this;
319 }
320}