blob: 11ea81b2da5531960a941ec4a436a91df428ddad [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
alshabibc4901cd2014-09-05 16:50:40 -07009 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
Thomas Vachuska24c849c2014-10-27 09:53:05 -070012 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
alshabibc4901cd2014-09-05 16:50:40 -070017 * under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070018 */
19
20
alshabibc4901cd2014-09-05 16:50:40 -070021
22package org.onlab.packet;
23
24import java.nio.ByteBuffer;
25import java.util.HashMap;
26import java.util.Map;
27
28/**
29 *
alshabibc4901cd2014-09-05 16:50:40 -070030 */
31
32public class UDP extends BasePacket {
33 public static Map<Short, Class<? extends IPacket>> decodeMap;
34 public static final short DHCP_SERVER_PORT = (short) 67;
35 public static final short DHCP_CLIENT_PORT = (short) 68;
36
37 static {
38 UDP.decodeMap = new HashMap<Short, Class<? extends IPacket>>();
39 /*
40 * Disable DHCP until the deserialize code is hardened to deal with
41 * garbage input
42 */
43 UDP.decodeMap.put(UDP.DHCP_SERVER_PORT, DHCP.class);
44 UDP.decodeMap.put(UDP.DHCP_CLIENT_PORT, DHCP.class);
45
46 }
47
48 protected short sourcePort;
49 protected short destinationPort;
50 protected short length;
51 protected short checksum;
52
53 /**
54 * @return the sourcePort
55 */
56 public short getSourcePort() {
57 return this.sourcePort;
58 }
59
60 /**
61 * @param sourcePort
62 * the sourcePort to set
63 */
64 public UDP setSourcePort(final short sourcePort) {
65 this.sourcePort = sourcePort;
66 return this;
67 }
68
69 /**
70 * @return the destinationPort
71 */
72 public short getDestinationPort() {
73 return this.destinationPort;
74 }
75
76 /**
77 * @param destinationPort
78 * the destinationPort to set
79 */
80 public UDP setDestinationPort(final short destinationPort) {
81 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
102 */
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
234 if (UDP.decodeMap.containsKey(this.destinationPort)) {
235 try {
236 this.payload = UDP.decodeMap.get(this.destinationPort)
237 .getConstructor().newInstance();
238 } catch (final Exception e) {
239 throw new RuntimeException("Failure instantiating class", e);
240 }
241 } else if (UDP.decodeMap.containsKey(this.sourcePort)) {
242 try {
243 this.payload = UDP.decodeMap.get(this.sourcePort)
244 .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}