blob: 7886dab0fd7bbc6f34839904c5f9d906589dfb4d [file] [log] [blame]
alshabibc4901cd2014-09-05 16:50:40 -07001/*******************************************************************************
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * 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
7 *
8 * 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.
15 ******************************************************************************/
16/**
17 * Copyright 2011, Big Switch Networks, Inc.
18 * Originally created by David Erickson, Stanford University
19 *
20 * Licensed under the Apache License, Version 2.0 (the "License"); you may
21 * not use this file except in compliance with the License. You may obtain
22 * a copy of the License at
23 *
24 * http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
28 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
29 * License for the specific language governing permissions and limitations
30 * under the License.
31 **/
32
33package org.onlab.packet;
34
35import java.nio.ByteBuffer;
36import java.util.HashMap;
37import java.util.Map;
38
39/**
40 *
alshabibc4901cd2014-09-05 16:50:40 -070041 */
42
43public class UDP extends BasePacket {
44 public static Map<Short, Class<? extends IPacket>> decodeMap;
45 public static final short DHCP_SERVER_PORT = (short) 67;
46 public static final short DHCP_CLIENT_PORT = (short) 68;
47
48 static {
49 UDP.decodeMap = new HashMap<Short, Class<? extends IPacket>>();
50 /*
51 * Disable DHCP until the deserialize code is hardened to deal with
52 * garbage input
53 */
54 UDP.decodeMap.put(UDP.DHCP_SERVER_PORT, DHCP.class);
55 UDP.decodeMap.put(UDP.DHCP_CLIENT_PORT, DHCP.class);
56
57 }
58
59 protected short sourcePort;
60 protected short destinationPort;
61 protected short length;
62 protected short checksum;
63
64 /**
65 * @return the sourcePort
66 */
67 public short getSourcePort() {
68 return this.sourcePort;
69 }
70
71 /**
72 * @param sourcePort
73 * the sourcePort to set
74 */
75 public UDP setSourcePort(final short sourcePort) {
76 this.sourcePort = sourcePort;
77 return this;
78 }
79
80 /**
81 * @return the destinationPort
82 */
83 public short getDestinationPort() {
84 return this.destinationPort;
85 }
86
87 /**
88 * @param destinationPort
89 * the destinationPort to set
90 */
91 public UDP setDestinationPort(final short destinationPort) {
92 this.destinationPort = destinationPort;
93 return this;
94 }
95
96 /**
97 * @return the length
98 */
99 public short getLength() {
100 return this.length;
101 }
102
103 /**
104 * @return the checksum
105 */
106 public short getChecksum() {
107 return this.checksum;
108 }
109
110 /**
111 * @param checksum
112 * the checksum to set
113 */
114 public UDP setChecksum(final short checksum) {
115 this.checksum = checksum;
116 return this;
117 }
118
119 @Override
120 public void resetChecksum() {
121 this.checksum = 0;
122 super.resetChecksum();
123 }
124
125 /**
126 * Serializes the packet. Will compute and set the following fields if they
127 * are set to specific values at the time serialize is called: -checksum : 0
128 * -length : 0
129 */
130 @Override
131 public byte[] serialize() {
132 byte[] payloadData = null;
133 if (this.payload != null) {
134 this.payload.setParent(this);
135 payloadData = this.payload.serialize();
136 }
137
138 this.length = (short) (8 + (payloadData == null ? 0
139 : payloadData.length));
140
141 final byte[] data = new byte[this.length];
142 final ByteBuffer bb = ByteBuffer.wrap(data);
143
144 bb.putShort(this.sourcePort);
145 bb.putShort(this.destinationPort);
146 bb.putShort(this.length);
147 bb.putShort(this.checksum);
148 if (payloadData != null) {
149 bb.put(payloadData);
150 }
151
152 if (this.parent != null && this.parent instanceof IPv4) {
153 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
154 }
155
156 // compute checksum if needed
157 if (this.checksum == 0) {
158 bb.rewind();
159 int accumulation = 0;
160
161 // compute pseudo header mac
162 if (this.parent != null && this.parent instanceof IPv4) {
163 final IPv4 ipv4 = (IPv4) this.parent;
164 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
165 + (ipv4.getSourceAddress() & 0xffff);
166 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
167 + (ipv4.getDestinationAddress() & 0xffff);
168 accumulation += ipv4.getProtocol() & 0xff;
169 accumulation += this.length & 0xffff;
170 }
171
172 for (int i = 0; i < this.length / 2; ++i) {
173 accumulation += 0xffff & bb.getShort();
174 }
175 // pad to an even number of shorts
176 if (this.length % 2 > 0) {
177 accumulation += (bb.get() & 0xff) << 8;
178 }
179
180 accumulation = (accumulation >> 16 & 0xffff)
181 + (accumulation & 0xffff);
182 this.checksum = (short) (~accumulation & 0xffff);
183 bb.putShort(6, this.checksum);
184 }
185 return data;
186 }
187
188 /*
189 * (non-Javadoc)
190 *
191 * @see java.lang.Object#hashCode()
192 */
193 @Override
194 public int hashCode() {
195 final int prime = 5807;
196 int result = super.hashCode();
197 result = prime * result + this.checksum;
198 result = prime * result + this.destinationPort;
199 result = prime * result + this.length;
200 result = prime * result + this.sourcePort;
201 return result;
202 }
203
204 /*
205 * (non-Javadoc)
206 *
207 * @see java.lang.Object#equals(java.lang.Object)
208 */
209 @Override
210 public boolean equals(final Object obj) {
211 if (this == obj) {
212 return true;
213 }
214 if (!super.equals(obj)) {
215 return false;
216 }
217 if (!(obj instanceof UDP)) {
218 return false;
219 }
220 final UDP other = (UDP) obj;
221 if (this.checksum != other.checksum) {
222 return false;
223 }
224 if (this.destinationPort != other.destinationPort) {
225 return false;
226 }
227 if (this.length != other.length) {
228 return false;
229 }
230 if (this.sourcePort != other.sourcePort) {
231 return false;
232 }
233 return true;
234 }
235
236 @Override
237 public IPacket deserialize(final byte[] data, final int offset,
238 final int length) {
239 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
240 this.sourcePort = bb.getShort();
241 this.destinationPort = bb.getShort();
242 this.length = bb.getShort();
243 this.checksum = bb.getShort();
244
245 if (UDP.decodeMap.containsKey(this.destinationPort)) {
246 try {
247 this.payload = UDP.decodeMap.get(this.destinationPort)
248 .getConstructor().newInstance();
249 } catch (final Exception e) {
250 throw new RuntimeException("Failure instantiating class", e);
251 }
252 } else if (UDP.decodeMap.containsKey(this.sourcePort)) {
253 try {
254 this.payload = UDP.decodeMap.get(this.sourcePort)
255 .getConstructor().newInstance();
256 } catch (final Exception e) {
257 throw new RuntimeException("Failure instantiating class", e);
258 }
259 } else {
260 this.payload = new Data();
261 }
262 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
263 - bb.position());
264 this.payload.setParent(this);
265 return this;
266 }
267}