blob: 5d9c645dabed60a8e514a187d8c3ce357ce4a8d8 [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 {
30 public static Map<Short, Class<? extends IPacket>> decodeMap;
31 public static final short DHCP_SERVER_PORT = (short) 67;
32 public static final short DHCP_CLIENT_PORT = (short) 68;
33
34 static {
35 UDP.decodeMap = new HashMap<Short, Class<? extends IPacket>>();
36 /*
37 * Disable DHCP until the deserialize code is hardened to deal with
38 * garbage input
39 */
40 UDP.decodeMap.put(UDP.DHCP_SERVER_PORT, DHCP.class);
41 UDP.decodeMap.put(UDP.DHCP_CLIENT_PORT, DHCP.class);
42
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
60 */
61 public UDP setSourcePort(final short sourcePort) {
62 this.sourcePort = sourcePort;
63 return this;
64 }
65
66 /**
67 * @return the destinationPort
68 */
69 public short getDestinationPort() {
70 return this.destinationPort;
71 }
72
73 /**
74 * @param destinationPort
75 * the destinationPort to set
76 */
77 public UDP setDestinationPort(final short destinationPort) {
78 this.destinationPort = destinationPort;
79 return this;
80 }
81
82 /**
83 * @return the length
84 */
85 public short getLength() {
86 return this.length;
87 }
88
89 /**
90 * @return the checksum
91 */
92 public short getChecksum() {
93 return this.checksum;
94 }
95
96 /**
97 * @param checksum
98 * the checksum to set
99 */
100 public UDP setChecksum(final short checksum) {
101 this.checksum = checksum;
102 return this;
103 }
104
105 @Override
106 public void resetChecksum() {
107 this.checksum = 0;
108 super.resetChecksum();
109 }
110
111 /**
112 * Serializes the packet. Will compute and set the following fields if they
113 * are set to specific values at the time serialize is called: -checksum : 0
114 * -length : 0
115 */
116 @Override
117 public byte[] serialize() {
118 byte[] payloadData = null;
119 if (this.payload != null) {
120 this.payload.setParent(this);
121 payloadData = this.payload.serialize();
122 }
123
124 this.length = (short) (8 + (payloadData == null ? 0
125 : payloadData.length));
126
127 final byte[] data = new byte[this.length];
128 final ByteBuffer bb = ByteBuffer.wrap(data);
129
130 bb.putShort(this.sourcePort);
131 bb.putShort(this.destinationPort);
132 bb.putShort(this.length);
133 bb.putShort(this.checksum);
134 if (payloadData != null) {
135 bb.put(payloadData);
136 }
137
138 if (this.parent != null && this.parent instanceof IPv4) {
139 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
140 }
141
142 // compute checksum if needed
143 if (this.checksum == 0) {
144 bb.rewind();
145 int accumulation = 0;
146
147 // compute pseudo header mac
148 if (this.parent != null && this.parent instanceof IPv4) {
149 final IPv4 ipv4 = (IPv4) this.parent;
150 accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
151 + (ipv4.getSourceAddress() & 0xffff);
152 accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
153 + (ipv4.getDestinationAddress() & 0xffff);
154 accumulation += ipv4.getProtocol() & 0xff;
155 accumulation += this.length & 0xffff;
156 }
157
158 for (int i = 0; i < this.length / 2; ++i) {
159 accumulation += 0xffff & bb.getShort();
160 }
161 // pad to an even number of shorts
162 if (this.length % 2 > 0) {
163 accumulation += (bb.get() & 0xff) << 8;
164 }
165
166 accumulation = (accumulation >> 16 & 0xffff)
167 + (accumulation & 0xffff);
168 this.checksum = (short) (~accumulation & 0xffff);
169 bb.putShort(6, this.checksum);
170 }
171 return data;
172 }
173
174 /*
175 * (non-Javadoc)
176 *
177 * @see java.lang.Object#hashCode()
178 */
179 @Override
180 public int hashCode() {
181 final int prime = 5807;
182 int result = super.hashCode();
183 result = prime * result + this.checksum;
184 result = prime * result + this.destinationPort;
185 result = prime * result + this.length;
186 result = prime * result + this.sourcePort;
187 return result;
188 }
189
190 /*
191 * (non-Javadoc)
192 *
193 * @see java.lang.Object#equals(java.lang.Object)
194 */
195 @Override
196 public boolean equals(final Object obj) {
197 if (this == obj) {
198 return true;
199 }
200 if (!super.equals(obj)) {
201 return false;
202 }
203 if (!(obj instanceof UDP)) {
204 return false;
205 }
206 final UDP other = (UDP) obj;
207 if (this.checksum != other.checksum) {
208 return false;
209 }
210 if (this.destinationPort != other.destinationPort) {
211 return false;
212 }
213 if (this.length != other.length) {
214 return false;
215 }
216 if (this.sourcePort != other.sourcePort) {
217 return false;
218 }
219 return true;
220 }
221
222 @Override
223 public IPacket deserialize(final byte[] data, final int offset,
224 final int length) {
225 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
226 this.sourcePort = bb.getShort();
227 this.destinationPort = bb.getShort();
228 this.length = bb.getShort();
229 this.checksum = bb.getShort();
230
231 if (UDP.decodeMap.containsKey(this.destinationPort)) {
232 try {
233 this.payload = UDP.decodeMap.get(this.destinationPort)
234 .getConstructor().newInstance();
235 } catch (final Exception e) {
236 throw new RuntimeException("Failure instantiating class", e);
237 }
238 } else if (UDP.decodeMap.containsKey(this.sourcePort)) {
239 try {
240 this.payload = UDP.decodeMap.get(this.sourcePort)
241 .getConstructor().newInstance();
242 } catch (final Exception e) {
243 throw new RuntimeException("Failure instantiating class", e);
244 }
245 } else {
246 this.payload = new Data();
247 }
248 this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
249 - bb.position());
250 this.payload.setParent(this);
251 return this;
252 }
253}