blob: 19e23c04f3258c5e2f1085a3be0851d52f3d7df5 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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
151 if (this.parent != null && this.parent instanceof IPv4) {
152 final IPv4 ipv4 = (IPv4) this.parent;
153 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
154 + (ipv4.getSourceAddress() & 0xffff);
155 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
156 + (ipv4.getDestinationAddress() & 0xffff);
157 accumulation += ipv4.getProtocol() & 0xff;
158 accumulation += this.length & 0xffff;
159 }
160
161 for (int i = 0; i < this.length / 2; ++i) {
162 accumulation += 0xffff & bb.getShort();
163 }
164 // pad to an even number of shorts
165 if (this.length % 2 > 0) {
166 accumulation += (bb.get() & 0xff) << 8;
167 }
168
169 accumulation = (accumulation >> 16 & 0xffff)
170 + (accumulation & 0xffff);
171 this.checksum = (short) (~accumulation & 0xffff);
172 bb.putShort(6, this.checksum);
173 }
174 return data;
175 }
176
177 /*
178 * (non-Javadoc)
179 *
180 * @see java.lang.Object#hashCode()
181 */
182 @Override
183 public int hashCode() {
184 final int prime = 5807;
185 int result = super.hashCode();
186 result = prime * result + this.checksum;
187 result = prime * result + this.destinationPort;
188 result = prime * result + this.length;
189 result = prime * result + this.sourcePort;
190 return result;
191 }
192
193 /*
194 * (non-Javadoc)
195 *
196 * @see java.lang.Object#equals(java.lang.Object)
197 */
198 @Override
199 public boolean equals(final Object obj) {
200 if (this == obj) {
201 return true;
202 }
203 if (!super.equals(obj)) {
204 return false;
205 }
206 if (!(obj instanceof UDP)) {
207 return false;
208 }
209 final UDP other = (UDP) obj;
210 if (this.checksum != other.checksum) {
211 return false;
212 }
213 if (this.destinationPort != other.destinationPort) {
214 return false;
215 }
216 if (this.length != other.length) {
217 return false;
218 }
219 if (this.sourcePort != other.sourcePort) {
220 return false;
221 }
222 return true;
223 }
224
225 @Override
226 public IPacket deserialize(final byte[] data, final int offset,
227 final int length) {
228 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
229 this.sourcePort = bb.getShort();
230 this.destinationPort = bb.getShort();
231 this.length = bb.getShort();
232 this.checksum = bb.getShort();
233
Ray Milkey241b96a2014-11-17 13:08:20 -0800234 if (UDP.DECODE_MAP.containsKey(this.destinationPort)) {
alshabibc4901cd2014-09-05 16:50:40 -0700235 try {
Ray Milkey241b96a2014-11-17 13:08:20 -0800236 this.payload = UDP.DECODE_MAP.get(this.destinationPort)
alshabibc4901cd2014-09-05 16:50:40 -0700237 .getConstructor().newInstance();
238 } catch (final Exception e) {
239 throw new RuntimeException("Failure instantiating class", e);
240 }
Ray Milkey241b96a2014-11-17 13:08:20 -0800241 } else if (UDP.DECODE_MAP.containsKey(this.sourcePort)) {
alshabibc4901cd2014-09-05 16:50:40 -0700242 try {
Ray Milkey241b96a2014-11-17 13:08:20 -0800243 this.payload = UDP.DECODE_MAP.get(this.sourcePort)
alshabibc4901cd2014-09-05 16:50:40 -0700244 .getConstructor().newInstance();
245 } catch (final Exception e) {
246 throw new RuntimeException("Failure instantiating class", e);
247 }
248 } else {
249 this.payload = new Data();
250 }
251 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
252 - bb.position());
253 this.payload.setParent(this);
254 return this;
255 }
256}