blob: 66534ebe2c5520d1ddb9dddf030a0efe9b5c0482 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Charles M.C. Chan197a0122015-04-08 18:15:34 +08002 * Copyright 2014-2015 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;
22import java.util.HashMap;
23import java.util.Map;
24
Jonathan Hart2a655752015-04-07 16:46:33 -070025import static org.onlab.packet.PacketUtils.*;
26
alshabibc4901cd2014-09-05 16:50:40 -070027/**
28 *
alshabibc4901cd2014-09-05 16:50:40 -070029 */
30
31public class UDP extends BasePacket {
Jonathan Hart2a655752015-04-07 16:46:33 -070032 public static final Map<Short, Deserializer<? extends IPacket>> PORT_DESERIALIZER_MAP =
Ray Milkey241b96a2014-11-17 13:08:20 -080033 new HashMap<>();
alshabibc4901cd2014-09-05 16:50:40 -070034 public static final short DHCP_SERVER_PORT = (short) 67;
35 public static final short DHCP_CLIENT_PORT = (short) 68;
36
Jonathan Hart2a655752015-04-07 16:46:33 -070037 private static final short UDP_HEADER_LENGTH = 8;
38
alshabibc4901cd2014-09-05 16:50:40 -070039 static {
alshabibc4901cd2014-09-05 16:50:40 -070040 /*
41 * Disable DHCP until the deserialize code is hardened to deal with
42 * garbage input
43 */
Jonathan Hart2a655752015-04-07 16:46:33 -070044 UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_SERVER_PORT, DHCP.deserializer());
45 UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_CLIENT_PORT, DHCP.deserializer());
alshabibc4901cd2014-09-05 16:50:40 -070046
47 }
48
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070049 protected int sourcePort;
50 protected int destinationPort;
alshabibc4901cd2014-09-05 16:50:40 -070051 protected short length;
52 protected short checksum;
53
54 /**
55 * @return the sourcePort
56 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070057 public int getSourcePort() {
alshabibc4901cd2014-09-05 16:50:40 -070058 return this.sourcePort;
59 }
60
61 /**
62 * @param sourcePort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070063 * the sourcePort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080064 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070065 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070066 public UDP setSourcePort(final int sourcePort) {
alshabibc4901cd2014-09-05 16:50:40 -070067 this.sourcePort = sourcePort;
68 return this;
69 }
70
71 /**
72 * @return the destinationPort
73 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070074 public int getDestinationPort() {
alshabibc4901cd2014-09-05 16:50:40 -070075 return this.destinationPort;
76 }
77
78 /**
79 * @param destinationPort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070080 * the destinationPort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080081 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070082 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070083 public UDP setDestinationPort(final int destinationPort) {
alshabibc4901cd2014-09-05 16:50:40 -070084 this.destinationPort = destinationPort;
85 return this;
86 }
87
88 /**
89 * @return the length
90 */
91 public short getLength() {
92 return this.length;
93 }
94
95 /**
96 * @return the checksum
97 */
98 public short getChecksum() {
99 return this.checksum;
100 }
101
102 /**
103 * @param checksum
104 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800105 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700106 */
107 public UDP setChecksum(final short checksum) {
108 this.checksum = checksum;
109 return this;
110 }
111
112 @Override
113 public void resetChecksum() {
114 this.checksum = 0;
115 super.resetChecksum();
116 }
117
118 /**
119 * Serializes the packet. Will compute and set the following fields if they
120 * are set to specific values at the time serialize is called: -checksum : 0
121 * -length : 0
122 */
123 @Override
124 public byte[] serialize() {
125 byte[] payloadData = null;
126 if (this.payload != null) {
127 this.payload.setParent(this);
128 payloadData = this.payload.serialize();
129 }
130
131 this.length = (short) (8 + (payloadData == null ? 0
132 : payloadData.length));
133
134 final byte[] data = new byte[this.length];
135 final ByteBuffer bb = ByteBuffer.wrap(data);
136
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700137 bb.putShort((short) (this.sourcePort & 0xffff));
138 bb.putShort((short) (this.destinationPort & 0xffff));
alshabibc4901cd2014-09-05 16:50:40 -0700139 bb.putShort(this.length);
140 bb.putShort(this.checksum);
141 if (payloadData != null) {
142 bb.put(payloadData);
143 }
144
145 if (this.parent != null && this.parent instanceof IPv4) {
146 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
147 }
148
149 // compute checksum if needed
150 if (this.checksum == 0) {
151 bb.rewind();
152 int accumulation = 0;
153
154 // compute pseudo header mac
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800155 if (this.parent != null) {
156 if (this.parent instanceof IPv4) {
157 final IPv4 ipv4 = (IPv4) this.parent;
158 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
159 + (ipv4.getSourceAddress() & 0xffff);
160 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
161 + (ipv4.getDestinationAddress() & 0xffff);
162 accumulation += ipv4.getProtocol() & 0xff;
163 accumulation += length & 0xffff;
164 } else if (this.parent instanceof IPv6) {
165 final IPv6 ipv6 = (IPv6) this.parent;
166 final int bbLength =
167 Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
168 + 2 // nextHeader (with padding)
169 + 4; // length
170 final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
171 bbChecksum.put(ipv6.getSourceAddress());
172 bbChecksum.put(ipv6.getDestinationAddress());
173 bbChecksum.put((byte) 0); // padding
174 bbChecksum.put(ipv6.getNextHeader());
175 bbChecksum.putInt(length);
176 bbChecksum.rewind();
177 for (int i = 0; i < bbLength / 2; ++i) {
178 accumulation += 0xffff & bbChecksum.getShort();
179 }
180 }
alshabibc4901cd2014-09-05 16:50:40 -0700181 }
182
183 for (int i = 0; i < this.length / 2; ++i) {
184 accumulation += 0xffff & bb.getShort();
185 }
186 // pad to an even number of shorts
187 if (this.length % 2 > 0) {
188 accumulation += (bb.get() & 0xff) << 8;
189 }
190
191 accumulation = (accumulation >> 16 & 0xffff)
192 + (accumulation & 0xffff);
193 this.checksum = (short) (~accumulation & 0xffff);
194 bb.putShort(6, this.checksum);
195 }
196 return data;
197 }
198
Jonathan Hart2a655752015-04-07 16:46:33 -0700199 @Override
200 public IPacket deserialize(final byte[] data, final int offset,
201 final int length) {
202 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700203 this.sourcePort = (bb.getShort() & 0xffff);
204 this.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700205 this.length = bb.getShort();
206 this.checksum = bb.getShort();
207
208 Deserializer<? extends IPacket> deserializer;
209 if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.destinationPort)) {
210 deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.destinationPort);
211 } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.sourcePort)) {
212 deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.sourcePort);
213 } else {
214 deserializer = Data.deserializer();
215 }
216
217 try {
218 this.payload = deserializer.deserialize(data, bb.position(),
219 bb.limit() - bb.position());
220 this.payload.setParent(this);
221 } catch (DeserializationException e) {
222 return this;
223 }
224 return this;
225 }
226
alshabibc4901cd2014-09-05 16:50:40 -0700227 /*
228 * (non-Javadoc)
229 *
230 * @see java.lang.Object#hashCode()
231 */
232 @Override
233 public int hashCode() {
234 final int prime = 5807;
235 int result = super.hashCode();
236 result = prime * result + this.checksum;
237 result = prime * result + this.destinationPort;
238 result = prime * result + this.length;
239 result = prime * result + this.sourcePort;
240 return result;
241 }
242
243 /*
244 * (non-Javadoc)
245 *
246 * @see java.lang.Object#equals(java.lang.Object)
247 */
248 @Override
249 public boolean equals(final Object obj) {
250 if (this == obj) {
251 return true;
252 }
253 if (!super.equals(obj)) {
254 return false;
255 }
256 if (!(obj instanceof UDP)) {
257 return false;
258 }
259 final UDP other = (UDP) obj;
260 if (this.checksum != other.checksum) {
261 return false;
262 }
263 if (this.destinationPort != other.destinationPort) {
264 return false;
265 }
266 if (this.length != other.length) {
267 return false;
268 }
269 if (this.sourcePort != other.sourcePort) {
270 return false;
271 }
272 return true;
273 }
274
Jonathan Hart2a655752015-04-07 16:46:33 -0700275 /**
276 * Deserializer function for UDP packets.
277 *
278 * @return deserializer function
279 */
280 public static Deserializer<UDP> deserializer() {
281 return (data, offset, length) -> {
282 checkInput(data, offset, length, UDP_HEADER_LENGTH);
alshabibc4901cd2014-09-05 16:50:40 -0700283
Jonathan Hart2a655752015-04-07 16:46:33 -0700284 UDP udp = new UDP();
285
286 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700287 udp.sourcePort = (bb.getShort() & 0xffff);
288 udp.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700289 udp.length = bb.getShort();
290 udp.checksum = bb.getShort();
291
292 Deserializer<? extends IPacket> deserializer;
293 if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.destinationPort)) {
294 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.destinationPort);
295 } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.sourcePort)) {
296 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.sourcePort);
297 } else {
298 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700299 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700300
301 udp.payload = deserializer.deserialize(data, bb.position(),
302 bb.limit() - bb.position());
303 udp.payload.setParent(udp);
304 return udp;
305 };
alshabibc4901cd2014-09-05 16:50:40 -0700306 }
307}