blob: b8b58bc4ac9e71a8944a7e1e4540cb608b85511b [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
alshabibc4901cd2014-09-05 16:50:40 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
alshabibc4901cd2014-09-05 16:50:40 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
alshabibc4901cd2014-09-05 16:50:40 -070016
alshabibc4901cd2014-09-05 16:50:40 -070017package org.onlab.packet;
18
19import java.nio.ByteBuffer;
20import java.util.Arrays;
21import java.util.Collection;
22import java.util.HashMap;
23import java.util.Map;
24
Jian Li5fc14292015-12-04 11:30:46 -080025import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070026import static org.onlab.packet.PacketUtils.*;
27
alshabibc4901cd2014-09-05 16:50:40 -070028/**
Jian Li5fc14292015-12-04 11:30:46 -080029 * Implements IPv4 packet format.
alshabibc4901cd2014-09-05 16:50:40 -070030 */
Jian Li1270aea2016-09-15 13:32:24 +090031public class IPv4 extends IP {
alshabibc4901cd2014-09-05 16:50:40 -070032 public static final byte PROTOCOL_ICMP = 0x1;
Rusty Eddy1da61a22015-09-01 00:48:58 +000033 public static final byte PROTOCOL_IGMP = 0x2;
alshabibc4901cd2014-09-05 16:50:40 -070034 public static final byte PROTOCOL_TCP = 0x6;
35 public static final byte PROTOCOL_UDP = 0x11;
Rusty Eddy80f12522015-09-03 22:42:02 +000036 public static final byte PROTOCOL_PIM = 0x67;
Jonathan Hart2a655752015-04-07 16:46:33 -070037 public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
Ray Milkey241b96a2014-11-17 13:08:20 -080038 new HashMap<>();
alshabibc4901cd2014-09-05 16:50:40 -070039
40 static {
Jonathan Hart2a655752015-04-07 16:46:33 -070041 IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_ICMP, ICMP.deserializer());
Rusty Eddy1da61a22015-09-01 00:48:58 +000042 IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_IGMP, IGMP.deserializer());
Jonathan Hart2a655752015-04-07 16:46:33 -070043 IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_TCP, TCP.deserializer());
44 IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_UDP, UDP.deserializer());
Rusty Eddy80f12522015-09-03 22:42:02 +000045 IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_PIM, PIM.deserializer());
alshabibc4901cd2014-09-05 16:50:40 -070046 }
47
Pavlin Radoslavovbf23c552015-02-20 14:20:30 -080048 private static final byte DSCP_MASK = 0x3f;
49 private static final byte DSCP_OFFSET = 2;
50 private static final byte ECN_MASK = 0x3;
51
Jonathan Hart2a655752015-04-07 16:46:33 -070052 private static final short HEADER_LENGTH = 20;
53
alshabibc4901cd2014-09-05 16:50:40 -070054 protected byte version;
55 protected byte headerLength;
56 protected byte diffServ;
57 protected short totalLength;
58 protected short identification;
59 protected byte flags;
60 protected short fragmentOffset;
61 protected byte ttl;
62 protected byte protocol;
63 protected short checksum;
64 protected int sourceAddress;
65 protected int destinationAddress;
66 protected byte[] options;
67
68 protected boolean isTruncated;
69
70 /**
71 * Default constructor that sets the version to 4.
72 */
73 public IPv4() {
74 super();
75 this.version = 4;
76 this.isTruncated = false;
77 }
78
Jian Li1270aea2016-09-15 13:32:24 +090079 @Override
alshabibc4901cd2014-09-05 16:50:40 -070080 public byte getVersion() {
81 return this.version;
82 }
83
Jian Li1270aea2016-09-15 13:32:24 +090084 @Override
alshabibc4901cd2014-09-05 16:50:40 -070085 public IPv4 setVersion(final byte version) {
86 this.version = version;
87 return this;
88 }
89
90 /**
91 * @return the headerLength
92 */
93 public byte getHeaderLength() {
94 return this.headerLength;
95 }
96
97 /**
Pavlin Radoslavovbf23c552015-02-20 14:20:30 -080098 * Gets the DSCP value (6 bits).
99 *
100 * @return the DSCP value (6 bits)
101 */
102 public byte getDscp() {
103 return (byte) ((this.diffServ >>> DSCP_OFFSET) & DSCP_MASK);
104 }
105
106 /**
107 * Sets the DSCP value (6 bits).
108 *
109 * @param dscp the DSCP value (6 bits)
110 * @return this
111 */
112 public IPv4 setDscp(byte dscp) {
113 this.diffServ &= ~(DSCP_MASK << DSCP_OFFSET);
114 this.diffServ |= (dscp & DSCP_MASK) << DSCP_OFFSET;
115 return this;
116 }
117
118 /**
119 * Gets the ECN value (2 bits).
120 *
121 * @return the ECN value (2 bits)
122 */
123 public byte getEcn() {
124 return (byte) (this.diffServ & ECN_MASK);
125 }
126
127 /**
128 * Sets the ECN value (2 bits).
129 *
130 * @param ecn the ECN value (2 bits)
131 * @return this
132 */
133 public IPv4 setEcn(byte ecn) {
134 this.diffServ &= ~ECN_MASK;
135 this.diffServ |= (ecn & ECN_MASK);
136 return this;
137 }
138
139 /**
140 * Gets the DiffServ octet (including the DSCP and ECN bits).
141 *
142 * @return the diffServ octet (including the DSCP and ECN bits)
alshabibc4901cd2014-09-05 16:50:40 -0700143 */
144 public byte getDiffServ() {
145 return this.diffServ;
146 }
147
148 /**
Pavlin Radoslavovbf23c552015-02-20 14:20:30 -0800149 * Sets the DiffServ octet (including the DSCP and ECN bits).
150 *
151 * @param diffServ the diffServ octet to set (including the DSCP and ECN
152 * bits)
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800153 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700154 */
155 public IPv4 setDiffServ(final byte diffServ) {
156 this.diffServ = diffServ;
157 return this;
158 }
159
160 /**
161 * @return the totalLength
162 */
163 public short getTotalLength() {
164 return this.totalLength;
165 }
166
167 /**
168 * @return the identification
169 */
170 public short getIdentification() {
171 return this.identification;
172 }
173
174 public boolean isTruncated() {
175 return this.isTruncated;
176 }
177
178 public void setTruncated(final boolean isTruncated) {
179 this.isTruncated = isTruncated;
180 }
181
182 /**
183 * @param identification
184 * the identification to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800185 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700186 */
187 public IPv4 setIdentification(final short identification) {
188 this.identification = identification;
189 return this;
190 }
191
192 /**
193 * @return the flags
194 */
195 public byte getFlags() {
196 return this.flags;
197 }
198
199 /**
200 * @param flags
201 * the flags to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800202 * @return this
203s */
alshabibc4901cd2014-09-05 16:50:40 -0700204 public IPv4 setFlags(final byte flags) {
205 this.flags = flags;
206 return this;
207 }
208
209 /**
210 * @return the fragmentOffset
211 */
212 public short getFragmentOffset() {
213 return this.fragmentOffset;
214 }
215
216 /**
217 * @param fragmentOffset
218 * the fragmentOffset to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800219 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700220 */
221 public IPv4 setFragmentOffset(final short fragmentOffset) {
222 this.fragmentOffset = fragmentOffset;
223 return this;
224 }
225
226 /**
227 * @return the ttl
228 */
229 public byte getTtl() {
230 return this.ttl;
231 }
232
233 /**
234 * @param ttl
235 * the ttl to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800236 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700237 */
238 public IPv4 setTtl(final byte ttl) {
239 this.ttl = ttl;
240 return this;
241 }
242
243 /**
244 * @return the protocol
245 */
246 public byte getProtocol() {
247 return this.protocol;
248 }
249
250 /**
251 * @param protocol
252 * the protocol to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800253 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700254 */
255 public IPv4 setProtocol(final byte protocol) {
256 this.protocol = protocol;
257 return this;
258 }
259
260 /**
261 * @return the checksum
262 */
263 public short getChecksum() {
264 return this.checksum;
265 }
266
267 /**
268 * @param checksum
269 * the checksum to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800270 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700271 */
272 public IPv4 setChecksum(final short checksum) {
273 this.checksum = checksum;
274 return this;
275 }
276
277 @Override
278 public void resetChecksum() {
279 this.checksum = 0;
280 super.resetChecksum();
281 }
282
283 /**
284 * @return the sourceAddress
285 */
286 public int getSourceAddress() {
287 return this.sourceAddress;
288 }
289
290 /**
291 * @param sourceAddress
292 * the sourceAddress to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800293 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700294 */
295 public IPv4 setSourceAddress(final int sourceAddress) {
296 this.sourceAddress = sourceAddress;
297 return this;
298 }
299
300 /**
301 * @param sourceAddress
302 * the sourceAddress to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800303 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700304 */
305 public IPv4 setSourceAddress(final String sourceAddress) {
306 this.sourceAddress = IPv4.toIPv4Address(sourceAddress);
307 return this;
308 }
309
310 /**
311 * @return the destinationAddress
312 */
313 public int getDestinationAddress() {
314 return this.destinationAddress;
315 }
316
317 /**
318 * @param destinationAddress
319 * the destinationAddress to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800320 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700321 */
322 public IPv4 setDestinationAddress(final int destinationAddress) {
323 this.destinationAddress = destinationAddress;
324 return this;
325 }
326
327 /**
328 * @param destinationAddress
329 * the destinationAddress to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800330 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700331 */
332 public IPv4 setDestinationAddress(final String destinationAddress) {
333 this.destinationAddress = IPv4.toIPv4Address(destinationAddress);
334 return this;
335 }
336
337 /**
338 * @return the options
339 */
340 public byte[] getOptions() {
341 return this.options;
342 }
343
344 /**
345 * @param options
346 * the options to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800347 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700348 */
349 public IPv4 setOptions(final byte[] options) {
350 if (options != null && options.length % 4 > 0) {
351 throw new IllegalArgumentException(
352 "Options length must be a multiple of 4");
353 }
354 this.options = options;
355 return this;
356 }
357
358 /**
359 * Serializes the packet. Will compute and set the following fields if they
360 * are set to specific values at the time serialize is called: -checksum : 0
361 * -headerLength : 0 -totalLength : 0
362 */
363 @Override
364 public byte[] serialize() {
365 byte[] payloadData = null;
366 if (this.payload != null) {
367 this.payload.setParent(this);
368 payloadData = this.payload.serialize();
369 }
370
371 int optionsLength = 0;
372 if (this.options != null) {
373 optionsLength = this.options.length / 4;
374 }
375 this.headerLength = (byte) (5 + optionsLength);
376
377 this.totalLength = (short) (this.headerLength * 4 + (payloadData == null ? 0
378 : payloadData.length));
379
380 final byte[] data = new byte[this.totalLength];
381 final ByteBuffer bb = ByteBuffer.wrap(data);
382
383 bb.put((byte) ((this.version & 0xf) << 4 | this.headerLength & 0xf));
384 bb.put(this.diffServ);
385 bb.putShort(this.totalLength);
386 bb.putShort(this.identification);
387 bb.putShort((short) ((this.flags & 0x7) << 13 | this.fragmentOffset & 0x1fff));
388 bb.put(this.ttl);
389 bb.put(this.protocol);
390 bb.putShort(this.checksum);
391 bb.putInt(this.sourceAddress);
392 bb.putInt(this.destinationAddress);
393 if (this.options != null) {
394 bb.put(this.options);
395 }
396 if (payloadData != null) {
397 bb.put(payloadData);
398 }
399
400 // compute checksum if needed
401 if (this.checksum == 0) {
402 bb.rewind();
403 int accumulation = 0;
404 for (int i = 0; i < this.headerLength * 2; ++i) {
405 accumulation += 0xffff & bb.getShort();
406 }
407 accumulation = (accumulation >> 16 & 0xffff)
408 + (accumulation & 0xffff);
409 this.checksum = (short) (~accumulation & 0xffff);
410 bb.putShort(10, this.checksum);
411 }
412 return data;
413 }
414
415 @Override
416 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700417 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700418 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
419 short sscratch;
420
421 this.version = bb.get();
422 this.headerLength = (byte) (this.version & 0xf);
423 this.version = (byte) (this.version >> 4 & 0xf);
424 this.diffServ = bb.get();
425 this.totalLength = bb.getShort();
426 this.identification = bb.getShort();
427 sscratch = bb.getShort();
428 this.flags = (byte) (sscratch >> 13 & 0x7);
429 this.fragmentOffset = (short) (sscratch & 0x1fff);
430 this.ttl = bb.get();
431 this.protocol = bb.get();
432 this.checksum = bb.getShort();
433 this.sourceAddress = bb.getInt();
434 this.destinationAddress = bb.getInt();
435
436 if (this.headerLength > 5) {
437 final int optionsLength = (this.headerLength - 5) * 4;
438 this.options = new byte[optionsLength];
439 bb.get(this.options);
440 }
441
alshabibc4901cd2014-09-05 16:50:40 -0700442 if (this.totalLength != length) {
443 this.isTruncated = true;
444 } else {
445 this.isTruncated = false;
446 }
447
Jonathan Hart2a655752015-04-07 16:46:33 -0700448 Deserializer<? extends IPacket> deserializer;
449 if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(this.protocol)) {
450 deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(this.protocol);
451 } else {
452 deserializer = Data.deserializer();
453 }
454 try {
455 this.payload = deserializer.deserialize(data, bb.position(),
456 bb.limit() - bb.position());
457 this.payload.setParent(this);
458 } catch (DeserializationException e) {
459 return this;
460 }
461
alshabibc4901cd2014-09-05 16:50:40 -0700462 return this;
463 }
464
465 /**
466 * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
467 * returns the corresponding 32 bit integer.
468 *
tom5f18cf32014-09-13 14:10:57 -0700469 * @param ipAddress ip address in string form
470 * @return int ip address value
alshabibc4901cd2014-09-05 16:50:40 -0700471 */
472 public static int toIPv4Address(final String ipAddress) {
473 if (ipAddress == null) {
474 throw new IllegalArgumentException("Specified IPv4 address must"
475 + "contain 4 sets of numerical digits separated by periods");
476 }
477 final String[] octets = ipAddress.split("\\.");
478 if (octets.length != 4) {
479 throw new IllegalArgumentException("Specified IPv4 address must"
480 + "contain 4 sets of numerical digits separated by periods");
481 }
482
483 int result = 0;
484 for (int i = 0; i < 4; ++i) {
Yuta HIGUCHIe5ca93b2014-10-23 09:49:00 -0700485 result |= Integer.parseInt(octets[i]) << (3 - i) * 8;
alshabibc4901cd2014-09-05 16:50:40 -0700486 }
487 return result;
488 }
489
490 /**
491 * Accepts an IPv4 address in a byte array and returns the corresponding
492 * 32-bit integer value.
493 *
tom5f18cf32014-09-13 14:10:57 -0700494 * @param ipAddress ip address in byte form
495 * @return int ip address value
alshabibc4901cd2014-09-05 16:50:40 -0700496 */
497 public static int toIPv4Address(final byte[] ipAddress) {
498 int ip = 0;
499 for (int i = 0; i < 4; i++) {
500 final int t = (ipAddress[i] & 0xff) << (3 - i) * 8;
501 ip |= t;
502 }
503 return ip;
504 }
505
506 /**
507 * Accepts an IPv4 address and returns of string of the form xxx.xxx.xxx.xxx,
508 * e.g., 192.168.0.1.
509 *
tom5f18cf32014-09-13 14:10:57 -0700510 * @param ipAddress ip address in form
511 * @return string form of ip address
alshabibc4901cd2014-09-05 16:50:40 -0700512 */
513 public static String fromIPv4Address(final int ipAddress) {
514 final StringBuffer sb = new StringBuffer();
515 int result = 0;
516 for (int i = 0; i < 4; ++i) {
517 result = ipAddress >> (3 - i) * 8 & 0xff;
Yuta HIGUCHIe5ca93b2014-10-23 09:49:00 -0700518 sb.append(result);
alshabib638dc712014-09-05 18:03:45 -0700519 if (i != 3) {
520 sb.append(".");
521 }
alshabibc4901cd2014-09-05 16:50:40 -0700522 }
523 return sb.toString();
524 }
525
526 /**
527 * Accepts a collection of IPv4 addresses as integers and returns a single
528 * String useful in toString method's containing collections of IP
529 * addresses.
530 *
531 * @param ipAddresses
532 * collection
tom5f18cf32014-09-13 14:10:57 -0700533 * @return ip addresses in comma-separated string form
alshabibc4901cd2014-09-05 16:50:40 -0700534 */
535 public static String fromIPv4AddressCollection(
536 final Collection<Integer> ipAddresses) {
537 if (ipAddresses == null) {
538 return "null";
539 }
540 final StringBuffer sb = new StringBuffer();
541 sb.append("[");
542 for (final Integer ip : ipAddresses) {
543 sb.append(IPv4.fromIPv4Address(ip));
544 sb.append(",");
545 }
546 sb.replace(sb.length() - 1, sb.length(), "]");
547 return sb.toString();
548 }
549
550 /**
551 * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
552 * returns the corresponding byte array.
553 *
554 * @param ipAddress
555 * The IP address in the form xx.xxx.xxx.xxx.
556 * @return The IP address separated into bytes
557 */
558 public static byte[] toIPv4AddressBytes(final String ipAddress) {
559 final String[] octets = ipAddress.split("\\.");
560 if (octets.length != 4) {
561 throw new IllegalArgumentException("Specified IPv4 address must"
562 + "contain 4 sets of numerical digits separated by periods");
563 }
564
565 final byte[] result = new byte[4];
566 for (int i = 0; i < 4; ++i) {
567 result[i] = Integer.valueOf(octets[i]).byteValue();
568 }
569 return result;
570 }
571
572 /**
573 * Accepts an IPv4 address in the form of an integer and returns the
574 * corresponding byte array.
575 *
576 * @param ipAddress
577 * The IP address as an integer.
578 * @return The IP address separated into bytes.
579 */
580 public static byte[] toIPv4AddressBytes(final int ipAddress) {
581 return new byte[] {(byte) (ipAddress >>> 24),
582 (byte) (ipAddress >>> 16), (byte) (ipAddress >>> 8),
583 (byte) ipAddress};
584 }
585
586 /*
587 * (non-Javadoc)
588 *
589 * @see java.lang.Object#hashCode()
590 */
591 @Override
592 public int hashCode() {
593 final int prime = 2521;
594 int result = super.hashCode();
595 result = prime * result + this.checksum;
596 result = prime * result + this.destinationAddress;
597 result = prime * result + this.diffServ;
598 result = prime * result + this.flags;
599 result = prime * result + this.fragmentOffset;
600 result = prime * result + this.headerLength;
601 result = prime * result + this.identification;
602 result = prime * result + Arrays.hashCode(this.options);
603 result = prime * result + this.protocol;
604 result = prime * result + this.sourceAddress;
605 result = prime * result + this.totalLength;
606 result = prime * result + this.ttl;
607 result = prime * result + this.version;
608 return result;
609 }
610
611 /*
612 * (non-Javadoc)
613 *
614 * @see java.lang.Object#equals(java.lang.Object)
615 */
616 @Override
617 public boolean equals(final Object obj) {
618 if (this == obj) {
619 return true;
620 }
621 if (!super.equals(obj)) {
622 return false;
623 }
624 if (!(obj instanceof IPv4)) {
625 return false;
626 }
627 final IPv4 other = (IPv4) obj;
628 if (this.checksum != other.checksum) {
629 return false;
630 }
631 if (this.destinationAddress != other.destinationAddress) {
632 return false;
633 }
634 if (this.diffServ != other.diffServ) {
635 return false;
636 }
637 if (this.flags != other.flags) {
638 return false;
639 }
640 if (this.fragmentOffset != other.fragmentOffset) {
641 return false;
642 }
643 if (this.headerLength != other.headerLength) {
644 return false;
645 }
646 if (this.identification != other.identification) {
647 return false;
648 }
649 if (!Arrays.equals(this.options, other.options)) {
650 return false;
651 }
652 if (this.protocol != other.protocol) {
653 return false;
654 }
655 if (this.sourceAddress != other.sourceAddress) {
656 return false;
657 }
658 if (this.totalLength != other.totalLength) {
659 return false;
660 }
661 if (this.ttl != other.ttl) {
662 return false;
663 }
664 if (this.version != other.version) {
665 return false;
666 }
667 return true;
668 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700669
670 /**
671 * Deserializer function for IPv4 packets.
672 *
673 * @return deserializer function
674 */
675 public static Deserializer<IPv4> deserializer() {
676 return (data, offset, length) -> {
677 checkInput(data, offset, length, HEADER_LENGTH);
678
679 IPv4 ipv4 = new IPv4();
680
681 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
682
683 byte versionByte = bb.get();
684 ipv4.headerLength = (byte) (versionByte & 0xf);
685 ipv4.setVersion((byte) (versionByte >> 4 & 0xf));
686 ipv4.setDiffServ(bb.get());
687 ipv4.totalLength = bb.getShort();
688 ipv4.identification = bb.getShort();
689 short flagsFragment = bb.getShort();
690 ipv4.flags = (byte) (flagsFragment >> 13 & 0x7);
691 ipv4.fragmentOffset = (short) (flagsFragment & 0x1fff);
692 ipv4.ttl = bb.get();
693 ipv4.protocol = bb.get();
694 ipv4.checksum = bb.getShort();
695 ipv4.sourceAddress = bb.getInt();
696 ipv4.destinationAddress = bb.getInt();
697
698 if (ipv4.headerLength > 5) {
699 checkHeaderLength(length, ipv4.headerLength * 4);
700
701 int optionsLength = (ipv4.headerLength - 5) * 4;
702 ipv4.options = new byte[optionsLength];
703 bb.get(ipv4.options);
704 }
705
706 Deserializer<? extends IPacket> deserializer;
707 if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv4.protocol)) {
708 deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(ipv4.protocol);
709 } else {
710 deserializer = Data.deserializer();
711 }
Charles Chan89c4a642017-04-13 17:43:52 -0700712
713 int remainingLength = bb.limit() - bb.position();
714 int payloadLength = ipv4.totalLength - ipv4.headerLength * 4;
715 int bytesToRead = (payloadLength <= remainingLength) ?
716 payloadLength : remainingLength;
717 ipv4.payload = deserializer.deserialize(data, bb.position(), bytesToRead);
Jonathan Hart2a655752015-04-07 16:46:33 -0700718 ipv4.payload.setParent(ipv4);
719
720 if (ipv4.totalLength != length) {
721 ipv4.isTruncated = true;
722 } else {
723 ipv4.isTruncated = false;
724 }
725
726 return ipv4;
727 };
728 }
Jian Li5fc14292015-12-04 11:30:46 -0800729
730 @Override
731 public String toString() {
732 return toStringHelper(getClass())
733 .add("version", Byte.toString(version))
734 .add("headerLength", Byte.toString(headerLength))
735 .add("diffServ", Byte.toString(diffServ))
736 .add("totalLength", Short.toString(totalLength))
737 .add("identification", Short.toString(identification))
738 .add("flags", Byte.toString(flags))
739 .add("fragmentOffset", Short.toString(fragmentOffset))
740 .add("ttl", Byte.toString(ttl))
741 .add("protocol", Byte.toString(protocol))
742 .add("checksum", Short.toString(checksum))
743 .add("sourceAddress", Integer.toString(sourceAddress))
744 .add("destinationAddress", Integer.toString(destinationAddress))
745 .add("options", Arrays.toString(options))
746 .add("isTruncated", Boolean.toString(isTruncated))
747 .toString();
748 }
alshabibc4901cd2014-09-05 16:50:40 -0700749}