blob: 889e4c6a88292d3e2ea704aa3b49e38e93054fdd [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2* 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**/
17
18package net.floodlightcontroller.packet;
19
20import java.nio.ByteBuffer;
21
22/**
23 *
24 * @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 }
74
75 public int getSequence() {
76 return this.sequence;
77 }
78 public TCP setSequence(int seq) {
79 this.sequence = seq;
80 return this;
81 }
82 public int getAcknowledge() {
83 return this.acknowledge;
84 }
85 public TCP setAcknowledge(int ack) {
86 this.acknowledge = ack;
87 return this;
88 }
89 public byte getDataOffset() {
90 return this.dataOffset;
91 }
92 public TCP setDataOffset(byte offset) {
93 this.dataOffset = offset;
94 return this;
95 }
96 public short getFlags() {
97 return this.flags;
98 }
99 public TCP setFlags(short flags) {
100 this.flags = flags;
101 return this;
102 }
103 public short getWindowSize() {
104 return this.windowSize;
105 }
106 public TCP setWindowSize(short windowSize) {
107 this.windowSize = windowSize;
108 return this;
109 }
110 public short getTcpChecksum() {
111 return this.checksum;
112 }
113 public TCP setTcpChecksum(short checksum) {
114 this.checksum = checksum;
115 return this;
116 }
117
118 @Override
119 public void resetChecksum() {
120 this.checksum = 0;
121 super.resetChecksum();
122 }
123
124 public short getUrgentPointer(short urgentPointer) {
125 return this.urgentPointer;
126 }
127 public TCP setUrgentPointer(short urgentPointer) {
128 this.urgentPointer= urgentPointer;
129 return this;
130 }
131 public byte[] getOptions() {
132 return this.options;
133 }
134 public TCP setOptions(byte[] options) {
135 this.options = options;
136 this.dataOffset = (byte) ((20 + options.length + 3) >> 2);
137 return this;
138 }
139 /**
140 * @param checksum the checksum to set
141 */
142 public TCP setChecksum(short checksum) {
143 this.checksum = checksum;
144 return this;
145 }
146
147 /**
148 * Serializes the packet. Will compute and set the following fields if they
149 * are set to specific values at the time serialize is called:
150 * -checksum : 0
151 * -length : 0
152 */
153 public byte[] serialize() {
154 int length;
155 if (dataOffset == 0)
156 dataOffset = 5; // default header length
157 length = dataOffset << 2;
158 byte[] payloadData = null;
159 if (payload != null) {
160 payload.setParent(this);
161 payloadData = payload.serialize();
162 length += payloadData.length;
163 }
164
165 byte[] data = new byte[length];
166 ByteBuffer bb = ByteBuffer.wrap(data);
167
168 bb.putShort(this.sourcePort);
169 bb.putShort(this.destinationPort);
170 bb.putInt(this.sequence);
171 bb.putInt(this.acknowledge);
172 bb.putShort((short) (this.flags | (dataOffset << 12)));
173 bb.putShort(this.windowSize);
174 bb.putShort(this.checksum);
175 bb.putShort(this.urgentPointer);
176 if (dataOffset > 5) {
177 int padding;
178 bb.put(options);
179 padding = (dataOffset << 2) - 20 - options.length;
180 for (int i = 0; i < padding; i++)
181 bb.put((byte) 0);
182 }
183 if (payloadData != null)
184 bb.put(payloadData);
185
186 if (this.parent != null && this.parent instanceof IPv4)
187 ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_TCP);
188
189 // compute checksum if needed
190 if (this.checksum == 0) {
191 bb.rewind();
192 int accumulation = 0;
193
194 // compute pseudo header mac
195 if (this.parent != null && this.parent instanceof IPv4) {
196 IPv4 ipv4 = (IPv4) this.parent;
197 accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
198 + (ipv4.getSourceAddress() & 0xffff);
199 accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
200 + (ipv4.getDestinationAddress() & 0xffff);
201 accumulation += ipv4.getProtocol() & 0xff;
202 accumulation += length & 0xffff;
203 }
204
205 for (int i = 0; i < length / 2; ++i) {
206 accumulation += 0xffff & bb.getShort();
207 }
208 // pad to an even number of shorts
209 if (length % 2 > 0) {
210 accumulation += (bb.get() & 0xff) << 8;
211 }
212
213 accumulation = ((accumulation >> 16) & 0xffff)
214 + (accumulation & 0xffff);
215 this.checksum = (short) (~accumulation & 0xffff);
216 bb.putShort(16, this.checksum);
217 }
218 return data;
219 }
220
221 /* (non-Javadoc)
222 * @see java.lang.Object#hashCode()
223 */
224 @Override
225 public int hashCode() {
226 final int prime = 5807;
227 int result = super.hashCode();
228 result = prime * result + checksum;
229 result = prime * result + destinationPort;
230 result = prime * result + sourcePort;
231 return result;
232 }
233
234 /* (non-Javadoc)
235 * @see java.lang.Object#equals(java.lang.Object)
236 */
237 @Override
238 public boolean equals(Object obj) {
239 if (this == obj)
240 return true;
241 if (!super.equals(obj))
242 return false;
243 if (!(obj instanceof TCP))
244 return false;
245 TCP other = (TCP) obj;
246 // May want to compare fields based on the flags set
247 return (checksum == other.checksum) &&
248 (destinationPort == other.destinationPort) &&
249 (sourcePort == other.sourcePort) &&
250 (sequence == other.sequence) &&
251 (acknowledge == other.acknowledge) &&
252 (dataOffset == other.dataOffset) &&
253 (flags == other.flags) &&
254 (windowSize == other.windowSize) &&
255 (urgentPointer == other.urgentPointer) &&
256 (dataOffset == 5 || options.equals(other.options));
257 }
258
259 @Override
260 public IPacket deserialize(byte[] data, int offset, int length) {
261 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
262 this.sourcePort = bb.getShort();
263 this.destinationPort = bb.getShort();
264 this.sequence = bb.getInt();
265 this.acknowledge = bb.getInt();
266 this.flags = bb.getShort();
267 this.dataOffset = (byte) ((this.flags >> 12) & 0xf);
268 this.flags = (short) (this.flags & 0x1ff);
269 this.windowSize = bb.getShort();
270 this.checksum = bb.getShort();
271 this.urgentPointer = bb.getShort();
272 if (this.dataOffset > 5) {
273 int optLength = (dataOffset << 2) - 20;
274 if (bb.limit() < bb.position()+optLength) {
275 optLength = bb.limit() - bb.position();
276 }
277 try {
278 this.options = new byte[optLength];
279 bb.get(this.options, 0, optLength);
280 } catch (IndexOutOfBoundsException e) {
281 this.options = null;
282 }
283 }
284
285 this.payload = new Data();
286 this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
287 this.payload.setParent(this);
288 return this;
289 }
290}