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