blob: ed7d9dcc986a2b87ff27f2fc419b6122fabf82c2 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
Ray Milkey269ffb92014-04-03 14:43:30 -07002 * Copyright 2011, Big Switch Networks, Inc.
3 * Originally created by David Erickson, Stanford University
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain
7 * a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 **/
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080017
18/**
Ray Milkey269ffb92014-04-03 14:43:30 -070019 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080020 */
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070021package net.onrc.onos.core.packet;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080022
23import java.nio.ByteBuffer;
24import java.util.Arrays;
25import java.util.Collection;
26import java.util.HashMap;
27import java.util.Map;
28
Pavlin Radoslavovc9bacee2014-04-11 19:02:17 -070029import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
30
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080031/**
32 * @author David Erickson (daviderickson@cs.stanford.edu)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080033 */
34public class IPv4 extends BasePacket {
Ray Milkey269ffb92014-04-03 14:43:30 -070035 public static final int ADDRESS_LENGTH = 4;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080036 public static final byte PROTOCOL_ICMP = 0x1;
37 public static final byte PROTOCOL_TCP = 0x6;
38 public static final byte PROTOCOL_UDP = 0x11;
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070039 public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080040
41 static {
Pavlin Radoslavov608fac32014-04-09 12:40:24 -070042 PROTOCOL_CLASS_MAP = new HashMap<Byte, Class<? extends IPacket>>();
43 PROTOCOL_CLASS_MAP.put(PROTOCOL_ICMP, ICMP.class);
44 PROTOCOL_CLASS_MAP.put(PROTOCOL_TCP, TCP.class);
45 PROTOCOL_CLASS_MAP.put(PROTOCOL_UDP, UDP.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080046 }
47
48 protected byte version;
49 protected byte headerLength;
50 protected byte diffServ;
51 protected short totalLength;
52 protected short identification;
53 protected byte flags;
54 protected short fragmentOffset;
55 protected byte ttl;
56 protected byte protocol;
57 protected short checksum;
58 protected int sourceAddress;
59 protected int destinationAddress;
60 protected byte[] options;
61
62 protected boolean isTruncated;
63
64 /**
65 * Default constructor that sets the version to 4.
66 */
67 public IPv4() {
68 super();
69 this.version = 4;
70 isTruncated = false;
71 }
72
73 /**
74 * @return the version
75 */
76 public byte getVersion() {
77 return version;
78 }
79
80 /**
81 * @param version the version to set
82 */
83 public IPv4 setVersion(byte version) {
84 this.version = version;
85 return this;
86 }
87
88 /**
89 * @return the headerLength
90 */
91 public byte getHeaderLength() {
92 return headerLength;
93 }
94
95 /**
96 * @return the diffServ
97 */
98 public byte getDiffServ() {
99 return diffServ;
100 }
101
102 /**
103 * @param diffServ the diffServ to set
104 */
105 public IPv4 setDiffServ(byte diffServ) {
106 this.diffServ = diffServ;
107 return this;
108 }
109
110 /**
111 * @return the totalLength
112 */
113 public short getTotalLength() {
114 return totalLength;
115 }
116
117 /**
118 * @return the identification
119 */
120 public short getIdentification() {
121 return identification;
122 }
123
124 public boolean isTruncated() {
125 return isTruncated;
126 }
127
128 public void setTruncated(boolean isTruncated) {
129 this.isTruncated = isTruncated;
130 }
131
132 /**
133 * @param identification the identification to set
134 */
135 public IPv4 setIdentification(short identification) {
136 this.identification = identification;
137 return this;
138 }
139
140 /**
141 * @return the flags
142 */
143 public byte getFlags() {
144 return flags;
145 }
146
147 /**
148 * @param flags the flags to set
149 */
150 public IPv4 setFlags(byte flags) {
151 this.flags = flags;
152 return this;
153 }
154
155 /**
156 * @return the fragmentOffset
157 */
158 public short getFragmentOffset() {
159 return fragmentOffset;
160 }
161
162 /**
163 * @param fragmentOffset the fragmentOffset to set
164 */
165 public IPv4 setFragmentOffset(short fragmentOffset) {
166 this.fragmentOffset = fragmentOffset;
167 return this;
168 }
169
170 /**
171 * @return the ttl
172 */
173 public byte getTtl() {
174 return ttl;
175 }
176
177 /**
178 * @param ttl the ttl to set
179 */
180 public IPv4 setTtl(byte ttl) {
181 this.ttl = ttl;
182 return this;
183 }
184
185 /**
186 * @return the protocol
187 */
188 public byte getProtocol() {
189 return protocol;
190 }
191
192 /**
193 * @param protocol the protocol to set
194 */
195 public IPv4 setProtocol(byte protocol) {
196 this.protocol = protocol;
197 return this;
198 }
199
200 /**
201 * @return the checksum
202 */
203 public short getChecksum() {
204 return checksum;
205 }
206
207 /**
208 * @param checksum the checksum to set
209 */
210 public IPv4 setChecksum(short checksum) {
211 this.checksum = checksum;
212 return this;
213 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700214
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800215 @Override
216 public void resetChecksum() {
217 this.checksum = 0;
218 super.resetChecksum();
219 }
220
221 /**
222 * @return the sourceAddress
223 */
224 public int getSourceAddress() {
225 return sourceAddress;
226 }
227
228 /**
229 * @param sourceAddress the sourceAddress to set
230 */
231 public IPv4 setSourceAddress(int sourceAddress) {
232 this.sourceAddress = sourceAddress;
233 return this;
234 }
235
236 /**
237 * @param sourceAddress the sourceAddress to set
238 */
239 public IPv4 setSourceAddress(String sourceAddress) {
240 this.sourceAddress = IPv4.toIPv4Address(sourceAddress);
241 return this;
242 }
243
244 /**
245 * @return the destinationAddress
246 */
247 public int getDestinationAddress() {
248 return destinationAddress;
249 }
250
251 /**
252 * @param destinationAddress the destinationAddress to set
253 */
254 public IPv4 setDestinationAddress(int destinationAddress) {
255 this.destinationAddress = destinationAddress;
256 return this;
257 }
258
259 /**
260 * @param destinationAddress the destinationAddress to set
261 */
262 public IPv4 setDestinationAddress(String destinationAddress) {
263 this.destinationAddress = IPv4.toIPv4Address(destinationAddress);
264 return this;
265 }
266
267 /**
268 * @return the options
269 */
Pavlin Radoslavovc9bacee2014-04-11 19:02:17 -0700270 @SuppressFBWarnings(value = "EI_EXPOSE_REP",
271 justification = "TODO: Return a copy of the object?")
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800272 public byte[] getOptions() {
273 return options;
274 }
275
276 /**
277 * @param options the options to set
278 */
Pavlin Radoslavovc9bacee2014-04-11 19:02:17 -0700279 @SuppressFBWarnings(value = "EI_EXPOSE_REP2",
280 justification = "TODO: Store a copy of the object?")
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800281 public IPv4 setOptions(byte[] options) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700282 if (options != null && (options.length % 4) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800283 throw new IllegalArgumentException(
284 "Options length must be a multiple of 4");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700285 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800286 this.options = options;
287 return this;
288 }
289
290 /**
291 * Serializes the packet. Will compute and set the following fields if they
292 * are set to specific values at the time serialize is called:
Ray Milkey269ffb92014-04-03 14:43:30 -0700293 * -checksum : 0
294 * -headerLength : 0
295 * -totalLength : 0
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800296 */
297 public byte[] serialize() {
298 byte[] payloadData = null;
299 if (payload != null) {
300 payload.setParent(this);
301 payloadData = payload.serialize();
302 }
303
304 int optionsLength = 0;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700305 if (this.options != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800306 optionsLength = this.options.length / 4;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700307 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800308 this.headerLength = (byte) (5 + optionsLength);
309
310 this.totalLength = (short) (this.headerLength * 4 + ((payloadData == null) ? 0
311 : payloadData.length));
312
313 byte[] data = new byte[this.totalLength];
314 ByteBuffer bb = ByteBuffer.wrap(data);
315
316 bb.put((byte) (((this.version & 0xf) << 4) | (this.headerLength & 0xf)));
317 bb.put(this.diffServ);
318 bb.putShort(this.totalLength);
319 bb.putShort(this.identification);
320 bb.putShort((short) (((this.flags & 0x7) << 13) | (this.fragmentOffset & 0x1fff)));
321 bb.put(this.ttl);
322 bb.put(this.protocol);
323 bb.putShort(this.checksum);
324 bb.putInt(this.sourceAddress);
325 bb.putInt(this.destinationAddress);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700326 if (this.options != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800327 bb.put(this.options);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700328 }
329 if (payloadData != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800330 bb.put(payloadData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700331 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800332
333 // compute checksum if needed
334 if (this.checksum == 0) {
335 bb.rewind();
336 int accumulation = 0;
337 for (int i = 0; i < this.headerLength * 2; ++i) {
338 accumulation += 0xffff & bb.getShort();
339 }
340 accumulation = ((accumulation >> 16) & 0xffff)
341 + (accumulation & 0xffff);
342 this.checksum = (short) (~accumulation & 0xffff);
343 bb.putShort(10, this.checksum);
344 }
345 return data;
346 }
347
348 @Override
349 public IPacket deserialize(byte[] data, int offset, int length) {
350 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
351 short sscratch;
352
353 this.version = bb.get();
354 this.headerLength = (byte) (this.version & 0xf);
355 this.version = (byte) ((this.version >> 4) & 0xf);
356 this.diffServ = bb.get();
357 this.totalLength = bb.getShort();
358 this.identification = bb.getShort();
359 sscratch = bb.getShort();
360 this.flags = (byte) ((sscratch >> 13) & 0x7);
361 this.fragmentOffset = (short) (sscratch & 0x1fff);
362 this.ttl = bb.get();
363 this.protocol = bb.get();
364 this.checksum = bb.getShort();
365 this.sourceAddress = bb.getInt();
366 this.destinationAddress = bb.getInt();
367
368 if (this.headerLength > 5) {
369 int optionsLength = (this.headerLength - 5) * 4;
370 this.options = new byte[optionsLength];
371 bb.get(this.options);
372 }
373
374 IPacket payload;
Pavlin Radoslavov608fac32014-04-09 12:40:24 -0700375 if (IPv4.PROTOCOL_CLASS_MAP.containsKey(this.protocol)) {
376 Class<? extends IPacket> clazz = IPv4.PROTOCOL_CLASS_MAP.get(this.protocol);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800377 try {
378 payload = clazz.newInstance();
379 } catch (Exception e) {
380 throw new RuntimeException("Error parsing payload for IPv4 packet", e);
381 }
382 } else {
383 payload = new Data();
384 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700385 this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800386 this.payload.setParent(this);
387
Ray Milkeyb29e6262014-04-09 16:02:14 -0700388 if (this.totalLength != length) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800389 this.isTruncated = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700390 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800391 this.isTruncated = false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700392 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800393
394 return this;
395 }
396
397 /**
398 * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
399 * returns the corresponding 32 bit integer.
Ray Milkey269ffb92014-04-03 14:43:30 -0700400 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800401 * @param ipAddress
402 * @return
403 */
404 public static int toIPv4Address(String ipAddress) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700405 if (ipAddress == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800406 throw new IllegalArgumentException("Specified IPv4 address must" +
Ray Milkey269ffb92014-04-03 14:43:30 -0700407 "contain 4 sets of numerical digits separated by periods");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700408 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800409 String[] octets = ipAddress.split("\\.");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700410 if (octets.length != 4) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800411 throw new IllegalArgumentException("Specified IPv4 address must" +
Ray Milkey269ffb92014-04-03 14:43:30 -0700412 "contain 4 sets of numerical digits separated by periods");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700413 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800414
415 int result = 0;
416 for (int i = 0; i < 4; ++i) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700417 result |= Integer.valueOf(octets[i]) << ((3 - i) * 8);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800418 }
419 return result;
420 }
421
422 /**
423 * Accepts an IPv4 address in a byte array and returns the corresponding
424 * 32-bit integer value.
Ray Milkey269ffb92014-04-03 14:43:30 -0700425 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800426 * @param ipAddress
427 * @return
428 */
429 public static int toIPv4Address(byte[] ipAddress) {
430 int ip = 0;
431 for (int i = 0; i < 4; i++) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700432 int t = (ipAddress[i] & 0xff) << ((3 - i) * 8);
433 ip |= t;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800434 }
435 return ip;
436 }
437
438 /**
439 * Accepts an IPv4 address and returns of string of the form xxx.xxx.xxx.xxx
Ray Milkeyb41100a2014-04-10 10:42:15 -0700440 * ie 192.168.0.1.
Ray Milkey269ffb92014-04-03 14:43:30 -0700441 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800442 * @param ipAddress
443 * @return
444 */
445 public static String fromIPv4Address(int ipAddress) {
446 StringBuffer sb = new StringBuffer();
447 int result = 0;
448 for (int i = 0; i < 4; ++i) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700449 result = (ipAddress >> ((3 - i) * 8)) & 0xff;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800450 sb.append(Integer.valueOf(result).toString());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700451 if (i != 3) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800452 sb.append(".");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700453 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800454 }
455 return sb.toString();
456 }
457
458 /**
459 * Accepts a collection of IPv4 addresses as integers and returns a single
460 * String useful in toString method's containing collections of IP
461 * addresses.
Ray Milkey269ffb92014-04-03 14:43:30 -0700462 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800463 * @param ipAddresses collection
464 * @return
465 */
466 public static String fromIPv4AddressCollection(Collection<Integer> ipAddresses) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700467 if (ipAddresses == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800468 return "null";
Ray Milkeyb29e6262014-04-09 16:02:14 -0700469 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800470 StringBuffer sb = new StringBuffer();
471 sb.append("[");
472 for (Integer ip : ipAddresses) {
473 sb.append(fromIPv4Address(ip));
474 sb.append(",");
475 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700476 sb.replace(sb.length() - 1, sb.length(), "]");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800477 return sb.toString();
478 }
479
480 /**
481 * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
482 * returns the corresponding byte array.
Ray Milkey269ffb92014-04-03 14:43:30 -0700483 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800484 * @param ipAddress The IP address in the form xx.xxx.xxx.xxx.
485 * @return The IP address separated into bytes
486 */
487 public static byte[] toIPv4AddressBytes(String ipAddress) {
488 String[] octets = ipAddress.split("\\.");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700489 if (octets.length != 4) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800490 throw new IllegalArgumentException("Specified IPv4 address must" +
Ray Milkey269ffb92014-04-03 14:43:30 -0700491 "contain 4 sets of numerical digits separated by periods");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700492 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800493
494 byte[] result = new byte[4];
495 for (int i = 0; i < 4; ++i) {
496 result[i] = Integer.valueOf(octets[i]).byteValue();
497 }
498 return result;
499 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700500
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800501 /**
502 * Accepts an IPv4 address in the form of an integer and
503 * returns the corresponding byte array.
Ray Milkey269ffb92014-04-03 14:43:30 -0700504 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800505 * @param ipAddress The IP address as an integer.
506 * @return The IP address separated into bytes.
507 */
508 public static byte[] toIPv4AddressBytes(int ipAddress) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700509 return new byte[]{
510 (byte) (ipAddress >>> 24),
511 (byte) (ipAddress >>> 16),
512 (byte) (ipAddress >>> 8),
513 (byte) ipAddress};
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800514 }
515
516 /* (non-Javadoc)
517 * @see java.lang.Object#hashCode()
518 */
519 @Override
520 public int hashCode() {
521 final int prime = 2521;
522 int result = super.hashCode();
523 result = prime * result + checksum;
524 result = prime * result + destinationAddress;
525 result = prime * result + diffServ;
526 result = prime * result + flags;
527 result = prime * result + fragmentOffset;
528 result = prime * result + headerLength;
529 result = prime * result + identification;
530 result = prime * result + Arrays.hashCode(options);
531 result = prime * result + protocol;
532 result = prime * result + sourceAddress;
533 result = prime * result + totalLength;
534 result = prime * result + ttl;
535 result = prime * result + version;
536 return result;
537 }
538
539 /* (non-Javadoc)
540 * @see java.lang.Object#equals(java.lang.Object)
541 */
542 @Override
543 public boolean equals(Object obj) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700544 if (this == obj) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800545 return true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700546 }
547 if (!super.equals(obj)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800548 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700549 }
550 if (!(obj instanceof IPv4)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800551 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700552 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800553 IPv4 other = (IPv4) obj;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700554 if (checksum != other.checksum) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800555 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700556 }
557 if (destinationAddress != other.destinationAddress) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800558 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700559 }
560 if (diffServ != other.diffServ) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800561 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700562 }
563 if (flags != other.flags) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800564 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700565 }
566 if (fragmentOffset != other.fragmentOffset) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800567 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700568 }
569 if (headerLength != other.headerLength) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800570 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700571 }
572 if (identification != other.identification) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800573 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700574 }
575 if (!Arrays.equals(options, other.options)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800576 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700577 }
578 if (protocol != other.protocol) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800579 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700580 }
581 if (sourceAddress != other.sourceAddress) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800582 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700583 }
584 if (totalLength != other.totalLength) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800585 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700586 }
587 if (ttl != other.ttl) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800588 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700589 }
590 if (version != other.version) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800591 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700592 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800593 return true;
594 }
595}