blob: 5a0d4b4db020c7b9e39c33b225cdacbd16b16762 [file] [log] [blame]
Charles M.C. Chan94f37372015-01-10 17:53:42 +08001/*
2 * Copyright 2014-2015 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
17package org.onlab.packet.ipv6;
18
19import org.onlab.packet.BasePacket;
20import org.onlab.packet.Data;
21import org.onlab.packet.IPacket;
22import org.onlab.packet.IPv6;
23
24import java.nio.ByteBuffer;
25
26/**
27 * Implements IPv6 fragment extension header format. (RFC 2460)
28 */
29public class Fragment extends BasePacket implements IExtensionHeader {
30 public static final byte HEADER_LENGTH = 8; // bytes
31
32 protected byte nextHeader;
33 protected short fragmentOffset;
34 protected byte moreFragment;
35 protected int identification;
36
37 @Override
38 public byte getNextHeader() {
39 return this.nextHeader;
40 }
41
42 @Override
43 public Fragment setNextHeader(final byte nextHeader) {
44 this.nextHeader = nextHeader;
45 return this;
46 }
47
48 /**
49 * Gets the fragment offset of this header.
50 *
51 * @return fragment offset
52 */
53 public short getFragmentOffset() {
54 return this.fragmentOffset;
55 }
56
57 /**
58 * Sets the fragment offset of this header.
59 *
60 * @param fragmentOffset the fragment offset to set
61 * @return this
62 */
63 public Fragment setFragmentOffset(final short fragmentOffset) {
64 this.fragmentOffset = fragmentOffset;
65 return this;
66 }
67
68 /**
69 * Gets the more fragment flag of this header.
70 *
71 * @return more fragment flag
72 */
73 public byte getMoreFragment() {
74 return this.moreFragment;
75 }
76
77 /**
78 * Sets the more fragment flag of this header.
79 *
80 * @param moreFragment the more fragment flag to set
81 * @return this
82 */
83 public Fragment setMoreFragment(final byte moreFragment) {
84 this.moreFragment = moreFragment;
85 return this;
86 }
87
88 /**
89 * Gets the identification of this header.
90 *
91 * @return identification
92 */
93 public int getIdentification() {
94 return this.identification;
95 }
96
97 /**
98 * Sets the identification of this header.
99 *
100 * @param identification the identification to set
101 * @return this
102 */
103 public Fragment setIdentification(final int identification) {
104 this.identification = identification;
105 return this;
106 }
107
108 @Override
109 public byte[] serialize() {
110 byte[] payloadData = null;
111 if (this.payload != null) {
112 this.payload.setParent(this);
113 payloadData = this.payload.serialize();
114 }
115
116 int payloadLength = 0;
117 if (payloadData != null) {
118 payloadLength = payloadData.length;
119 }
120
121 final byte[] data = new byte[HEADER_LENGTH + payloadLength];
122 final ByteBuffer bb = ByteBuffer.wrap(data);
123
124 bb.put(this.nextHeader);
125 bb.put((byte) 0);
126 bb.putShort((short) (
127 (this.fragmentOffset & 0x1fff) << 3 |
128 this.moreFragment & 0x1
129 ));
130 bb.putInt(this.identification);
131
132 if (payloadData != null) {
133 bb.put(payloadData);
134 }
135
136 if (this.parent != null && this.parent instanceof IExtensionHeader) {
137 ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_FRAG);
138 }
139 return data;
140 }
141
142 @Override
143 public IPacket deserialize(byte[] data, int offset, int length) {
144 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
145 this.nextHeader = bb.get();
146 bb.get();
147 short sscratch = bb.getShort();
148 this.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
149 this.moreFragment = (byte) (sscratch & 0x1);
150 this.identification = bb.getInt();
151
152 IPacket payload;
153 if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
154 final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
155 .get(this.nextHeader);
156 try {
157 payload = clazz.newInstance();
158 } catch (final Exception e) {
159 throw new RuntimeException(
160 "Error parsing payload for Fragment packet", e);
161 }
162 } else {
163 payload = new Data();
164 }
165 this.payload = payload.deserialize(data, bb.position(),
166 bb.limit() - bb.position());
167 this.payload.setParent(this);
168
169 return this;
170 }
171
172 /*
173 * (non-Javadoc)
174 *
175 * @see java.lang.Object#hashCode()
176 */
177 @Override
178 public int hashCode() {
179 final int prime = 5807;
180 int result = super.hashCode();
181 result = prime * result + this.nextHeader;
182 result = prime * result + this.fragmentOffset;
183 result = prime * result + this.moreFragment;
184 result = prime * result + this.identification;
185 return result;
186 }
187
188 /*
189 * (non-Javadoc)
190 *
191 * @see java.lang.Object#equals(java.lang.Object)
192 */
193 @Override
194 public boolean equals(final Object obj) {
195 if (this == obj) {
196 return true;
197 }
198 if (!super.equals(obj)) {
199 return false;
200 }
201 if (!(obj instanceof Fragment)) {
202 return false;
203 }
204 final Fragment other = (Fragment) obj;
205 if (this.nextHeader != other.nextHeader) {
206 return false;
207 }
208 if (this.fragmentOffset != other.fragmentOffset) {
209 return false;
210 }
211 if (this.moreFragment != other.moreFragment) {
212 return false;
213 }
214 if (this.identification != other.identification) {
215 return false;
216 }
217 return true;
218 }
219}