blob: 09584e3aa9ab0a0ce41b2df0bdc1ac0854badf1b [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
Yuta HIGUCHI498e1532014-08-20 21:30:28 -070023import org.apache.commons.lang3.ArrayUtils;
Pavlin Radoslavov1d595c02014-04-16 14:11:54 -070024
Yuta HIGUCHIaa132f52014-06-26 10:18:39 -070025// CHECKSTYLE IGNORE WriteTag FOR NEXT 2 LINES
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080026/**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080027 * @author shudong.zhou@bigswitch.com
28 */
29public class TCP extends BasePacket {
30 protected short sourcePort;
31 protected short destinationPort;
32 protected int sequence;
33 protected int acknowledge;
34 protected byte dataOffset;
35 protected short flags;
36 protected short windowSize;
37 protected short checksum;
38 protected short urgentPointer;
39 protected byte[] options;
40
41 /**
42 * @return the sourcePort
43 */
44 public short getSourcePort() {
45 return sourcePort;
46 }
47
48 /**
49 * @param sourcePort the sourcePort to set
50 */
51 public TCP setSourcePort(short sourcePort) {
52 this.sourcePort = sourcePort;
53 return this;
54 }
55
56 /**
57 * @return the destinationPort
58 */
59 public short getDestinationPort() {
60 return destinationPort;
61 }
62
63 /**
64 * @param destinationPort the destinationPort to set
65 */
66 public TCP setDestinationPort(short destinationPort) {
67 this.destinationPort = destinationPort;
68 return this;
69 }
70
71 /**
72 * @return the checksum
73 */
74 public short getChecksum() {
75 return checksum;
76 }
Ray Milkey269ffb92014-04-03 14:43:30 -070077
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080078 public int getSequence() {
79 return this.sequence;
80 }
Ray Milkey269ffb92014-04-03 14:43:30 -070081
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080082 public TCP setSequence(int seq) {
83 this.sequence = seq;
84 return this;
85 }
Ray Milkey269ffb92014-04-03 14:43:30 -070086
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080087 public int getAcknowledge() {
88 return this.acknowledge;
89 }
Ray Milkey269ffb92014-04-03 14:43:30 -070090
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080091 public TCP setAcknowledge(int ack) {
92 this.acknowledge = ack;
93 return this;
94 }
Ray Milkey269ffb92014-04-03 14:43:30 -070095
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080096 public byte getDataOffset() {
97 return this.dataOffset;
98 }
Ray Milkey269ffb92014-04-03 14:43:30 -070099
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800100 public TCP setDataOffset(byte offset) {
101 this.dataOffset = offset;
102 return this;
103 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700104
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800105 public short getFlags() {
106 return this.flags;
107 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700108
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800109 public TCP setFlags(short flags) {
110 this.flags = flags;
111 return this;
112 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700113
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800114 public short getWindowSize() {
115 return this.windowSize;
116 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700117
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800118 public TCP setWindowSize(short windowSize) {
119 this.windowSize = windowSize;
120 return this;
121 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700122
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800123 public short getTcpChecksum() {
124 return this.checksum;
125 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700126
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800127 public TCP setTcpChecksum(short checksum) {
128 this.checksum = checksum;
129 return this;
130 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700131
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800132 @Override
133 public void resetChecksum() {
134 this.checksum = 0;
135 super.resetChecksum();
136 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700137
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800138 public short getUrgentPointer(short urgentPointer) {
139 return this.urgentPointer;
140 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700141
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800142 public TCP setUrgentPointer(short urgentPointer) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700143 this.urgentPointer = urgentPointer;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800144 return this;
145 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700146
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800147 public byte[] getOptions() {
Pavlin Radoslavov1d595c02014-04-16 14:11:54 -0700148 return ArrayUtils.clone(this.options);
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 Radoslavov1d595c02014-04-16 14:11:54 -0700152 this.options = ArrayUtils.clone(options);
153 if (this.options == null) {
Pavlin Radoslavov0a9d5c32014-04-15 17:45:23 -0700154 this.dataOffset = 0;
155 } else {
Pavlin Radoslavov1d595c02014-04-16 14:11:54 -0700156 this.dataOffset = (byte) ((20 + this.options.length + 3) >> 2);
Pavlin Radoslavov0a9d5c32014-04-15 17:45:23 -0700157 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800158 return this;
159 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700160
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800161 /**
162 * @param checksum the checksum to set
163 */
164 public TCP setChecksum(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:
Ray Milkey269ffb92014-04-03 14:43:30 -0700172 * -checksum : 0
173 * -length : 0
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800174 */
Yuta HIGUCHIaa132f52014-06-26 10:18:39 -0700175 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800176 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}