blob: aec3c2affae30c061fe63aa582b8f3bad765e56b [file] [log] [blame]
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * 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
7 *
8 * 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.
15 */
16
17
18
19package org.onlab.packet;
20
21import java.nio.ByteBuffer;
22import java.util.Arrays;
23import java.util.HashMap;
24import java.util.Map;
25
26/**
27 *
28 */
29public class IPv6 extends BasePacket {
30 public static final byte FIXED_HEADER_LENGTH = 40; // bytes
31
32 // TODO: Implement extension header.
33 public static final byte PROTOCOL_TCP = 0x6;
34 public static final byte PROTOCOL_UDP = 0x11;
35 public static final byte PROTOCOL_ICMP6 = 0x3A;
36 public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP =
37 new HashMap<>();
38
39 static {
40 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.class);
41 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_TCP, TCP.class);
42 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_UDP, UDP.class);
43 }
44
45 protected byte version;
46 protected byte diffServ;
47 protected int flowLabel;
48 protected short payloadLength;
49 protected byte nextHeader;
50 protected byte hopLimit;
51 protected byte[] sourceAddress = new byte[Ip6Address.BYTE_LENGTH];
52 protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH];
53
54 /**
55 * Default constructor that sets the version to 4.
56 */
57 public IPv6() {
58 super();
59 this.version = 6;
60 }
61
62 /**
63 * @return the version
64 */
65 public byte getVersion() {
66 return this.version;
67 }
68
69 /**
70 * @param version
71 * the version to set
72 * @return this
73 */
74 public IPv6 setVersion(final byte version) {
75 this.version = version;
76 return this;
77 }
78
79 /**
80 * @return the diffServ
81 */
82 public byte getDiffServ() {
83 return this.diffServ;
84 }
85
86 /**
87 * @param diffServ
88 * the diffServ to set
89 * @return this
90 */
91 public IPv6 setDiffServ(final byte diffServ) {
92 this.diffServ = diffServ;
93 return this;
94 }
95
96 /**
97 * @return the flowLabel
98 */
99 public int getFlowLabel() {
100 return this.flowLabel;
101 }
102
103 /**
104 * @param flowLabel
105 * the flowLabel to set
106 * @return this
107 */
108 public IPv6 setFlowLabel(final int flowLabel) {
109 this.flowLabel = flowLabel;
110 return this;
111 }
112
113 /**
114 * @return the nextHeader
115 */
116 public byte getNextHeader() {
117 return this.nextHeader;
118 }
119
120 /**
121 * @param nextHeader
122 * the nextHeader to set
123 * @return this
124 */
125 public IPv6 setNextHeader(final byte nextHeader) {
126 this.nextHeader = nextHeader;
127 return this;
128 }
129
130 /**
131 * @return the hopLimit
132 */
133 public byte getHopLimit() {
134 return this.hopLimit;
135 }
136
137 /**
138 * @param hopLimit
139 * the hopLimit to set
140 * @return this
141 */
142 public IPv6 setHopLimit(final byte hopLimit) {
143 this.hopLimit = hopLimit;
144 return this;
145 }
146
147 /**
148 * @return the sourceAddress
149 */
150 public byte[] getSourceAddress() {
151 return this.sourceAddress;
152 }
153
154 /**
155 * @param sourceAddress
156 * the sourceAddress to set
157 * @return this
158 */
159 public IPv6 setSourceAddress(final byte[] sourceAddress) {
160 this.sourceAddress = Arrays.copyOfRange(sourceAddress, 0, Ip6Address.BYTE_LENGTH);
161 return this;
162 }
163
164 /**
165 * @return the destinationAddress
166 */
167 public byte[] getDestinationAddress() {
168 return this.destinationAddress;
169 }
170
171 /**
172 * @param destinationAddress
173 * the destinationAddress to set
174 * @return this
175 */
176 public IPv6 setDestinationAddress(final byte[] destinationAddress) {
177 this.destinationAddress = Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH);
178 return this;
179 }
180
181 @Override
182 public byte[] serialize() {
183 byte[] payloadData = null;
184 if (this.payload != null) {
185 this.payload.setParent(this);
186 payloadData = this.payload.serialize();
187 }
188
189 this.payloadLength = payloadData == null ? 0 : (short) payloadData.length;
190
191 final byte[] data = new byte[FIXED_HEADER_LENGTH + payloadLength];
192 final ByteBuffer bb = ByteBuffer.wrap(data);
193
194 bb.putInt((this.version & 0xf) << 28 | (this.diffServ & 0xff) << 20 | this.flowLabel & 0xfffff);
195 bb.putShort(this.payloadLength);
196 bb.put(this.nextHeader);
197 bb.put(this.hopLimit);
198 bb.put(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
199 bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
200
201 if (payloadData != null) {
202 bb.put(payloadData);
203 }
204
205 return data;
206 }
207
208 @Override
209 public IPacket deserialize(final byte[] data, final int offset,
210 final int length) {
211 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
212 int iscratch;
213
214 iscratch = bb.getInt();
215 this.version = (byte) (iscratch >> 28 & 0xf);
216 this.diffServ = (byte) (iscratch >> 20 & 0xff);
217 this.flowLabel = iscratch & 0xfffff;
218 this.payloadLength = bb.getShort();
219 this.nextHeader = bb.get();
220 this.hopLimit = bb.get();
221 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
222 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
223
224 IPacket payload;
225 if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
226 final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
227 .get(this.nextHeader);
228 try {
229 payload = clazz.newInstance();
230 } catch (final Exception e) {
231 throw new RuntimeException(
232 "Error parsing payload for IPv6 packet", e);
233 }
234 } else {
235 payload = new Data();
236 }
237 this.payload = payload.deserialize(data, bb.position(),
238 bb.limit() - bb.position());
239 this.payload.setParent(this);
240
241 return this;
242 }
243
244 /*
245 * (non-Javadoc)
246 *
247 * @see java.lang.Object#hashCode()
248 */
249 @Override
250 public int hashCode() {
251 final int prime = 2521;
252 int result = super.hashCode();
253 ByteBuffer bb;
254 bb = ByteBuffer.wrap(this.destinationAddress);
255 for (int i = 0; i < 4; i++) {
256 result = prime * result + bb.getInt();
257 }
258 result = prime * result + this.diffServ;
259 result = prime * result + this.flowLabel;
260 result = prime * result + this.hopLimit;
261 result = prime * result + this.nextHeader;
262 result = prime * result + this.payloadLength;
263 bb = ByteBuffer.wrap(this.sourceAddress);
264 for (int i = 0; i < 4; i++) {
265 result = prime * result + bb.getInt();
266 }
267 result = prime * result + this.version;
268 return result;
269 }
270
271 /*
272 * (non-Javadoc)
273 *
274 * @see java.lang.Object#equals(java.lang.Object)
275 */
276 @Override
277 public boolean equals(final Object obj) {
278 if (this == obj) {
279 return true;
280 }
281 if (!super.equals(obj)) {
282 return false;
283 }
284 if (!(obj instanceof IPv6)) {
285 return false;
286 }
287 final IPv6 other = (IPv6) obj;
288 if (!Arrays.equals(this.destinationAddress, other.destinationAddress)) {
289 return false;
290 }
291 if (this.diffServ != other.diffServ) {
292 return false;
293 }
294 if (this.flowLabel != other.flowLabel) {
295 return false;
296 }
297 if (this.hopLimit != other.hopLimit) {
298 return false;
299 }
300 if (this.nextHeader != other.nextHeader) {
301 return false;
302 }
303 if (this.payloadLength != other.payloadLength) {
304 return false;
305 }
306 if (!Arrays.equals(this.sourceAddress, other.sourceAddress)) {
307 return false;
308 }
309 return true;
310 }
311}