blob: 6849654ffabccfd9de903582c9f6be95a3186f1b [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())
37 .build();
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070038
Thomas Vachuskae4ed1a22015-08-26 15:19:05 -070039 public static final int DHCP_SERVER_PORT = 67;
40 public static final int DHCP_CLIENT_PORT = 68;
Yi Tseng60bf35a2017-06-02 17:05:48 -070041 public static final int DHCP_V6_SERVER_PORT = 547;
42 public static final int DHCP_V6_CLIENT_PORT = 546;
alshabibc4901cd2014-09-05 16:50:40 -070043
Jonathan Hart2a655752015-04-07 16:46:33 -070044 private static final short UDP_HEADER_LENGTH = 8;
45
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070046 protected int sourcePort;
47 protected int destinationPort;
alshabibc4901cd2014-09-05 16:50:40 -070048 protected short length;
49 protected short checksum;
50
51 /**
52 * @return the sourcePort
53 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070054 public int getSourcePort() {
alshabibc4901cd2014-09-05 16:50:40 -070055 return this.sourcePort;
56 }
57
58 /**
59 * @param sourcePort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070060 * the sourcePort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080061 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070062 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070063 public UDP setSourcePort(final int sourcePort) {
alshabibc4901cd2014-09-05 16:50:40 -070064 this.sourcePort = sourcePort;
65 return this;
66 }
67
68 /**
69 * @return the destinationPort
70 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070071 public int getDestinationPort() {
alshabibc4901cd2014-09-05 16:50:40 -070072 return this.destinationPort;
73 }
74
75 /**
76 * @param destinationPort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070077 * the destinationPort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080078 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070079 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070080 public UDP setDestinationPort(final int destinationPort) {
alshabibc4901cd2014-09-05 16:50:40 -070081 this.destinationPort = destinationPort;
82 return this;
83 }
84
85 /**
86 * @return the length
87 */
88 public short getLength() {
89 return this.length;
90 }
91
92 /**
93 * @return the checksum
94 */
95 public short getChecksum() {
96 return this.checksum;
97 }
98
99 /**
100 * @param checksum
101 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800102 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700103 */
104 public UDP setChecksum(final short checksum) {
105 this.checksum = checksum;
106 return this;
107 }
108
109 @Override
110 public void resetChecksum() {
111 this.checksum = 0;
112 super.resetChecksum();
113 }
114
115 /**
116 * Serializes the packet. Will compute and set the following fields if they
117 * are set to specific values at the time serialize is called: -checksum : 0
118 * -length : 0
119 */
120 @Override
121 public byte[] serialize() {
122 byte[] payloadData = null;
123 if (this.payload != null) {
124 this.payload.setParent(this);
125 payloadData = this.payload.serialize();
126 }
127
128 this.length = (short) (8 + (payloadData == null ? 0
129 : payloadData.length));
130
131 final byte[] data = new byte[this.length];
132 final ByteBuffer bb = ByteBuffer.wrap(data);
133
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700134 bb.putShort((short) (this.sourcePort & 0xffff));
135 bb.putShort((short) (this.destinationPort & 0xffff));
alshabibc4901cd2014-09-05 16:50:40 -0700136 bb.putShort(this.length);
137 bb.putShort(this.checksum);
138 if (payloadData != null) {
139 bb.put(payloadData);
140 }
141
142 if (this.parent != null && this.parent instanceof IPv4) {
143 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
144 }
145
146 // compute checksum if needed
147 if (this.checksum == 0) {
148 bb.rewind();
149 int accumulation = 0;
150
151 // compute pseudo header mac
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800152 if (this.parent != null) {
153 if (this.parent instanceof IPv4) {
154 final IPv4 ipv4 = (IPv4) this.parent;
155 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
156 + (ipv4.getSourceAddress() & 0xffff);
157 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
158 + (ipv4.getDestinationAddress() & 0xffff);
159 accumulation += ipv4.getProtocol() & 0xff;
160 accumulation += length & 0xffff;
161 } else if (this.parent instanceof IPv6) {
162 final IPv6 ipv6 = (IPv6) this.parent;
163 final int bbLength =
164 Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
165 + 2 // nextHeader (with padding)
166 + 4; // length
167 final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
168 bbChecksum.put(ipv6.getSourceAddress());
169 bbChecksum.put(ipv6.getDestinationAddress());
170 bbChecksum.put((byte) 0); // padding
171 bbChecksum.put(ipv6.getNextHeader());
172 bbChecksum.putInt(length);
173 bbChecksum.rewind();
174 for (int i = 0; i < bbLength / 2; ++i) {
175 accumulation += 0xffff & bbChecksum.getShort();
176 }
177 }
alshabibc4901cd2014-09-05 16:50:40 -0700178 }
179
180 for (int i = 0; i < this.length / 2; ++i) {
181 accumulation += 0xffff & bb.getShort();
182 }
183 // pad to an even number of shorts
184 if (this.length % 2 > 0) {
185 accumulation += (bb.get() & 0xff) << 8;
186 }
187
188 accumulation = (accumulation >> 16 & 0xffff)
189 + (accumulation & 0xffff);
190 this.checksum = (short) (~accumulation & 0xffff);
191 bb.putShort(6, this.checksum);
192 }
193 return data;
194 }
195
Jonathan Hart2a655752015-04-07 16:46:33 -0700196 @Override
197 public IPacket deserialize(final byte[] data, final int offset,
198 final int length) {
199 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700200 this.sourcePort = (bb.getShort() & 0xffff);
201 this.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700202 this.length = bb.getShort();
203 this.checksum = bb.getShort();
204
205 Deserializer<? extends IPacket> deserializer;
206 if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.destinationPort)) {
207 deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.destinationPort);
208 } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.sourcePort)) {
209 deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.sourcePort);
210 } else {
211 deserializer = Data.deserializer();
212 }
213
214 try {
215 this.payload = deserializer.deserialize(data, bb.position(),
216 bb.limit() - bb.position());
217 this.payload.setParent(this);
218 } catch (DeserializationException e) {
219 return this;
220 }
221 return this;
222 }
223
alshabibc4901cd2014-09-05 16:50:40 -0700224 /*
225 * (non-Javadoc)
226 *
227 * @see java.lang.Object#hashCode()
228 */
229 @Override
230 public int hashCode() {
231 final int prime = 5807;
232 int result = super.hashCode();
233 result = prime * result + this.checksum;
234 result = prime * result + this.destinationPort;
235 result = prime * result + this.length;
236 result = prime * result + this.sourcePort;
237 return result;
238 }
239
240 /*
241 * (non-Javadoc)
242 *
243 * @see java.lang.Object#equals(java.lang.Object)
244 */
245 @Override
246 public boolean equals(final Object obj) {
247 if (this == obj) {
248 return true;
249 }
250 if (!super.equals(obj)) {
251 return false;
252 }
253 if (!(obj instanceof UDP)) {
254 return false;
255 }
256 final UDP other = (UDP) obj;
257 if (this.checksum != other.checksum) {
258 return false;
259 }
260 if (this.destinationPort != other.destinationPort) {
261 return false;
262 }
263 if (this.length != other.length) {
264 return false;
265 }
266 if (this.sourcePort != other.sourcePort) {
267 return false;
268 }
269 return true;
270 }
271
Jonathan Hart2a655752015-04-07 16:46:33 -0700272 /**
273 * Deserializer function for UDP packets.
274 *
275 * @return deserializer function
276 */
277 public static Deserializer<UDP> deserializer() {
278 return (data, offset, length) -> {
279 checkInput(data, offset, length, UDP_HEADER_LENGTH);
alshabibc4901cd2014-09-05 16:50:40 -0700280
Jonathan Hart2a655752015-04-07 16:46:33 -0700281 UDP udp = new UDP();
282
283 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700284 udp.sourcePort = (bb.getShort() & 0xffff);
285 udp.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700286 udp.length = bb.getShort();
287 udp.checksum = bb.getShort();
288
289 Deserializer<? extends IPacket> deserializer;
290 if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.destinationPort)) {
291 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.destinationPort);
292 } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.sourcePort)) {
293 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.sourcePort);
294 } else {
295 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700296 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700297
298 udp.payload = deserializer.deserialize(data, bb.position(),
299 bb.limit() - bb.position());
300 udp.payload.setParent(udp);
301 return udp;
302 };
alshabibc4901cd2014-09-05 16:50:40 -0700303 }
Jian Li5fc14292015-12-04 11:30:46 -0800304
305 @Override
306 public String toString() {
307 return toStringHelper(getClass())
308 .add("sourcePort", Integer.toString(sourcePort))
309 .add("destinationPort", Integer.toString(destinationPort))
310 .add("length", Short.toString(length))
311 .add("checksum", Short.toString(checksum))
312 .toString();
313 }
alshabibc4901cd2014-09-05 16:50:40 -0700314}