blob: 6fd81cf7d03c97710d7b2e4454369ab38d2f00cf [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;
21import org.onlab.packet.IPacket;
22import org.onlab.packet.IPv6;
23
24import java.nio.ByteBuffer;
25import java.util.Arrays;
26
27/**
28 * Base class for hop-by-hop options and destination options.
29 */
30public class BaseOptions extends BasePacket implements IExtensionHeader {
31 public static final byte FIXED_HEADER_LENGTH = 2; // bytes
32 public static final byte FIXED_OPTIONS_LENGTH = 6; // bytes
33 public static final byte LENGTH_UNIT = 8; // bytes per unit
34
35 protected byte nextHeader;
36 protected byte headerExtLength;
37 protected byte[] options;
38 protected byte type;
39
40 @Override
41 public byte getNextHeader() {
42 return this.nextHeader;
43 }
44
45 @Override
46 public BaseOptions setNextHeader(final byte nextHeader) {
47 this.nextHeader = nextHeader;
48 return this;
49 }
50
51 /**
52 * Gets the extension length of this header.
53 *
54 * @return header length
55 */
56 public byte getHeaderExtLength() {
57 return this.headerExtLength;
58 }
59
60 /**
61 * Sets the extension length of this header.
62 *
63 * @param headerExtLength the header length to set
64 * @return this
65 */
66 public BaseOptions setHeaderExtLength(final byte headerExtLength) {
67 this.headerExtLength = headerExtLength;
68 return this;
69 }
70
71 /**
72 * Gets the options.
73 *
74 * @return the options
75 */
76 public byte[] getOptions() {
77 return this.options;
78 }
79
80 /**
81 * Sets the options.
82 *
83 * @param options the options to set
84 * @return this
85 */
86 public BaseOptions setOptions(final byte[] options) {
87 this.options =
88 Arrays.copyOfRange(options, 0, options.length);
89 return this;
90 }
91
92 /**
93 * Gets the type of this option.
94 *
95 * @return the type
96 */
97 protected byte getType() {
98 return this.type;
99 }
100
101 /**
102 * Sets the type of this option.
103 * Must be either IPv6.PROTOCOL_HOPOPT or IPv6.PROTOCOL_DSTOPT
104 *
105 * @param type the type to set
106 * @return this
107 */
108 protected BaseOptions setType(final byte type) {
109 this.type = type;
110 return this;
111 }
112
113 @Override
114 public byte[] serialize() {
115 byte[] payloadData = null;
116 if (this.payload != null) {
117 this.payload.setParent(this);
118 payloadData = this.payload.serialize();
119 }
120
121 int headerLength = FIXED_HEADER_LENGTH + options.length;
122 int payloadLength = 0;
123 if (payloadData != null) {
124 payloadLength = payloadData.length;
125 }
126
127 final byte[] data = new byte[headerLength + payloadLength];
128 final ByteBuffer bb = ByteBuffer.wrap(data);
129
130 bb.put(this.nextHeader);
131 bb.put(this.headerExtLength);
132 bb.put(this.options, 0, options.length);
133
134 if (payloadData != null) {
135 bb.put(payloadData);
136 }
137
138 if (this.parent != null && this.parent instanceof IExtensionHeader) {
139 ((IExtensionHeader) this.parent).setNextHeader(this.type);
140 }
141 return data;
142 }
143
144 @Override
145 public IPacket deserialize(byte[] data, int offset, int length) {
146 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
147 this.nextHeader = bb.get();
148 this.headerExtLength = bb.get();
149 int optionLength =
150 FIXED_OPTIONS_LENGTH + LENGTH_UNIT * this.headerExtLength;
151 this.options = new byte[optionLength];
152 bb.get(this.options, 0, optionLength);
153
154 IPacket payload;
155 if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
156 final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
157 .get(this.nextHeader);
158 try {
159 payload = clazz.newInstance();
160 } catch (final Exception e) {
161 throw new RuntimeException(
162 "Error parsing payload for BaseOptions packet", e);
163 }
164 } else {
165 payload = new Data();
166 }
167 this.payload = payload.deserialize(data, bb.position(),
168 bb.limit() - bb.position());
169 this.payload.setParent(this);
170
171 return this;
172 }
173
174 /*
175 * (non-Javadoc)
176 *
177 * @see java.lang.Object#hashCode()
178 */
179 @Override
180 public int hashCode() {
181 final int prime = 5807;
182 int result = super.hashCode();
183 result = prime * result + this.nextHeader;
184 result = prime * result + this.headerExtLength;
185 for (byte b : this.options) {
186 result = prime * result + b;
187 }
188 return result;
189 }
190
191 /*
192 * (non-Javadoc)
193 *
194 * @see java.lang.Object#equals(java.lang.Object)
195 */
196 @Override
197 public boolean equals(final Object obj) {
198 if (this == obj) {
199 return true;
200 }
201 if (!super.equals(obj)) {
202 return false;
203 }
204 if (!(obj instanceof BaseOptions)) {
205 return false;
206 }
207 final BaseOptions other = (BaseOptions) obj;
208 if (this.nextHeader != other.nextHeader) {
209 return false;
210 }
211 if (this.headerExtLength != other.headerExtLength) {
212 return false;
213 }
214 if (!Arrays.equals(this.options, other.options)) {
215 return false;
216 }
217 if (this.type != other.type) {
218 return false;
219 }
220 return true;
221 }
222}