blob: 112e43eef5ff2d0c67e18baeddf4eb524eedfe12 [file] [log] [blame]
Charles M.C. Chan94f37372015-01-10 17:53:42 +08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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.Deserializer;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080022import org.onlab.packet.IPacket;
23import org.onlab.packet.IPv6;
24
25import java.nio.ByteBuffer;
26
Jian Li5fc14292015-12-04 11:30:46 -080027import static com.google.common.base.MoreObjects.toStringHelper;
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
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800146
147 /*
148 * (non-Javadoc)
149 *
150 * @see java.lang.Object#hashCode()
151 */
152 @Override
153 public int hashCode() {
154 final int prime = 5807;
155 int result = super.hashCode();
156 result = prime * result + this.nextHeader;
157 result = prime * result + this.fragmentOffset;
158 result = prime * result + this.moreFragment;
159 result = prime * result + this.identification;
160 return result;
161 }
162
163 /*
164 * (non-Javadoc)
165 *
166 * @see java.lang.Object#equals(java.lang.Object)
167 */
168 @Override
169 public boolean equals(final Object obj) {
170 if (this == obj) {
171 return true;
172 }
173 if (!super.equals(obj)) {
174 return false;
175 }
176 if (!(obj instanceof Fragment)) {
177 return false;
178 }
179 final Fragment other = (Fragment) obj;
180 if (this.nextHeader != other.nextHeader) {
181 return false;
182 }
183 if (this.fragmentOffset != other.fragmentOffset) {
184 return false;
185 }
186 if (this.moreFragment != other.moreFragment) {
187 return false;
188 }
189 if (this.identification != other.identification) {
190 return false;
191 }
192 return true;
193 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700194
195 /**
196 * Deserializer function for fragment headers.
197 *
198 * @return deserializer function
199 */
200 public static Deserializer<Fragment> deserializer() {
201 return (data, offset, length) -> {
202 checkInput(data, offset, length, HEADER_LENGTH);
203
204 Fragment fragment = new Fragment();
205
206 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
207 fragment.nextHeader = bb.get();
208 bb.get();
209 short sscratch = bb.getShort();
210 fragment.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
211 fragment.moreFragment = (byte) (sscratch & 0x1);
212 fragment.identification = bb.getInt();
213
214 Deserializer<? extends IPacket> deserializer;
215 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(fragment.nextHeader)) {
216 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(fragment.nextHeader);
217 } else {
218 deserializer = Data.deserializer();
219 }
220 fragment.payload = deserializer.deserialize(data, bb.position(),
221 bb.limit() - bb.position());
222 fragment.payload.setParent(fragment);
223
224 return fragment;
225 };
226 }
Jian Li5fc14292015-12-04 11:30:46 -0800227
228 @Override
229 public String toString() {
230 return toStringHelper(getClass())
231 .add("nextHeader", Byte.toString(nextHeader))
232 .add("fragmentOffset", Short.toString(fragmentOffset))
233 .add("moreFragment", Byte.toString(moreFragment))
234 .add("identification", Integer.toString(identification))
235 .toString();
236 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800237}