blob: 6a9f188d546ae05cb1490bdb20b4b1b6c7a278f7 [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.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;
27import java.util.Arrays;
28
Jian Li5fc14292015-12-04 11:30:46 -080029import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070030import static org.onlab.packet.PacketUtils.checkHeaderLength;
31import static org.onlab.packet.PacketUtils.checkInput;
32
Charles M.C. Chan94f37372015-01-10 17:53:42 +080033/**
34 * Base class for hop-by-hop options and destination options.
35 */
36public class BaseOptions extends BasePacket implements IExtensionHeader {
37 public static final byte FIXED_HEADER_LENGTH = 2; // bytes
38 public static final byte FIXED_OPTIONS_LENGTH = 6; // bytes
39 public static final byte LENGTH_UNIT = 8; // bytes per unit
40
41 protected byte nextHeader;
42 protected byte headerExtLength;
43 protected byte[] options;
44 protected byte type;
45
46 @Override
47 public byte getNextHeader() {
48 return this.nextHeader;
49 }
50
51 @Override
52 public BaseOptions setNextHeader(final byte nextHeader) {
53 this.nextHeader = nextHeader;
54 return this;
55 }
56
57 /**
58 * Gets the extension length of this header.
59 *
60 * @return header length
61 */
62 public byte getHeaderExtLength() {
63 return this.headerExtLength;
64 }
65
66 /**
67 * Sets the extension length of this header.
68 *
69 * @param headerExtLength the header length to set
70 * @return this
71 */
72 public BaseOptions setHeaderExtLength(final byte headerExtLength) {
73 this.headerExtLength = headerExtLength;
74 return this;
75 }
76
77 /**
78 * Gets the options.
79 *
80 * @return the options
81 */
82 public byte[] getOptions() {
83 return this.options;
84 }
85
86 /**
87 * Sets the options.
88 *
89 * @param options the options to set
90 * @return this
91 */
92 public BaseOptions setOptions(final byte[] options) {
93 this.options =
94 Arrays.copyOfRange(options, 0, options.length);
95 return this;
96 }
97
98 /**
99 * Gets the type of this option.
100 *
101 * @return the type
102 */
103 protected byte getType() {
104 return this.type;
105 }
106
107 /**
108 * Sets the type of this option.
109 * Must be either IPv6.PROTOCOL_HOPOPT or IPv6.PROTOCOL_DSTOPT
110 *
111 * @param type the type to set
112 * @return this
113 */
114 protected BaseOptions setType(final byte type) {
115 this.type = type;
116 return this;
117 }
118
119 @Override
120 public byte[] serialize() {
121 byte[] payloadData = null;
122 if (this.payload != null) {
123 this.payload.setParent(this);
124 payloadData = this.payload.serialize();
125 }
126
127 int headerLength = FIXED_HEADER_LENGTH + options.length;
128 int payloadLength = 0;
129 if (payloadData != null) {
130 payloadLength = payloadData.length;
131 }
132
133 final byte[] data = new byte[headerLength + payloadLength];
134 final ByteBuffer bb = ByteBuffer.wrap(data);
135
136 bb.put(this.nextHeader);
137 bb.put(this.headerExtLength);
138 bb.put(this.options, 0, options.length);
139
140 if (payloadData != null) {
141 bb.put(payloadData);
142 }
143
144 if (this.parent != null && this.parent instanceof IExtensionHeader) {
145 ((IExtensionHeader) this.parent).setNextHeader(this.type);
146 }
147 return data;
148 }
149
150 @Override
151 public IPacket deserialize(byte[] data, int offset, int length) {
152 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
153 this.nextHeader = bb.get();
154 this.headerExtLength = bb.get();
155 int optionLength =
156 FIXED_OPTIONS_LENGTH + LENGTH_UNIT * this.headerExtLength;
157 this.options = new byte[optionLength];
158 bb.get(this.options, 0, optionLength);
159
Jonathan Hart2a655752015-04-07 16:46:33 -0700160 Deserializer<? extends IPacket> deserializer;
161 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
162 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800163 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700164 deserializer = Data.deserializer();
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800165 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700166 try {
167 this.payload = deserializer.deserialize(data, bb.position(),
168 bb.limit() - bb.position());
169 this.payload.setParent(this);
170 } catch (DeserializationException e) {
171 return this;
172 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800173
174 return this;
175 }
176
177 /*
178 * (non-Javadoc)
179 *
180 * @see java.lang.Object#hashCode()
181 */
182 @Override
183 public int hashCode() {
184 final int prime = 5807;
185 int result = super.hashCode();
186 result = prime * result + this.nextHeader;
187 result = prime * result + this.headerExtLength;
188 for (byte b : this.options) {
189 result = prime * result + b;
190 }
191 return result;
192 }
193
194 /*
195 * (non-Javadoc)
196 *
197 * @see java.lang.Object#equals(java.lang.Object)
198 */
199 @Override
200 public boolean equals(final Object obj) {
201 if (this == obj) {
202 return true;
203 }
204 if (!super.equals(obj)) {
205 return false;
206 }
207 if (!(obj instanceof BaseOptions)) {
208 return false;
209 }
210 final BaseOptions other = (BaseOptions) obj;
211 if (this.nextHeader != other.nextHeader) {
212 return false;
213 }
214 if (this.headerExtLength != other.headerExtLength) {
215 return false;
216 }
217 if (!Arrays.equals(this.options, other.options)) {
218 return false;
219 }
220 if (this.type != other.type) {
221 return false;
222 }
223 return true;
224 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700225
226 /**
227 * Deserializer function for IPv6 base options.
228 *
229 * @return deserializer function
230 */
231 public static Deserializer<BaseOptions> deserializer() {
232 return (data, offset, length) -> {
233 checkInput(data, offset, length, FIXED_HEADER_LENGTH);
234
235 BaseOptions baseOptions = new BaseOptions();
236
237 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
238 baseOptions.nextHeader = bb.get();
239 baseOptions.headerExtLength = bb.get();
240 int optionLength =
241 FIXED_OPTIONS_LENGTH + LENGTH_UNIT * baseOptions.headerExtLength;
242
243 checkHeaderLength(bb.remaining(), optionLength);
244
245 baseOptions.options = new byte[optionLength];
246 bb.get(baseOptions.options, 0, optionLength);
247
248 Deserializer<? extends IPacket> deserializer;
249 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(baseOptions.nextHeader)) {
250 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(baseOptions.nextHeader);
251 } else {
252 deserializer = Data.deserializer();
253 }
254 baseOptions.payload = deserializer.deserialize(data, bb.position(),
255 bb.limit() - bb.position());
256 baseOptions.payload.setParent(baseOptions);
257
258 return baseOptions;
259 };
260 }
Jian Li5fc14292015-12-04 11:30:46 -0800261
262 @Override
263 public String toString() {
264 return toStringHelper(getClass())
265 .add("nextHeader", Byte.toString(nextHeader))
266 .add("headerExtLength", Byte.toString(headerExtLength))
267 .add("options", Arrays.toString(options))
268 .add("type", Short.toString(type))
269 .toString();
270 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800271}