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