blob: d6c49e1662070d4d2a93e18609be01e0da9a22d5 [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;
26import java.util.Arrays;
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.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
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800149 /*
150 * (non-Javadoc)
151 *
152 * @see java.lang.Object#hashCode()
153 */
154 @Override
155 public int hashCode() {
156 final int prime = 5807;
157 int result = super.hashCode();
158 result = prime * result + this.nextHeader;
159 result = prime * result + this.headerExtLength;
160 for (byte b : this.options) {
161 result = prime * result + b;
162 }
163 return result;
164 }
165
166 /*
167 * (non-Javadoc)
168 *
169 * @see java.lang.Object#equals(java.lang.Object)
170 */
171 @Override
172 public boolean equals(final Object obj) {
173 if (this == obj) {
174 return true;
175 }
176 if (!super.equals(obj)) {
177 return false;
178 }
179 if (!(obj instanceof BaseOptions)) {
180 return false;
181 }
182 final BaseOptions other = (BaseOptions) obj;
183 if (this.nextHeader != other.nextHeader) {
184 return false;
185 }
186 if (this.headerExtLength != other.headerExtLength) {
187 return false;
188 }
189 if (!Arrays.equals(this.options, other.options)) {
190 return false;
191 }
192 if (this.type != other.type) {
193 return false;
194 }
195 return true;
196 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700197
198 /**
199 * Deserializer function for IPv6 base options.
200 *
201 * @return deserializer function
202 */
203 public static Deserializer<BaseOptions> deserializer() {
204 return (data, offset, length) -> {
205 checkInput(data, offset, length, FIXED_HEADER_LENGTH);
206
207 BaseOptions baseOptions = new BaseOptions();
208
209 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
210 baseOptions.nextHeader = bb.get();
211 baseOptions.headerExtLength = bb.get();
212 int optionLength =
213 FIXED_OPTIONS_LENGTH + LENGTH_UNIT * baseOptions.headerExtLength;
214
215 checkHeaderLength(bb.remaining(), optionLength);
216
217 baseOptions.options = new byte[optionLength];
218 bb.get(baseOptions.options, 0, optionLength);
219
220 Deserializer<? extends IPacket> deserializer;
221 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(baseOptions.nextHeader)) {
222 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(baseOptions.nextHeader);
223 } else {
224 deserializer = Data.deserializer();
225 }
226 baseOptions.payload = deserializer.deserialize(data, bb.position(),
227 bb.limit() - bb.position());
228 baseOptions.payload.setParent(baseOptions);
229
230 return baseOptions;
231 };
232 }
Jian Li5fc14292015-12-04 11:30:46 -0800233
234 @Override
235 public String toString() {
236 return toStringHelper(getClass())
237 .add("nextHeader", Byte.toString(nextHeader))
238 .add("headerExtLength", Byte.toString(headerExtLength))
239 .add("options", Arrays.toString(options))
240 .add("type", Short.toString(type))
241 .toString();
242 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800243}