blob: 62e178129f3ba74981143c797a55e5cfba6f90e1 [file] [log] [blame]
Charles M.C. Chan94f37372015-01-10 17:53:42 +08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Charles M.C. Chan94f37372015-01-10 17:53:42 +08003 *
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;
Jonathan Hart2a655752015-04-07 16:46:33 -070021import org.onlab.packet.DeserializationException;
22import org.onlab.packet.Deserializer;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080023import org.onlab.packet.IPacket;
24import org.onlab.packet.IPv6;
25
26import java.nio.ByteBuffer;
27
Jian Li5fc14292015-12-04 11:30:46 -080028import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070029import static org.onlab.packet.PacketUtils.checkInput;
30
Charles M.C. Chan94f37372015-01-10 17:53:42 +080031/**
32 * Implements IPv6 fragment extension header format. (RFC 2460)
33 */
34public class Fragment extends BasePacket implements IExtensionHeader {
35 public static final byte HEADER_LENGTH = 8; // bytes
36
37 protected byte nextHeader;
38 protected short fragmentOffset;
39 protected byte moreFragment;
40 protected int identification;
41
42 @Override
43 public byte getNextHeader() {
44 return this.nextHeader;
45 }
46
47 @Override
48 public Fragment setNextHeader(final byte nextHeader) {
49 this.nextHeader = nextHeader;
50 return this;
51 }
52
53 /**
54 * Gets the fragment offset of this header.
55 *
56 * @return fragment offset
57 */
58 public short getFragmentOffset() {
59 return this.fragmentOffset;
60 }
61
62 /**
63 * Sets the fragment offset of this header.
64 *
65 * @param fragmentOffset the fragment offset to set
66 * @return this
67 */
68 public Fragment setFragmentOffset(final short fragmentOffset) {
69 this.fragmentOffset = fragmentOffset;
70 return this;
71 }
72
73 /**
74 * Gets the more fragment flag of this header.
75 *
76 * @return more fragment flag
77 */
78 public byte getMoreFragment() {
79 return this.moreFragment;
80 }
81
82 /**
83 * Sets the more fragment flag of this header.
84 *
85 * @param moreFragment the more fragment flag to set
86 * @return this
87 */
88 public Fragment setMoreFragment(final byte moreFragment) {
89 this.moreFragment = moreFragment;
90 return this;
91 }
92
93 /**
94 * Gets the identification of this header.
95 *
96 * @return identification
97 */
98 public int getIdentification() {
99 return this.identification;
100 }
101
102 /**
103 * Sets the identification of this header.
104 *
105 * @param identification the identification to set
106 * @return this
107 */
108 public Fragment setIdentification(final int identification) {
109 this.identification = identification;
110 return this;
111 }
112
113 @Override
114 public byte[] serialize() {
115 byte[] payloadData = null;
116 if (this.payload != null) {
117 this.payload.setParent(this);
118 payloadData = this.payload.serialize();
119 }
120
121 int payloadLength = 0;
122 if (payloadData != null) {
123 payloadLength = payloadData.length;
124 }
125
126 final byte[] data = new byte[HEADER_LENGTH + payloadLength];
127 final ByteBuffer bb = ByteBuffer.wrap(data);
128
129 bb.put(this.nextHeader);
130 bb.put((byte) 0);
131 bb.putShort((short) (
132 (this.fragmentOffset & 0x1fff) << 3 |
133 this.moreFragment & 0x1
134 ));
135 bb.putInt(this.identification);
136
137 if (payloadData != null) {
138 bb.put(payloadData);
139 }
140
141 if (this.parent != null && this.parent instanceof IExtensionHeader) {
142 ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_FRAG);
143 }
144 return data;
145 }
146
147 @Override
148 public IPacket deserialize(byte[] data, int offset, int length) {
149 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
150 this.nextHeader = bb.get();
151 bb.get();
152 short sscratch = bb.getShort();
153 this.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
154 this.moreFragment = (byte) (sscratch & 0x1);
155 this.identification = bb.getInt();
156
Jonathan Hart2a655752015-04-07 16:46:33 -0700157 Deserializer<? extends IPacket> deserializer;
158 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
159 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800160 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700161 deserializer = Data.deserializer();
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800162 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700163 try {
164 this.payload = deserializer.deserialize(data, bb.position(),
165 bb.limit() - bb.position());
166 this.payload.setParent(this);
167 } catch (DeserializationException e) {
168 return this;
169 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800170
171 return this;
172 }
173
174 /*
175 * (non-Javadoc)
176 *
177 * @see java.lang.Object#hashCode()
178 */
179 @Override
180 public int hashCode() {
181 final int prime = 5807;
182 int result = super.hashCode();
183 result = prime * result + this.nextHeader;
184 result = prime * result + this.fragmentOffset;
185 result = prime * result + this.moreFragment;
186 result = prime * result + this.identification;
187 return result;
188 }
189
190 /*
191 * (non-Javadoc)
192 *
193 * @see java.lang.Object#equals(java.lang.Object)
194 */
195 @Override
196 public boolean equals(final Object obj) {
197 if (this == obj) {
198 return true;
199 }
200 if (!super.equals(obj)) {
201 return false;
202 }
203 if (!(obj instanceof Fragment)) {
204 return false;
205 }
206 final Fragment other = (Fragment) obj;
207 if (this.nextHeader != other.nextHeader) {
208 return false;
209 }
210 if (this.fragmentOffset != other.fragmentOffset) {
211 return false;
212 }
213 if (this.moreFragment != other.moreFragment) {
214 return false;
215 }
216 if (this.identification != other.identification) {
217 return false;
218 }
219 return true;
220 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700221
222 /**
223 * Deserializer function for fragment headers.
224 *
225 * @return deserializer function
226 */
227 public static Deserializer<Fragment> deserializer() {
228 return (data, offset, length) -> {
229 checkInput(data, offset, length, HEADER_LENGTH);
230
231 Fragment fragment = new Fragment();
232
233 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
234 fragment.nextHeader = bb.get();
235 bb.get();
236 short sscratch = bb.getShort();
237 fragment.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
238 fragment.moreFragment = (byte) (sscratch & 0x1);
239 fragment.identification = bb.getInt();
240
241 Deserializer<? extends IPacket> deserializer;
242 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(fragment.nextHeader)) {
243 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(fragment.nextHeader);
244 } else {
245 deserializer = Data.deserializer();
246 }
247 fragment.payload = deserializer.deserialize(data, bb.position(),
248 bb.limit() - bb.position());
249 fragment.payload.setParent(fragment);
250
251 return fragment;
252 };
253 }
Jian Li5fc14292015-12-04 11:30:46 -0800254
255 @Override
256 public String toString() {
257 return toStringHelper(getClass())
258 .add("nextHeader", Byte.toString(nextHeader))
259 .add("fragmentOffset", Short.toString(fragmentOffset))
260 .add("moreFragment", Byte.toString(moreFragment))
261 .add("identification", Integer.toString(identification))
262 .toString();
263 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800264}