blob: c743f09c51ca37ccb2c46116fca7f2dccb3d3d6f [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
25/**
26 *
alshabibc4901cd2014-09-05 16:50:40 -070027 */
28
29public class UDP extends BasePacket {
Ray Milkey241b96a2014-11-17 13:08:20 -080030 public static final Map<Short, Class<? extends IPacket>> DECODE_MAP =
31 new HashMap<>();
alshabibc4901cd2014-09-05 16:50:40 -070032 public static final short DHCP_SERVER_PORT = (short) 67;
33 public static final short DHCP_CLIENT_PORT = (short) 68;
34
35 static {
alshabibc4901cd2014-09-05 16:50:40 -070036 /*
37 * Disable DHCP until the deserialize code is hardened to deal with
38 * garbage input
39 */
Ray Milkey241b96a2014-11-17 13:08:20 -080040 UDP.DECODE_MAP.put(UDP.DHCP_SERVER_PORT, DHCP.class);
41 UDP.DECODE_MAP.put(UDP.DHCP_CLIENT_PORT, DHCP.class);
alshabibc4901cd2014-09-05 16:50:40 -070042
43 }
44
45 protected short sourcePort;
46 protected short destinationPort;
47 protected short length;
48 protected short checksum;
49
50 /**
51 * @return the sourcePort
52 */
53 public short getSourcePort() {
54 return this.sourcePort;
55 }
56
57 /**
58 * @param sourcePort
59 * the sourcePort to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080060 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070061 */
62 public UDP setSourcePort(final short sourcePort) {
63 this.sourcePort = sourcePort;
64 return this;
65 }
66
67 /**
68 * @return the destinationPort
69 */
70 public short getDestinationPort() {
71 return this.destinationPort;
72 }
73
74 /**
75 * @param destinationPort
76 * the destinationPort to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080077 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070078 */
79 public UDP setDestinationPort(final short destinationPort) {
80 this.destinationPort = destinationPort;
81 return this;
82 }
83
84 /**
85 * @return the length
86 */
87 public short getLength() {
88 return this.length;
89 }
90
91 /**
92 * @return the checksum
93 */
94 public short getChecksum() {
95 return this.checksum;
96 }
97
98 /**
99 * @param checksum
100 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800101 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700102 */
103 public UDP setChecksum(final short checksum) {
104 this.checksum = checksum;
105 return this;
106 }
107
108 @Override
109 public void resetChecksum() {
110 this.checksum = 0;
111 super.resetChecksum();
112 }
113
114 /**
115 * Serializes the packet. Will compute and set the following fields if they
116 * are set to specific values at the time serialize is called: -checksum : 0
117 * -length : 0
118 */
119 @Override
120 public byte[] serialize() {
121 byte[] payloadData = null;
122 if (this.payload != null) {
123 this.payload.setParent(this);
124 payloadData = this.payload.serialize();
125 }
126
127 this.length = (short) (8 + (payloadData == null ? 0
128 : payloadData.length));
129
130 final byte[] data = new byte[this.length];
131 final ByteBuffer bb = ByteBuffer.wrap(data);
132
133 bb.putShort(this.sourcePort);
134 bb.putShort(this.destinationPort);
135 bb.putShort(this.length);
136 bb.putShort(this.checksum);
137 if (payloadData != null) {
138 bb.put(payloadData);
139 }
140
141 if (this.parent != null && this.parent instanceof IPv4) {
142 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
143 }
144
145 // compute checksum if needed
146 if (this.checksum == 0) {
147 bb.rewind();
148 int accumulation = 0;
149
150 // compute pseudo header mac
Charles M.C. Chan197a0122015-04-08 18:15:34 +0800151 if (this.parent != null) {
152 if (this.parent instanceof IPv4) {
153 final IPv4 ipv4 = (IPv4) this.parent;
154 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
155 + (ipv4.getSourceAddress() & 0xffff);
156 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
157 + (ipv4.getDestinationAddress() & 0xffff);
158 accumulation += ipv4.getProtocol() & 0xff;
159 accumulation += length & 0xffff;
160 } else if (this.parent instanceof IPv6) {
161 final IPv6 ipv6 = (IPv6) this.parent;
162 final int bbLength =
163 Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
164 + 2 // nextHeader (with padding)
165 + 4; // length
166 final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
167 bbChecksum.put(ipv6.getSourceAddress());
168 bbChecksum.put(ipv6.getDestinationAddress());
169 bbChecksum.put((byte) 0); // padding
170 bbChecksum.put(ipv6.getNextHeader());
171 bbChecksum.putInt(length);
172 bbChecksum.rewind();
173 for (int i = 0; i < bbLength / 2; ++i) {
174 accumulation += 0xffff & bbChecksum.getShort();
175 }
176 }
alshabibc4901cd2014-09-05 16:50:40 -0700177 }
178
179 for (int i = 0; i < this.length / 2; ++i) {
180 accumulation += 0xffff & bb.getShort();
181 }
182 // pad to an even number of shorts
183 if (this.length % 2 > 0) {
184 accumulation += (bb.get() & 0xff) << 8;
185 }
186
187 accumulation = (accumulation >> 16 & 0xffff)
188 + (accumulation & 0xffff);
189 this.checksum = (short) (~accumulation & 0xffff);
190 bb.putShort(6, this.checksum);
191 }
192 return data;
193 }
194
195 /*
196 * (non-Javadoc)
197 *
198 * @see java.lang.Object#hashCode()
199 */
200 @Override
201 public int hashCode() {
202 final int prime = 5807;
203 int result = super.hashCode();
204 result = prime * result + this.checksum;
205 result = prime * result + this.destinationPort;
206 result = prime * result + this.length;
207 result = prime * result + this.sourcePort;
208 return result;
209 }
210
211 /*
212 * (non-Javadoc)
213 *
214 * @see java.lang.Object#equals(java.lang.Object)
215 */
216 @Override
217 public boolean equals(final Object obj) {
218 if (this == obj) {
219 return true;
220 }
221 if (!super.equals(obj)) {
222 return false;
223 }
224 if (!(obj instanceof UDP)) {
225 return false;
226 }
227 final UDP other = (UDP) obj;
228 if (this.checksum != other.checksum) {
229 return false;
230 }
231 if (this.destinationPort != other.destinationPort) {
232 return false;
233 }
234 if (this.length != other.length) {
235 return false;
236 }
237 if (this.sourcePort != other.sourcePort) {
238 return false;
239 }
240 return true;
241 }
242
243 @Override
244 public IPacket deserialize(final byte[] data, final int offset,
245 final int length) {
246 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
247 this.sourcePort = bb.getShort();
248 this.destinationPort = bb.getShort();
249 this.length = bb.getShort();
250 this.checksum = bb.getShort();
251
Ray Milkey241b96a2014-11-17 13:08:20 -0800252 if (UDP.DECODE_MAP.containsKey(this.destinationPort)) {
alshabibc4901cd2014-09-05 16:50:40 -0700253 try {
Ray Milkey241b96a2014-11-17 13:08:20 -0800254 this.payload = UDP.DECODE_MAP.get(this.destinationPort)
alshabibc4901cd2014-09-05 16:50:40 -0700255 .getConstructor().newInstance();
256 } catch (final Exception e) {
257 throw new RuntimeException("Failure instantiating class", e);
258 }
Ray Milkey241b96a2014-11-17 13:08:20 -0800259 } else if (UDP.DECODE_MAP.containsKey(this.sourcePort)) {
alshabibc4901cd2014-09-05 16:50:40 -0700260 try {
Ray Milkey241b96a2014-11-17 13:08:20 -0800261 this.payload = UDP.DECODE_MAP.get(this.sourcePort)
alshabibc4901cd2014-09-05 16:50:40 -0700262 .getConstructor().newInstance();
263 } catch (final Exception e) {
264 throw new RuntimeException("Failure instantiating class", e);
265 }
266 } else {
267 this.payload = new Data();
268 }
269 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
270 - bb.position());
271 this.payload.setParent(this);
272 return this;
273 }
274}