blob: 8411d8f1608ce60e7d737037b546ff5a40b6bc82 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
Ray Milkey269ffb92014-04-03 14:43:30 -07002 * 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 **/
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080017
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070018package net.onrc.onos.core.packet;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080019
20import java.nio.ByteBuffer;
21import java.util.HashMap;
22import java.util.Map;
23
24/**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080025 * @author David Erickson (daviderickson@cs.stanford.edu)
26 */
27public class UDP extends BasePacket {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070028 public static final short DHCP_SERVER_PORT = (short) 67;
29 public static final short DHCP_CLIENT_PORT = (short) 68;
30 public static final Map<Short, Class<? extends IPacket>> DECODE_MAP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080031
32 static {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070033 DECODE_MAP = new HashMap<Short, Class<? extends IPacket>>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080034 /*
35 * Disable DHCP until the deserialize code is hardened to deal with garbage input
36 */
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070037 UDP.DECODE_MAP.put(DHCP_SERVER_PORT, DHCP.class);
38 UDP.DECODE_MAP.put(DHCP_CLIENT_PORT, DHCP.class);
Ray Milkey269ffb92014-04-03 14:43:30 -070039
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080040 }
41
42 protected short sourcePort;
43 protected short destinationPort;
44 protected short length;
45 protected short checksum;
46
47 /**
48 * @return the sourcePort
49 */
50 public short getSourcePort() {
51 return sourcePort;
52 }
53
54 /**
55 * @param sourcePort the sourcePort to set
56 */
57 public UDP setSourcePort(short sourcePort) {
58 this.sourcePort = sourcePort;
59 return this;
60 }
61
62 /**
63 * @return the destinationPort
64 */
65 public short getDestinationPort() {
66 return destinationPort;
67 }
68
69 /**
70 * @param destinationPort the destinationPort to set
71 */
72 public UDP setDestinationPort(short destinationPort) {
73 this.destinationPort = destinationPort;
74 return this;
75 }
76
77 /**
78 * @return the length
79 */
80 public short getLength() {
81 return length;
82 }
83
84 /**
85 * @return the checksum
86 */
87 public short getChecksum() {
88 return checksum;
89 }
90
91 /**
92 * @param checksum the checksum to set
93 */
94 public UDP setChecksum(short checksum) {
95 this.checksum = checksum;
96 return this;
97 }
98
99 @Override
100 public void resetChecksum() {
101 this.checksum = 0;
102 super.resetChecksum();
103 }
104
105 /**
106 * Serializes the packet. Will compute and set the following fields if they
107 * are set to specific values at the time serialize is called:
Ray Milkey269ffb92014-04-03 14:43:30 -0700108 * -checksum : 0
109 * -length : 0
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800110 */
111 public byte[] serialize() {
112 byte[] payloadData = null;
113 if (payload != null) {
114 payload.setParent(this);
115 payloadData = payload.serialize();
116 }
117
118 this.length = (short) (8 + ((payloadData == null) ? 0
119 : payloadData.length));
120
121 byte[] data = new byte[this.length];
122 ByteBuffer bb = ByteBuffer.wrap(data);
123
124 bb.putShort(this.sourcePort);
125 bb.putShort(this.destinationPort);
126 bb.putShort(this.length);
127 bb.putShort(this.checksum);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700128 if (payloadData != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800129 bb.put(payloadData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700130 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800131
Ray Milkeyb29e6262014-04-09 16:02:14 -0700132 if (this.parent != null && this.parent instanceof IPv4) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700134 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800135
136 // compute checksum if needed
137 if (this.checksum == 0) {
138 bb.rewind();
139 int accumulation = 0;
140
141 // compute pseudo header mac
142 if (this.parent != null && this.parent instanceof IPv4) {
143 IPv4 ipv4 = (IPv4) this.parent;
144 accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
145 + (ipv4.getSourceAddress() & 0xffff);
146 accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
147 + (ipv4.getDestinationAddress() & 0xffff);
148 accumulation += ipv4.getProtocol() & 0xff;
149 accumulation += this.length & 0xffff;
150 }
151
152 for (int i = 0; i < this.length / 2; ++i) {
153 accumulation += 0xffff & bb.getShort();
154 }
155 // pad to an even number of shorts
156 if (this.length % 2 > 0) {
157 accumulation += (bb.get() & 0xff) << 8;
158 }
159
160 accumulation = ((accumulation >> 16) & 0xffff)
161 + (accumulation & 0xffff);
162 this.checksum = (short) (~accumulation & 0xffff);
163 bb.putShort(6, this.checksum);
164 }
165 return data;
166 }
167
168 /* (non-Javadoc)
169 * @see java.lang.Object#hashCode()
170 */
171 @Override
172 public int hashCode() {
173 final int prime = 5807;
174 int result = super.hashCode();
175 result = prime * result + checksum;
176 result = prime * result + destinationPort;
177 result = prime * result + length;
178 result = prime * result + sourcePort;
179 return result;
180 }
181
182 /* (non-Javadoc)
183 * @see java.lang.Object#equals(java.lang.Object)
184 */
185 @Override
186 public boolean equals(Object obj) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700187 if (this == obj) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800188 return true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700189 }
190 if (!super.equals(obj)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800191 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700192 }
193 if (!(obj instanceof UDP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800194 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700195 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800196 UDP other = (UDP) obj;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700197 if (checksum != other.checksum) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800198 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700199 }
200 if (destinationPort != other.destinationPort) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800201 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700202 }
203 if (length != other.length) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800204 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700205 }
206 if (sourcePort != other.sourcePort) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800207 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700208 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800209 return true;
210 }
211
212 @Override
213 public IPacket deserialize(byte[] data, int offset, int length) {
214 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
215 this.sourcePort = bb.getShort();
216 this.destinationPort = bb.getShort();
217 this.length = bb.getShort();
218 this.checksum = bb.getShort();
219
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700220 if (UDP.DECODE_MAP.containsKey(this.destinationPort)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800221 try {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700222 this.payload = UDP.DECODE_MAP.get(this.destinationPort).getConstructor().newInstance();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800223 } catch (Exception e) {
224 throw new RuntimeException("Failure instantiating class", e);
225 }
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700226 } else if (UDP.DECODE_MAP.containsKey(this.sourcePort)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800227 try {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700228 this.payload = UDP.DECODE_MAP.get(this.sourcePort).getConstructor().newInstance();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800229 } catch (Exception e) {
230 throw new RuntimeException("Failure instantiating class", e);
231 }
232 } else {
233 this.payload = new Data();
234 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700235 this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800236 this.payload.setParent(this);
237 return this;
238 }
239}