blob: 0d7ff37511d9e5d73e0e68abe3dacbdbb0d6be64 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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
alshabibc4901cd2014-09-05 16:50:40 -070017package org.onlab.packet;
18
19import java.nio.ByteBuffer;
alshabibc4901cd2014-09-05 16:50:40 -070020import java.util.Map;
21
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070022import com.google.common.collect.ImmutableMap;
23
Jian Li5fc14292015-12-04 11:30:46 -080024import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070025import static org.onlab.packet.PacketUtils.*;
26
alshabibc4901cd2014-09-05 16:50:40 -070027/**
Thomas Vachuskae4ed1a22015-08-26 15:19:05 -070028 * Representation of a UDP packet.
alshabibc4901cd2014-09-05 16:50:40 -070029 */
alshabibc4901cd2014-09-05 16:50:40 -070030public class UDP extends BasePacket {
Thomas Vachuskae4ed1a22015-08-26 15:19:05 -070031 public static final Map<Integer, Deserializer<? extends IPacket>> PORT_DESERIALIZER_MAP =
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070032 ImmutableMap.<Integer, Deserializer<? extends IPacket>>builder()
Yi Tseng60bf35a2017-06-02 17:05:48 -070033 .put(UDP.DHCP_SERVER_PORT, DHCP.deserializer())
34 .put(UDP.DHCP_CLIENT_PORT, DHCP.deserializer())
35 .put(UDP.DHCP_V6_SERVER_PORT, DHCP6.deserializer())
36 .put(UDP.DHCP_V6_CLIENT_PORT, DHCP6.deserializer())
jaegonkim1179d832017-06-13 19:30:55 +090037 .put(UDP.VXLAN_UDP_PORT, VXLAN.deserializer())
Yi Tseng60bf35a2017-06-02 17:05:48 -070038 .build();
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070039
Thomas Vachuskae4ed1a22015-08-26 15:19:05 -070040 public static final int DHCP_SERVER_PORT = 67;
41 public static final int DHCP_CLIENT_PORT = 68;
Yi Tseng60bf35a2017-06-02 17:05:48 -070042 public static final int DHCP_V6_SERVER_PORT = 547;
43 public static final int DHCP_V6_CLIENT_PORT = 546;
jaegonkim1179d832017-06-13 19:30:55 +090044 public static final int VXLAN_UDP_PORT = 4789;
alshabibc4901cd2014-09-05 16:50:40 -070045
Jonathan Hart2a655752015-04-07 16:46:33 -070046 private static final short UDP_HEADER_LENGTH = 8;
47
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070048 protected int sourcePort;
49 protected int destinationPort;
alshabibc4901cd2014-09-05 16:50:40 -070050 protected short length;
51 protected short checksum;
52
53 /**
54 * @return the sourcePort
55 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070056 public int getSourcePort() {
alshabibc4901cd2014-09-05 16:50:40 -070057 return this.sourcePort;
58 }
59
60 /**
61 * @param sourcePort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070062 * the sourcePort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080063 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070064 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070065 public UDP setSourcePort(final int sourcePort) {
alshabibc4901cd2014-09-05 16:50:40 -070066 this.sourcePort = sourcePort;
67 return this;
68 }
69
70 /**
71 * @return the destinationPort
72 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070073 public int getDestinationPort() {
alshabibc4901cd2014-09-05 16:50:40 -070074 return this.destinationPort;
75 }
76
77 /**
78 * @param destinationPort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070079 * the destinationPort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080080 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070081 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070082 public UDP setDestinationPort(final int destinationPort) {
alshabibc4901cd2014-09-05 16:50:40 -070083 this.destinationPort = destinationPort;
84 return this;
85 }
86
87 /**
88 * @return the length
89 */
90 public short getLength() {
91 return this.length;
92 }
93
94 /**
95 * @return the checksum
96 */
97 public short getChecksum() {
98 return this.checksum;
99 }
100
101 /**
102 * @param checksum
103 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800104 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700105 */
106 public UDP setChecksum(final short checksum) {
107 this.checksum = checksum;
108 return this;
109 }
110
111 @Override
112 public void resetChecksum() {
113 this.checksum = 0;
114 super.resetChecksum();
115 }
116
117 /**
118 * Serializes the packet. Will compute and set the following fields if they
119 * are set to specific values at the time serialize is called: -checksum : 0
120 * -length : 0
121 */
122 @Override
123 public byte[] serialize() {
124 byte[] payloadData = null;
125 if (this.payload != null) {
126 this.payload.setParent(this);
127 payloadData = this.payload.serialize();
128 }
129
130 this.length = (short) (8 + (payloadData == null ? 0
131 : payloadData.length));
132
133 final byte[] data = new byte[this.length];
134 final ByteBuffer bb = ByteBuffer.wrap(data);
135
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700136 bb.putShort((short) (this.sourcePort & 0xffff));
137 bb.putShort((short) (this.destinationPort & 0xffff));
alshabibc4901cd2014-09-05 16:50:40 -0700138 bb.putShort(this.length);
139 bb.putShort(this.checksum);
140 if (payloadData != null) {
141 bb.put(payloadData);
142 }
143
144 if (this.parent != null && this.parent instanceof IPv4) {
145 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
146 }
147
148 // compute checksum if needed
149 if (this.checksum == 0) {
150 bb.rewind();
151 int accumulation = 0;
152
153 // compute pseudo header mac
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800154 if (this.parent != null) {
155 if (this.parent instanceof IPv4) {
156 final IPv4 ipv4 = (IPv4) this.parent;
157 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
158 + (ipv4.getSourceAddress() & 0xffff);
159 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
160 + (ipv4.getDestinationAddress() & 0xffff);
161 accumulation += ipv4.getProtocol() & 0xff;
162 accumulation += length & 0xffff;
163 } else if (this.parent instanceof IPv6) {
164 final IPv6 ipv6 = (IPv6) this.parent;
165 final int bbLength =
166 Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
167 + 2 // nextHeader (with padding)
168 + 4; // length
169 final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
170 bbChecksum.put(ipv6.getSourceAddress());
171 bbChecksum.put(ipv6.getDestinationAddress());
172 bbChecksum.put((byte) 0); // padding
173 bbChecksum.put(ipv6.getNextHeader());
174 bbChecksum.putInt(length);
175 bbChecksum.rewind();
176 for (int i = 0; i < bbLength / 2; ++i) {
177 accumulation += 0xffff & bbChecksum.getShort();
178 }
179 }
alshabibc4901cd2014-09-05 16:50:40 -0700180 }
181
182 for (int i = 0; i < this.length / 2; ++i) {
183 accumulation += 0xffff & bb.getShort();
184 }
185 // pad to an even number of shorts
186 if (this.length % 2 > 0) {
187 accumulation += (bb.get() & 0xff) << 8;
188 }
189
190 accumulation = (accumulation >> 16 & 0xffff)
191 + (accumulation & 0xffff);
192 this.checksum = (short) (~accumulation & 0xffff);
193 bb.putShort(6, this.checksum);
194 }
195 return data;
196 }
197
Jonathan Hart2a655752015-04-07 16:46:33 -0700198 @Override
199 public IPacket deserialize(final byte[] data, final int offset,
200 final int length) {
201 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700202 this.sourcePort = (bb.getShort() & 0xffff);
203 this.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700204 this.length = bb.getShort();
205 this.checksum = bb.getShort();
206
207 Deserializer<? extends IPacket> deserializer;
208 if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.destinationPort)) {
209 deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.destinationPort);
210 } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.sourcePort)) {
211 deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.sourcePort);
212 } else {
213 deserializer = Data.deserializer();
214 }
215
216 try {
217 this.payload = deserializer.deserialize(data, bb.position(),
218 bb.limit() - bb.position());
219 this.payload.setParent(this);
220 } catch (DeserializationException e) {
221 return this;
222 }
223 return this;
224 }
225
alshabibc4901cd2014-09-05 16:50:40 -0700226 /*
227 * (non-Javadoc)
228 *
229 * @see java.lang.Object#hashCode()
230 */
231 @Override
232 public int hashCode() {
233 final int prime = 5807;
234 int result = super.hashCode();
235 result = prime * result + this.checksum;
236 result = prime * result + this.destinationPort;
237 result = prime * result + this.length;
238 result = prime * result + this.sourcePort;
239 return result;
240 }
241
242 /*
243 * (non-Javadoc)
244 *
245 * @see java.lang.Object#equals(java.lang.Object)
246 */
247 @Override
248 public boolean equals(final Object obj) {
249 if (this == obj) {
250 return true;
251 }
252 if (!super.equals(obj)) {
253 return false;
254 }
255 if (!(obj instanceof UDP)) {
256 return false;
257 }
258 final UDP other = (UDP) obj;
259 if (this.checksum != other.checksum) {
260 return false;
261 }
262 if (this.destinationPort != other.destinationPort) {
263 return false;
264 }
265 if (this.length != other.length) {
266 return false;
267 }
268 if (this.sourcePort != other.sourcePort) {
269 return false;
270 }
271 return true;
272 }
273
Jonathan Hart2a655752015-04-07 16:46:33 -0700274 /**
275 * Deserializer function for UDP packets.
276 *
277 * @return deserializer function
278 */
279 public static Deserializer<UDP> deserializer() {
280 return (data, offset, length) -> {
281 checkInput(data, offset, length, UDP_HEADER_LENGTH);
alshabibc4901cd2014-09-05 16:50:40 -0700282
Jonathan Hart2a655752015-04-07 16:46:33 -0700283 UDP udp = new UDP();
284
285 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700286 udp.sourcePort = (bb.getShort() & 0xffff);
287 udp.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700288 udp.length = bb.getShort();
289 udp.checksum = bb.getShort();
290
291 Deserializer<? extends IPacket> deserializer;
292 if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.destinationPort)) {
293 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.destinationPort);
294 } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.sourcePort)) {
295 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.sourcePort);
296 } else {
297 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700298 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700299
300 udp.payload = deserializer.deserialize(data, bb.position(),
301 bb.limit() - bb.position());
302 udp.payload.setParent(udp);
303 return udp;
304 };
alshabibc4901cd2014-09-05 16:50:40 -0700305 }
Jian Li5fc14292015-12-04 11:30:46 -0800306
307 @Override
308 public String toString() {
309 return toStringHelper(getClass())
310 .add("sourcePort", Integer.toString(sourcePort))
311 .add("destinationPort", Integer.toString(destinationPort))
312 .add("length", Short.toString(length))
313 .add("checksum", Short.toString(checksum))
314 .toString();
315 }
alshabibc4901cd2014-09-05 16:50:40 -0700316}