blob: 51f5161addce93e70d79ece8507b34d6d9a998a8 [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
Yuta HIGUCHIaa132f52014-06-26 10:18:39 -070024// CHECKSTYLE IGNORE WriteTag FOR NEXT 2 LINES
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080025/**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080026 * @author David Erickson (daviderickson@cs.stanford.edu)
27 */
28public class UDP extends BasePacket {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070029 public static final short DHCP_SERVER_PORT = (short) 67;
30 public static final short DHCP_CLIENT_PORT = (short) 68;
31 public static final Map<Short, Class<? extends IPacket>> DECODE_MAP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080032
33 static {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070034 DECODE_MAP = new HashMap<Short, Class<? extends IPacket>>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080035 /*
36 * Disable DHCP until the deserialize code is hardened to deal with garbage input
37 */
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070038 UDP.DECODE_MAP.put(DHCP_SERVER_PORT, DHCP.class);
39 UDP.DECODE_MAP.put(DHCP_CLIENT_PORT, DHCP.class);
Ray Milkey269ffb92014-04-03 14:43:30 -070040
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080041 }
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:
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 * -checksum : 0
110 * -length : 0
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800111 */
Yuta HIGUCHIaa132f52014-06-26 10:18:39 -0700112 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800113 public byte[] serialize() {
114 byte[] payloadData = null;
115 if (payload != null) {
116 payload.setParent(this);
117 payloadData = payload.serialize();
118 }
119
120 this.length = (short) (8 + ((payloadData == null) ? 0
121 : payloadData.length));
122
123 byte[] data = new byte[this.length];
124 ByteBuffer bb = ByteBuffer.wrap(data);
125
126 bb.putShort(this.sourcePort);
127 bb.putShort(this.destinationPort);
128 bb.putShort(this.length);
129 bb.putShort(this.checksum);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700130 if (payloadData != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800131 bb.put(payloadData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700132 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800133
Ray Milkeyb29e6262014-04-09 16:02:14 -0700134 if (this.parent != null && this.parent instanceof IPv4) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700136 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800137
138 // compute checksum if needed
139 if (this.checksum == 0) {
140 bb.rewind();
141 int accumulation = 0;
142
143 // compute pseudo header mac
144 if (this.parent != null && this.parent instanceof IPv4) {
145 IPv4 ipv4 = (IPv4) this.parent;
146 accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
147 + (ipv4.getSourceAddress() & 0xffff);
148 accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
149 + (ipv4.getDestinationAddress() & 0xffff);
150 accumulation += ipv4.getProtocol() & 0xff;
151 accumulation += this.length & 0xffff;
152 }
153
154 for (int i = 0; i < this.length / 2; ++i) {
155 accumulation += 0xffff & bb.getShort();
156 }
157 // pad to an even number of shorts
158 if (this.length % 2 > 0) {
159 accumulation += (bb.get() & 0xff) << 8;
160 }
161
162 accumulation = ((accumulation >> 16) & 0xffff)
163 + (accumulation & 0xffff);
164 this.checksum = (short) (~accumulation & 0xffff);
165 bb.putShort(6, this.checksum);
166 }
167 return data;
168 }
169
170 /* (non-Javadoc)
171 * @see java.lang.Object#hashCode()
172 */
173 @Override
174 public int hashCode() {
175 final int prime = 5807;
176 int result = super.hashCode();
177 result = prime * result + checksum;
178 result = prime * result + destinationPort;
179 result = prime * result + length;
180 result = prime * result + sourcePort;
181 return result;
182 }
183
184 /* (non-Javadoc)
185 * @see java.lang.Object#equals(java.lang.Object)
186 */
187 @Override
188 public boolean equals(Object obj) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700189 if (this == obj) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800190 return true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700191 }
192 if (!super.equals(obj)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800193 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700194 }
195 if (!(obj instanceof UDP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800196 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700197 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800198 UDP other = (UDP) obj;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700199 if (checksum != other.checksum) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800200 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700201 }
202 if (destinationPort != other.destinationPort) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800203 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700204 }
205 if (length != other.length) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800206 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700207 }
208 if (sourcePort != other.sourcePort) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800209 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700210 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800211 return true;
212 }
213
214 @Override
215 public IPacket deserialize(byte[] data, int offset, int length) {
216 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
217 this.sourcePort = bb.getShort();
218 this.destinationPort = bb.getShort();
219 this.length = bb.getShort();
220 this.checksum = bb.getShort();
221
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700222 if (UDP.DECODE_MAP.containsKey(this.destinationPort)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800223 try {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700224 this.payload = UDP.DECODE_MAP.get(this.destinationPort).getConstructor().newInstance();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800225 } catch (Exception e) {
226 throw new RuntimeException("Failure instantiating class", e);
227 }
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700228 } else if (UDP.DECODE_MAP.containsKey(this.sourcePort)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800229 try {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700230 this.payload = UDP.DECODE_MAP.get(this.sourcePort).getConstructor().newInstance();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800231 } catch (Exception e) {
232 throw new RuntimeException("Failure instantiating class", e);
233 }
234 } else {
235 this.payload = new Data();
236 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800238 this.payload.setParent(this);
239 return this;
240 }
241}