blob: a5711e7a21e329f2b3833022e2eaba8ba51f9438 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
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())
Kalhee Kim6222dbe2017-10-26 15:44:37 +000038 .put(UDP.RIP_PORT, RIP.deserializer())
39 .put(UDP.RIPNG_PORT, RIPng.deserializer())
Yi Tseng60bf35a2017-06-02 17:05:48 -070040 .build();
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070041
Thomas Vachuskae4ed1a22015-08-26 15:19:05 -070042 public static final int DHCP_SERVER_PORT = 67;
43 public static final int DHCP_CLIENT_PORT = 68;
Yi Tseng60bf35a2017-06-02 17:05:48 -070044 public static final int DHCP_V6_SERVER_PORT = 547;
45 public static final int DHCP_V6_CLIENT_PORT = 546;
jaegonkim1179d832017-06-13 19:30:55 +090046 public static final int VXLAN_UDP_PORT = 4789;
Kalhee Kim6222dbe2017-10-26 15:44:37 +000047 public static final int RIP_PORT = 520;
48 public static final int RIPNG_PORT = 521;
alshabibc4901cd2014-09-05 16:50:40 -070049
Jonathan Hart2a655752015-04-07 16:46:33 -070050 private static final short UDP_HEADER_LENGTH = 8;
51
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070052 protected int sourcePort;
53 protected int destinationPort;
alshabibc4901cd2014-09-05 16:50:40 -070054 protected short length;
55 protected short checksum;
56
57 /**
58 * @return the sourcePort
59 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070060 public int getSourcePort() {
alshabibc4901cd2014-09-05 16:50:40 -070061 return this.sourcePort;
62 }
63
64 /**
65 * @param sourcePort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070066 * the sourcePort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080067 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070068 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070069 public UDP setSourcePort(final int sourcePort) {
alshabibc4901cd2014-09-05 16:50:40 -070070 this.sourcePort = sourcePort;
71 return this;
72 }
73
74 /**
75 * @return the destinationPort
76 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070077 public int getDestinationPort() {
alshabibc4901cd2014-09-05 16:50:40 -070078 return this.destinationPort;
79 }
80
81 /**
82 * @param destinationPort
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070083 * the destinationPort to set (16 bits unsigned integer)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080084 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070085 */
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070086 public UDP setDestinationPort(final int destinationPort) {
alshabibc4901cd2014-09-05 16:50:40 -070087 this.destinationPort = destinationPort;
88 return this;
89 }
90
91 /**
92 * @return the length
93 */
94 public short getLength() {
95 return this.length;
96 }
97
98 /**
99 * @return the checksum
100 */
101 public short getChecksum() {
102 return this.checksum;
103 }
104
105 /**
106 * @param checksum
107 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800108 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700109 */
110 public UDP setChecksum(final short checksum) {
111 this.checksum = checksum;
112 return this;
113 }
114
115 @Override
116 public void resetChecksum() {
117 this.checksum = 0;
118 super.resetChecksum();
119 }
120
121 /**
122 * Serializes the packet. Will compute and set the following fields if they
123 * are set to specific values at the time serialize is called: -checksum : 0
124 * -length : 0
125 */
126 @Override
127 public byte[] serialize() {
128 byte[] payloadData = null;
129 if (this.payload != null) {
130 this.payload.setParent(this);
131 payloadData = this.payload.serialize();
132 }
133
134 this.length = (short) (8 + (payloadData == null ? 0
135 : payloadData.length));
136
137 final byte[] data = new byte[this.length];
138 final ByteBuffer bb = ByteBuffer.wrap(data);
139
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700140 bb.putShort((short) (this.sourcePort & 0xffff));
141 bb.putShort((short) (this.destinationPort & 0xffff));
alshabibc4901cd2014-09-05 16:50:40 -0700142 bb.putShort(this.length);
143 bb.putShort(this.checksum);
144 if (payloadData != null) {
145 bb.put(payloadData);
146 }
147
148 if (this.parent != null && this.parent instanceof IPv4) {
149 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
150 }
151
152 // compute checksum if needed
153 if (this.checksum == 0) {
154 bb.rewind();
155 int accumulation = 0;
156
157 // compute pseudo header mac
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800158 if (this.parent != null) {
159 if (this.parent instanceof IPv4) {
160 final IPv4 ipv4 = (IPv4) this.parent;
161 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
162 + (ipv4.getSourceAddress() & 0xffff);
163 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
164 + (ipv4.getDestinationAddress() & 0xffff);
165 accumulation += ipv4.getProtocol() & 0xff;
166 accumulation += length & 0xffff;
167 } else if (this.parent instanceof IPv6) {
168 final IPv6 ipv6 = (IPv6) this.parent;
169 final int bbLength =
170 Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
171 + 2 // nextHeader (with padding)
172 + 4; // length
173 final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
174 bbChecksum.put(ipv6.getSourceAddress());
175 bbChecksum.put(ipv6.getDestinationAddress());
176 bbChecksum.put((byte) 0); // padding
177 bbChecksum.put(ipv6.getNextHeader());
178 bbChecksum.putInt(length);
179 bbChecksum.rewind();
180 for (int i = 0; i < bbLength / 2; ++i) {
181 accumulation += 0xffff & bbChecksum.getShort();
182 }
183 }
alshabibc4901cd2014-09-05 16:50:40 -0700184 }
185
186 for (int i = 0; i < this.length / 2; ++i) {
187 accumulation += 0xffff & bb.getShort();
188 }
189 // pad to an even number of shorts
190 if (this.length % 2 > 0) {
191 accumulation += (bb.get() & 0xff) << 8;
192 }
193
194 accumulation = (accumulation >> 16 & 0xffff)
195 + (accumulation & 0xffff);
196 this.checksum = (short) (~accumulation & 0xffff);
197 bb.putShort(6, this.checksum);
198 }
199 return data;
200 }
201
202 /*
203 * (non-Javadoc)
204 *
205 * @see java.lang.Object#hashCode()
206 */
207 @Override
208 public int hashCode() {
209 final int prime = 5807;
210 int result = super.hashCode();
211 result = prime * result + this.checksum;
212 result = prime * result + this.destinationPort;
213 result = prime * result + this.length;
214 result = prime * result + this.sourcePort;
215 return result;
216 }
217
218 /*
219 * (non-Javadoc)
220 *
221 * @see java.lang.Object#equals(java.lang.Object)
222 */
223 @Override
224 public boolean equals(final Object obj) {
225 if (this == obj) {
226 return true;
227 }
228 if (!super.equals(obj)) {
229 return false;
230 }
231 if (!(obj instanceof UDP)) {
232 return false;
233 }
234 final UDP other = (UDP) obj;
235 if (this.checksum != other.checksum) {
236 return false;
237 }
238 if (this.destinationPort != other.destinationPort) {
239 return false;
240 }
241 if (this.length != other.length) {
242 return false;
243 }
244 if (this.sourcePort != other.sourcePort) {
245 return false;
246 }
247 return true;
248 }
249
Jonathan Hart2a655752015-04-07 16:46:33 -0700250 /**
251 * Deserializer function for UDP packets.
252 *
253 * @return deserializer function
254 */
255 public static Deserializer<UDP> deserializer() {
256 return (data, offset, length) -> {
257 checkInput(data, offset, length, UDP_HEADER_LENGTH);
alshabibc4901cd2014-09-05 16:50:40 -0700258
Jonathan Hart2a655752015-04-07 16:46:33 -0700259 UDP udp = new UDP();
260
261 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700262 udp.sourcePort = (bb.getShort() & 0xffff);
263 udp.destinationPort = (bb.getShort() & 0xffff);
Jonathan Hart2a655752015-04-07 16:46:33 -0700264 udp.length = bb.getShort();
265 udp.checksum = bb.getShort();
266
267 Deserializer<? extends IPacket> deserializer;
268 if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.destinationPort)) {
269 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.destinationPort);
270 } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.sourcePort)) {
271 deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.sourcePort);
272 } else {
273 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700274 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700275
276 udp.payload = deserializer.deserialize(data, bb.position(),
277 bb.limit() - bb.position());
278 udp.payload.setParent(udp);
279 return udp;
280 };
alshabibc4901cd2014-09-05 16:50:40 -0700281 }
Jian Li5fc14292015-12-04 11:30:46 -0800282
283 @Override
284 public String toString() {
285 return toStringHelper(getClass())
286 .add("sourcePort", Integer.toString(sourcePort))
287 .add("destinationPort", Integer.toString(destinationPort))
288 .add("length", Short.toString(length))
289 .add("checksum", Short.toString(checksum))
290 .toString();
291 }
alshabibc4901cd2014-09-05 16:50:40 -0700292}