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