Jonathan Hart
Committed by Gerrit Code Review

Improve the resiliency of the packet deserialization code.

Packet deserializers now check for malformed input while reading the byte
stream. Deserializers are re-implemented as functions that take a byte array
and return a packet object. The old IPacket.deserialize(...) methods have been
deprecated with the goal of eventually moving to immutable packet objects.
Unit tests have been implemented for all Deserializer functions.

ONOS-1589

Change-Id: I9073d5e6e7991e15d43830cfd810989256b71c56
Showing 60 changed files with 2462 additions and 336 deletions
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
15 */ 15 */
16 package org.onosproject.bgprouter; 16 package org.onosproject.bgprouter;
17 17
18 -import java.nio.ByteBuffer;
19 -
20 import org.onlab.packet.Ethernet; 18 import org.onlab.packet.Ethernet;
21 import org.onlab.packet.ICMP; 19 import org.onlab.packet.ICMP;
22 import org.onlab.packet.IPv4; 20 import org.onlab.packet.IPv4;
...@@ -36,6 +34,8 @@ import org.onosproject.routing.config.RoutingConfigurationService; ...@@ -36,6 +34,8 @@ import org.onosproject.routing.config.RoutingConfigurationService;
36 import org.slf4j.Logger; 34 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory; 35 import org.slf4j.LoggerFactory;
38 36
37 +import java.nio.ByteBuffer;
38 +
39 public class IcmpHandler { 39 public class IcmpHandler {
40 40
41 private static final Logger log = LoggerFactory.getLogger(IcmpHandler.class); 41 private static final Logger log = LoggerFactory.getLogger(IcmpHandler.class);
...@@ -100,7 +100,7 @@ public class IcmpHandler { ...@@ -100,7 +100,7 @@ public class IcmpHandler {
100 icmpReplyIpv4.setTtl((byte) 64); 100 icmpReplyIpv4.setTtl((byte) 64);
101 icmpReplyIpv4.setChecksum((short) 0); 101 icmpReplyIpv4.setChecksum((short) 0);
102 102
103 - ICMP icmpReply = (ICMP) icmpRequestIpv4.getPayload().clone(); 103 + ICMP icmpReply = new ICMP();
104 icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY); 104 icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
105 icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY); 105 icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
106 icmpReply.setChecksum((short) 0); 106 icmpReply.setChecksum((short) 0);
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
15 */ 15 */
16 package org.onosproject.segmentrouting; 16 package org.onosproject.segmentrouting;
17 17
18 -import java.nio.ByteBuffer;
19 -import java.util.List;
20 import org.onlab.packet.Ethernet; 18 import org.onlab.packet.Ethernet;
21 import org.onlab.packet.ICMP; 19 import org.onlab.packet.ICMP;
22 import org.onlab.packet.IPv4; 20 import org.onlab.packet.IPv4;
...@@ -33,6 +31,9 @@ import org.onosproject.net.packet.OutboundPacket; ...@@ -33,6 +31,9 @@ import org.onosproject.net.packet.OutboundPacket;
33 import org.slf4j.Logger; 31 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory; 32 import org.slf4j.LoggerFactory;
35 33
34 +import java.nio.ByteBuffer;
35 +import java.util.List;
36 +
36 import static com.google.common.base.Preconditions.checkNotNull; 37 import static com.google.common.base.Preconditions.checkNotNull;
37 38
38 public class IcmpHandler { 39 public class IcmpHandler {
...@@ -109,7 +110,7 @@ public class IcmpHandler { ...@@ -109,7 +110,7 @@ public class IcmpHandler {
109 icmpReplyIpv4.setTtl((byte) 64); 110 icmpReplyIpv4.setTtl((byte) 64);
110 icmpReplyIpv4.setChecksum((short) 0); 111 icmpReplyIpv4.setChecksum((short) 0);
111 112
112 - ICMP icmpReply = (ICMP) icmpRequestIpv4.getPayload().clone(); 113 + ICMP icmpReply = new ICMP();
113 icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY); 114 icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
114 icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY); 115 icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
115 icmpReply.setChecksum((short) 0); 116 icmpReply.setChecksum((short) 0);
......
...@@ -49,8 +49,14 @@ import java.util.Collections; ...@@ -49,8 +49,14 @@ import java.util.Collections;
49 import java.util.List; 49 import java.util.List;
50 import java.util.Set; 50 import java.util.Set;
51 51
52 -import static org.easymock.EasyMock.*; 52 +import static org.easymock.EasyMock.createMock;
53 -import static org.junit.Assert.*; 53 +import static org.easymock.EasyMock.expect;
54 +import static org.easymock.EasyMock.expectLastCall;
55 +import static org.easymock.EasyMock.replay;
56 +import static org.easymock.EasyMock.verify;
57 +import static org.junit.Assert.assertArrayEquals;
58 +import static org.junit.Assert.assertEquals;
59 +import static org.junit.Assert.assertTrue;
54 60
55 public class HostMonitorTest { 61 public class HostMonitorTest {
56 62
...@@ -151,10 +157,9 @@ public class HostMonitorTest { ...@@ -151,10 +157,9 @@ public class HostMonitorTest {
151 assertEquals(portNum, oi.port()); 157 assertEquals(portNum, oi.port());
152 158
153 // Check the output packet is correct (well the important bits anyway) 159 // Check the output packet is correct (well the important bits anyway)
154 - Ethernet eth = new Ethernet();
155 final byte[] pktData = new byte[packet.data().remaining()]; 160 final byte[] pktData = new byte[packet.data().remaining()];
156 packet.data().get(pktData); 161 packet.data().get(pktData);
157 - eth.deserialize(pktData, 0, pktData.length); 162 + Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
158 assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID()); 163 assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
159 ARP arp = (ARP) eth.getPayload(); 164 ARP arp = (ARP) eth.getPayload();
160 assertArrayEquals(SOURCE_ADDR.toOctets(), 165 assertArrayEquals(SOURCE_ADDR.toOctets(),
...@@ -220,10 +225,9 @@ public class HostMonitorTest { ...@@ -220,10 +225,9 @@ public class HostMonitorTest {
220 assertEquals(portNum, oi.port()); 225 assertEquals(portNum, oi.port());
221 226
222 // Check the output packet is correct (well the important bits anyway) 227 // Check the output packet is correct (well the important bits anyway)
223 - Ethernet eth = new Ethernet();
224 final byte[] pktData = new byte[packet.data().remaining()]; 228 final byte[] pktData = new byte[packet.data().remaining()];
225 packet.data().get(pktData); 229 packet.data().get(pktData);
226 - eth.deserialize(pktData, 0, pktData.length); 230 + Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
227 assertEquals(vlan, eth.getVlanID()); 231 assertEquals(vlan, eth.getVlanID());
228 ARP arp = (ARP) eth.getPayload(); 232 ARP arp = (ARP) eth.getPayload();
229 assertArrayEquals(SOURCE_ADDR.toOctets(), 233 assertArrayEquals(SOURCE_ADDR.toOctets(),
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
15 */ 15 */
16 package org.onosproject.openflow.controller; 16 package org.onosproject.openflow.controller;
17 17
18 - 18 +import org.onlab.packet.DeserializationException;
19 import org.onlab.packet.Ethernet; 19 import org.onlab.packet.Ethernet;
20 import org.onosproject.core.Permission; 20 import org.onosproject.core.Permission;
21 import org.projectfloodlight.openflow.protocol.OFPacketIn; 21 import org.projectfloodlight.openflow.protocol.OFPacketIn;
...@@ -26,6 +26,8 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput; ...@@ -26,6 +26,8 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
26 import org.projectfloodlight.openflow.protocol.match.MatchField; 26 import org.projectfloodlight.openflow.protocol.match.MatchField;
27 import org.projectfloodlight.openflow.types.OFBufferId; 27 import org.projectfloodlight.openflow.types.OFBufferId;
28 import org.projectfloodlight.openflow.types.OFPort; 28 import org.projectfloodlight.openflow.types.OFPort;
29 +import org.slf4j.Logger;
30 +import org.slf4j.LoggerFactory;
29 31
30 import java.nio.BufferUnderflowException; 32 import java.nio.BufferUnderflowException;
31 import java.util.Collections; 33 import java.util.Collections;
...@@ -97,11 +99,12 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext ...@@ -97,11 +99,12 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext
97 public Ethernet parsed() { 99 public Ethernet parsed() {
98 checkPermission(Permission.PACKET_READ); 100 checkPermission(Permission.PACKET_READ);
99 101
100 - Ethernet eth = new Ethernet();
101 try { 102 try {
102 - eth.deserialize(pktin.getData(), 0, pktin.getData().length); 103 + return Ethernet.deserializer().deserialize(pktin.getData(), 0, pktin.getData().length);
103 - return eth; 104 + } catch (BufferUnderflowException | NullPointerException |
104 - } catch (BufferUnderflowException | NullPointerException e) { 105 + DeserializationException e) {
106 + Logger log = LoggerFactory.getLogger(getClass());
107 + log.warn("packet deserialization problem");
105 return null; 108 return null;
106 } 109 }
107 } 110 }
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
15 */ 15 */
16 package org.onosproject.provider.of.packet.impl; 16 package org.onosproject.provider.of.packet.impl;
17 17
18 +import org.onlab.packet.DeserializationException;
19 +import org.onlab.packet.Ethernet;
18 import org.onosproject.net.PortNumber; 20 import org.onosproject.net.PortNumber;
19 import org.onosproject.net.flow.instructions.Instruction; 21 import org.onosproject.net.flow.instructions.Instruction;
20 import org.onosproject.net.flow.instructions.Instruction.Type; 22 import org.onosproject.net.flow.instructions.Instruction.Type;
...@@ -23,8 +25,9 @@ import org.onosproject.net.packet.DefaultPacketContext; ...@@ -23,8 +25,9 @@ import org.onosproject.net.packet.DefaultPacketContext;
23 import org.onosproject.net.packet.InboundPacket; 25 import org.onosproject.net.packet.InboundPacket;
24 import org.onosproject.net.packet.OutboundPacket; 26 import org.onosproject.net.packet.OutboundPacket;
25 import org.onosproject.openflow.controller.OpenFlowPacketContext; 27 import org.onosproject.openflow.controller.OpenFlowPacketContext;
26 -import org.onlab.packet.Ethernet;
27 import org.projectfloodlight.openflow.types.OFPort; 28 import org.projectfloodlight.openflow.types.OFPort;
29 +import org.slf4j.Logger;
30 +import org.slf4j.LoggerFactory;
28 31
29 import java.util.List; 32 import java.util.List;
30 33
...@@ -33,6 +36,8 @@ import java.util.List; ...@@ -33,6 +36,8 @@ import java.util.List;
33 */ 36 */
34 public class OpenFlowCorePacketContext extends DefaultPacketContext { 37 public class OpenFlowCorePacketContext extends DefaultPacketContext {
35 38
39 + private static final Logger log = LoggerFactory.getLogger(OpenFlowCorePacketContext.class);
40 +
36 private final OpenFlowPacketContext ofPktCtx; 41 private final OpenFlowPacketContext ofPktCtx;
37 42
38 /** 43 /**
...@@ -57,12 +62,15 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext { ...@@ -57,12 +62,15 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext {
57 if (outPacket() == null) { 62 if (outPacket() == null) {
58 sendPacket(null); 63 sendPacket(null);
59 } else { 64 } else {
60 - Ethernet eth = new Ethernet(); 65 + try {
61 - eth.deserialize(outPacket().data().array(), 0, 66 + Ethernet eth = Ethernet.deserializer()
67 + .deserialize(outPacket().data().array(), 0,
62 outPacket().data().array().length); 68 outPacket().data().array().length);
63 sendPacket(eth); 69 sendPacket(eth);
70 + } catch (DeserializationException e) {
71 + log.warn("Unable to deserialize packet");
72 + }
64 } 73 }
65 -
66 } 74 }
67 } 75 }
68 76
......
...@@ -42,6 +42,11 @@ ...@@ -42,6 +42,11 @@
42 <scope>test</scope> 42 <scope>test</scope>
43 </dependency> 43 </dependency>
44 <dependency> 44 <dependency>
45 + <groupId>org.easymock</groupId>
46 + <artifactId>easymock</artifactId>
47 + <scope>test</scope>
48 + </dependency>
49 + <dependency>
45 <groupId>io.netty</groupId> 50 <groupId>io.netty</groupId>
46 <artifactId>netty</artifactId> 51 <artifactId>netty</artifactId>
47 </dependency> 52 </dependency>
......
...@@ -21,6 +21,8 @@ package org.onlab.packet; ...@@ -21,6 +21,8 @@ package org.onlab.packet;
21 import java.nio.ByteBuffer; 21 import java.nio.ByteBuffer;
22 import java.util.Arrays; 22 import java.util.Arrays;
23 23
24 +import static org.onlab.packet.PacketUtils.*;
25 +
24 /** 26 /**
25 * 27 *
26 * 28 *
...@@ -35,6 +37,8 @@ public class ARP extends BasePacket { ...@@ -35,6 +37,8 @@ public class ARP extends BasePacket {
35 public static final short OP_RARP_REQUEST = 0x3; 37 public static final short OP_RARP_REQUEST = 0x3;
36 public static final short OP_RARP_REPLY = 0x4; 38 public static final short OP_RARP_REPLY = 0x4;
37 39
40 + public static final short INITIAL_HEADER_LENGTH = 8;
41 +
38 protected short hardwareType; 42 protected short hardwareType;
39 protected short protocolType; 43 protected short protocolType;
40 protected byte hardwareAddressLength; 44 protected byte hardwareAddressLength;
...@@ -392,4 +396,44 @@ public class ARP extends BasePacket { ...@@ -392,4 +396,44 @@ public class ARP extends BasePacket {
392 eth.setPayload(arp); 396 eth.setPayload(arp);
393 return eth; 397 return eth;
394 } 398 }
399 +
400 + /**
401 + * Deserializer function for ARP packets.
402 + *
403 + * @return deserializer function
404 + */
405 + public static Deserializer<ARP> deserializer() {
406 + return (data, offset, length) -> {
407 + checkInput(data, offset, length, INITIAL_HEADER_LENGTH);
408 +
409 + ARP arp = new ARP();
410 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
411 + arp.setHardwareType(bb.getShort());
412 + arp.setProtocolType(bb.getShort());
413 +
414 + byte hwAddressLength = bb.get();
415 + arp.setHardwareAddressLength(hwAddressLength);
416 +
417 + byte protocolAddressLength = bb.get();
418 + arp.setProtocolAddressLength(protocolAddressLength);
419 + arp.setOpCode(bb.getShort());
420 +
421 + // Check we have enough space for the addresses
422 + checkHeaderLength(length, INITIAL_HEADER_LENGTH +
423 + 2 * hwAddressLength +
424 + 2 * protocolAddressLength);
425 +
426 + arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
427 + bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
428 + arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
429 + bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
430 + arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
431 + bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
432 + arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
433 + bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);
434 +
435 + return arp;
436 + };
437 + }
438 +
395 } 439 }
......
...@@ -24,6 +24,8 @@ import java.util.ArrayList; ...@@ -24,6 +24,8 @@ import java.util.ArrayList;
24 import java.util.List; 24 import java.util.List;
25 import java.util.ListIterator; 25 import java.util.ListIterator;
26 26
27 +import static org.onlab.packet.PacketUtils.*;
28 +
27 /** 29 /**
28 * 30 *
29 */ 31 */
...@@ -429,30 +431,6 @@ public class DHCP extends BasePacket { ...@@ -429,30 +431,6 @@ public class DHCP extends BasePacket {
429 return data; 431 return data;
430 } 432 }
431 433
432 - protected void writeString(final String string, final ByteBuffer bb,
433 - final int maxLength) {
434 - if (string == null) {
435 - for (int i = 0; i < maxLength; ++i) {
436 - bb.put((byte) 0x0);
437 - }
438 - } else {
439 - byte[] bytes = null;
440 - try {
441 - bytes = string.getBytes("ascii");
442 - } catch (final UnsupportedEncodingException e) {
443 - throw new RuntimeException("Failure encoding server name", e);
444 - }
445 - int writeLength = bytes.length;
446 - if (writeLength > maxLength) {
447 - writeLength = maxLength;
448 - }
449 - bb.put(bytes, 0, writeLength);
450 - for (int i = writeLength; i < maxLength; ++i) {
451 - bb.put((byte) 0x0);
452 - }
453 - }
454 - }
455 -
456 @Override 434 @Override
457 public IPacket deserialize(final byte[] data, final int offset, 435 public IPacket deserialize(final byte[] data, final int offset,
458 final int length) { 436 final int length) {
...@@ -529,7 +507,31 @@ public class DHCP extends BasePacket { ...@@ -529,7 +507,31 @@ public class DHCP extends BasePacket {
529 return this; 507 return this;
530 } 508 }
531 509
532 - protected String readString(final ByteBuffer bb, final int maxLength) { 510 + protected void writeString(final String string, final ByteBuffer bb,
511 + final int maxLength) {
512 + if (string == null) {
513 + for (int i = 0; i < maxLength; ++i) {
514 + bb.put((byte) 0x0);
515 + }
516 + } else {
517 + byte[] bytes = null;
518 + try {
519 + bytes = string.getBytes("ascii");
520 + } catch (final UnsupportedEncodingException e) {
521 + throw new RuntimeException("Failure encoding server name", e);
522 + }
523 + int writeLength = bytes.length;
524 + if (writeLength > maxLength) {
525 + writeLength = maxLength;
526 + }
527 + bb.put(bytes, 0, writeLength);
528 + for (int i = writeLength; i < maxLength; ++i) {
529 + bb.put((byte) 0x0);
530 + }
531 + }
532 + }
533 +
534 + private static String readString(final ByteBuffer bb, final int maxLength) {
533 final byte[] bytes = new byte[maxLength]; 535 final byte[] bytes = new byte[maxLength];
534 bb.get(bytes); 536 bb.get(bytes);
535 String result = null; 537 String result = null;
...@@ -540,4 +542,84 @@ public class DHCP extends BasePacket { ...@@ -540,4 +542,84 @@ public class DHCP extends BasePacket {
540 } 542 }
541 return result; 543 return result;
542 } 544 }
545 +
546 + /**
547 + * Deserializer function for DHCP packets.
548 + *
549 + * @return deserializer function
550 + */
551 + public static Deserializer<DHCP> deserializer() {
552 + return (data, offset, length) -> {
553 + checkInput(data, offset, length, MIN_HEADER_LENGTH);
554 +
555 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
556 + DHCP dhcp = new DHCP();
557 +
558 + dhcp.opCode = bb.get();
559 + dhcp.hardwareType = bb.get();
560 + dhcp.hardwareAddressLength = bb.get();
561 + dhcp.hops = bb.get();
562 + dhcp.transactionId = bb.getInt();
563 + dhcp.seconds = bb.getShort();
564 + dhcp.flags = bb.getShort();
565 + dhcp.clientIPAddress = bb.getInt();
566 + dhcp.yourIPAddress = bb.getInt();
567 + dhcp.serverIPAddress = bb.getInt();
568 + dhcp.gatewayIPAddress = bb.getInt();
569 + final int hardwareAddressLength = 0xff & dhcp.hardwareAddressLength;
570 + dhcp.clientHardwareAddress = new byte[hardwareAddressLength];
571 +
572 + bb.get(dhcp.clientHardwareAddress);
573 + for (int i = hardwareAddressLength; i < 16; ++i) {
574 + bb.get();
575 + }
576 + dhcp.serverName = readString(bb, 64);
577 + dhcp.bootFileName = readString(bb, 128);
578 + // read the magic cookie
579 + // magic cookie
580 + bb.get();
581 + bb.get();
582 + bb.get();
583 + bb.get();
584 +
585 + // read options
586 + boolean foundEndOptionsMarker = false;
587 + while (bb.hasRemaining()) {
588 + final DHCPOption option = new DHCPOption();
589 + int code = 0xff & bb.get(); // convert signed byte to int in range
590 + // [0,255]
591 + option.setCode((byte) code);
592 + if (code == 0) {
593 + // skip these
594 + continue;
595 + } else if (code != 255) {
596 + if (bb.hasRemaining()) {
597 + final int l = 0xff & bb.get(); // convert signed byte to
598 + // int in range [0,255]
599 + option.setLength((byte) l);
600 + if (bb.remaining() >= l) {
601 + final byte[] optionData = new byte[l];
602 + bb.get(optionData);
603 + option.setData(optionData);
604 + dhcp.options.add(option);
605 + } else {
606 + throw new DeserializationException(
607 + "Buffer underflow while reading DHCP option");
608 + }
609 + }
610 + } else if (code == 255) {
611 + // remaining bytes are supposed to be 0, but ignore them just in
612 + // case
613 + foundEndOptionsMarker = true;
614 + break;
615 + }
616 + }
617 +
618 + if (!foundEndOptionsMarker) {
619 + throw new DeserializationException("DHCP End options marker was missing");
620 + }
621 +
622 + return dhcp;
623 + };
624 + }
543 } 625 }
......
...@@ -20,6 +20,8 @@ package org.onlab.packet; ...@@ -20,6 +20,8 @@ package org.onlab.packet;
20 20
21 import java.util.Arrays; 21 import java.util.Arrays;
22 22
23 +import static org.onlab.packet.PacketUtils.*;
24 +
23 /** 25 /**
24 * 26 *
25 */ 27 */
...@@ -30,6 +32,7 @@ public class Data extends BasePacket { ...@@ -30,6 +32,7 @@ public class Data extends BasePacket {
30 * 32 *
31 */ 33 */
32 public Data() { 34 public Data() {
35 + data = new byte[0];
33 } 36 }
34 37
35 /** 38 /**
...@@ -103,4 +106,27 @@ public class Data extends BasePacket { ...@@ -103,4 +106,27 @@ public class Data extends BasePacket {
103 } 106 }
104 return true; 107 return true;
105 } 108 }
109 +
110 + /**
111 + * Deserializer function for generic payload data.
112 + *
113 + * @return deserializer function
114 + */
115 + public static Deserializer<Data> deserializer() {
116 + return (data, offset, length) -> {
117 + // Allow zero-length data for now
118 + if (length == 0) {
119 + return new Data();
120 + }
121 +
122 + checkInput(data, offset, length, 1);
123 +
124 + Data dataObject = new Data();
125 +
126 + dataObject.data = Arrays.copyOfRange(data, offset, data.length);
127 +
128 + return dataObject;
129 + };
130 + }
131 +
106 } 132 }
......
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +/**
20 + * Signals that an error occurred during deserialization of a packet.
21 + */
22 +public class DeserializationException extends Exception {
23 +
24 + /**
25 + * Creates a new deserialization exception with the given message.
26 + *
27 + * @param message exception message
28 + */
29 + public DeserializationException(String message) {
30 + super(message);
31 + }
32 +}
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +/**
20 + * Function to deserialize a packet from a byte-based input stream.
21 + */
22 +@FunctionalInterface
23 +public interface Deserializer<U extends IPacket> {
24 +
25 + /**
26 + * Deserialize a packet object from a byte array.
27 + *
28 + * @param data input array to take packet bytes from
29 + * @param offset index where this packet header begins in the byte array
30 + * @param length length of the packet header
31 + * @return a deserialized packet object
32 + * @throws DeserializationException if the packet cannot be deserialized
33 + * from the input
34 + */
35 + U deserialize(byte[] data, int offset, int length) throws DeserializationException;
36 +}
...@@ -93,25 +93,27 @@ public class EthType { ...@@ -93,25 +93,27 @@ public class EthType {
93 93
94 public static enum EtherType { 94 public static enum EtherType {
95 95
96 - ARP(0x806, "arp", ARP.class), 96 + ARP(0x806, "arp", ARP.class, org.onlab.packet.ARP.deserializer()),
97 - RARP(0x8035, "rarp", null), 97 + RARP(0x8035, "rarp", null, org.onlab.packet.ARP.deserializer()),
98 - IPV4(0x800, "ipv4", IPv4.class), 98 + IPV4(0x800, "ipv4", IPv4.class, org.onlab.packet.IPv4.deserializer()),
99 - IPV6(0x86dd, "ipv6", IPv6.class), 99 + IPV6(0x86dd, "ipv6", IPv6.class, org.onlab.packet.IPv6.deserializer()),
100 - LLDP(0x88cc, "lldp", LLDP.class), 100 + LLDP(0x88cc, "lldp", LLDP.class, org.onlab.packet.LLDP.deserializer()),
101 - VLAN(0x8100, "vlan", null), 101 + VLAN(0x8100, "vlan", null, null),
102 - BDDP(0x8942, "bddp", LLDP.class), 102 + BDDP(0x8942, "bddp", LLDP.class, org.onlab.packet.LLDP.deserializer()),
103 - MPLS_UNICAST(0x8847, "mpls_unicast", null), 103 + MPLS_UNICAST(0x8847, "mpls_unicast", null, org.onlab.packet.MPLS.deserializer()),
104 - MPLS_MULTICAST(0x8848, "mpls_unicast", null); 104 + MPLS_MULTICAST(0x8848, "mpls_unicast", null, org.onlab.packet.MPLS.deserializer());
105 105
106 106
107 private final Class clazz; 107 private final Class clazz;
108 private EthType ethType; 108 private EthType ethType;
109 private String type; 109 private String type;
110 + private Deserializer<?> deserializer;
110 111
111 - EtherType(int ethType, String type, Class clazz) { 112 + EtherType(int ethType, String type, Class clazz, Deserializer deserializer) {
112 this.ethType = new EthType(ethType); 113 this.ethType = new EthType(ethType);
113 this.type = type; 114 this.type = type;
114 this.clazz = clazz; 115 this.clazz = clazz;
116 + this.deserializer = deserializer;
115 } 117 }
116 118
117 public EthType ethType() { 119 public EthType ethType() {
...@@ -127,6 +129,8 @@ public class EthType { ...@@ -127,6 +129,8 @@ public class EthType {
127 return clazz; 129 return clazz;
128 } 130 }
129 131
130 - 132 + public Deserializer<?> deserializer() {
133 + return deserializer;
134 + }
131 } 135 }
132 } 136 }
......
...@@ -18,13 +18,14 @@ ...@@ -18,13 +18,14 @@
18 18
19 package org.onlab.packet; 19 package org.onlab.packet;
20 20
21 -import static com.google.common.base.Preconditions.checkNotNull;
22 -
23 import java.nio.ByteBuffer; 21 import java.nio.ByteBuffer;
24 import java.util.Arrays; 22 import java.util.Arrays;
25 import java.util.HashMap; 23 import java.util.HashMap;
26 import java.util.Map; 24 import java.util.Map;
27 25
26 +import static com.google.common.base.Preconditions.checkNotNull;
27 +import static org.onlab.packet.PacketUtils.checkHeaderLength;
28 +import static org.onlab.packet.PacketUtils.checkInput;
28 29
29 /** 30 /**
30 * 31 *
...@@ -42,15 +43,21 @@ public class Ethernet extends BasePacket { ...@@ -42,15 +43,21 @@ public class Ethernet extends BasePacket {
42 public static final short MPLS_UNICAST = EthType.MPLS_UNICAST; 43 public static final short MPLS_UNICAST = EthType.MPLS_UNICAST;
43 public static final short MPLS_MULTICAST = EthType.MPLS_MULTICAST; 44 public static final short MPLS_MULTICAST = EthType.MPLS_MULTICAST;
44 45
46 +
45 public static final short VLAN_UNTAGGED = (short) 0xffff; 47 public static final short VLAN_UNTAGGED = (short) 0xffff;
48 +
49 + public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
50 + public static final short VLAN_HEADER_LENGTH = 4; // bytes
51 +
46 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes 52 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
47 - public static final Map<Short, Class<? extends IPacket>> ETHER_TYPE_CLASS_MAP = 53 +
54 + private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP =
48 new HashMap<>(); 55 new HashMap<>();
49 56
50 static { 57 static {
51 for (EthType.EtherType ethType : EthType.EtherType.values()) { 58 for (EthType.EtherType ethType : EthType.EtherType.values()) {
52 if (ethType.clazz() != null) { 59 if (ethType.clazz() != null) {
53 - ETHER_TYPE_CLASS_MAP.put(ethType.ethType().toShort(), ethType.clazz()); 60 + ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer());
54 } 61 }
55 } 62 }
56 } 63 }
...@@ -331,21 +338,19 @@ public class Ethernet extends BasePacket { ...@@ -331,21 +338,19 @@ public class Ethernet extends BasePacket {
331 this.etherType = ethType; 338 this.etherType = ethType;
332 339
333 IPacket payload; 340 IPacket payload;
334 - if (Ethernet.ETHER_TYPE_CLASS_MAP.containsKey(this.etherType)) { 341 + Deserializer<? extends IPacket> deserializer;
335 - final Class<? extends IPacket> clazz = Ethernet.ETHER_TYPE_CLASS_MAP 342 + if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
336 - .get(this.etherType); 343 + deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
337 - try {
338 - payload = clazz.newInstance();
339 - } catch (final Exception e) {
340 - throw new RuntimeException(
341 - "Error parsing payload for Ethernet packet", e);
342 - }
343 } else { 344 } else {
344 - payload = new Data(); 345 + deserializer = Data.deserializer();
345 } 346 }
346 - this.payload = payload.deserialize(data, bb.position(), 347 + try {
348 + this.payload = deserializer.deserialize(data, bb.position(),
347 bb.limit() - bb.position()); 349 bb.limit() - bb.position());
348 this.payload.setParent(this); 350 this.payload.setParent(this);
351 + } catch (DeserializationException e) {
352 + return this;
353 + }
349 return this; 354 return this;
350 } 355 }
351 356
...@@ -567,4 +572,53 @@ public class Ethernet extends BasePacket { ...@@ -567,4 +572,53 @@ public class Ethernet extends BasePacket {
567 return builder.toString(); 572 return builder.toString();
568 } 573 }
569 574
575 + /**
576 + * Deserializer function for Ethernet packets.
577 + *
578 + * @return deserializer function
579 + */
580 + public static Deserializer<Ethernet> deserializer() {
581 + return (data, offset, length) -> {
582 + checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
583 +
584 + byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
585 +
586 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
587 + Ethernet eth = new Ethernet();
588 + // Read destination MAC address into buffer
589 + bb.get(addressBuffer);
590 + eth.setDestinationMACAddress(addressBuffer);
591 +
592 + // Read source MAC address into buffer
593 + bb.get(addressBuffer);
594 + eth.setSourceMACAddress(addressBuffer);
595 +
596 + short ethType = bb.getShort();
597 + if (ethType == TYPE_VLAN) {
598 + checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
599 + final short tci = bb.getShort();
600 + eth.setPriorityCode((byte) (tci >> 13 & 0x07));
601 + eth.setVlanID((short) (tci & 0x0fff));
602 + ethType = bb.getShort();
603 + } else {
604 + eth.setVlanID(Ethernet.VLAN_UNTAGGED);
605 + }
606 + eth.setEtherType(ethType);
607 +
608 + IPacket payload;
609 + Deserializer<? extends IPacket> deserializer;
610 + if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
611 + deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
612 + } else {
613 + deserializer = Data.deserializer();
614 + }
615 + payload = deserializer.deserialize(data, bb.position(),
616 + bb.limit() - bb.position());
617 + payload.setParent(eth);
618 + eth.setPayload(payload);
619 +
620 + return eth;
621 + };
622 + }
623 +
570 } 624 }
......
...@@ -20,6 +20,8 @@ package org.onlab.packet; ...@@ -20,6 +20,8 @@ package org.onlab.packet;
20 20
21 import java.nio.ByteBuffer; 21 import java.nio.ByteBuffer;
22 22
23 +import static org.onlab.packet.PacketUtils.*;
24 +
23 /** 25 /**
24 * Implements ICMP packet format. 26 * Implements ICMP packet format.
25 * 27 *
...@@ -33,6 +35,8 @@ public class ICMP extends BasePacket { ...@@ -33,6 +35,8 @@ public class ICMP extends BasePacket {
33 public static final byte TYPE_ECHO_REPLY = 0x00; 35 public static final byte TYPE_ECHO_REPLY = 0x00;
34 public static final byte SUBTYPE_ECHO_REPLY = 0x00; 36 public static final byte SUBTYPE_ECHO_REPLY = 0x00;
35 37
38 + public static final short ICMP_HEADER_LENGTH = 4;
39 +
36 /** 40 /**
37 * @return the icmpType 41 * @return the icmpType
38 */ 42 */
...@@ -134,6 +138,21 @@ public class ICMP extends BasePacket { ...@@ -134,6 +138,21 @@ public class ICMP extends BasePacket {
134 return data; 138 return data;
135 } 139 }
136 140
141 + @Override
142 + public IPacket deserialize(final byte[] data, final int offset,
143 + final int length) {
144 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
145 + this.icmpType = bb.get();
146 + this.icmpCode = bb.get();
147 + this.checksum = bb.getShort();
148 +
149 + this.payload = new Data();
150 + this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
151 + - bb.position());
152 + this.payload.setParent(this);
153 + return this;
154 + }
155 +
137 /* 156 /*
138 * (non-Javadoc) 157 * (non-Javadoc)
139 * 158 *
...@@ -178,18 +197,27 @@ public class ICMP extends BasePacket { ...@@ -178,18 +197,27 @@ public class ICMP extends BasePacket {
178 return true; 197 return true;
179 } 198 }
180 199
181 - @Override 200 + /**
182 - public IPacket deserialize(final byte[] data, final int offset, 201 + * Deserializer function for ICMP packets.
183 - final int length) { 202 + *
203 + * @return deserializer function
204 + */
205 + public static Deserializer<ICMP> deserializer() {
206 + return (data, offset, length) -> {
207 + checkInput(data, offset, length, ICMP_HEADER_LENGTH);
208 +
209 + ICMP icmp = new ICMP();
210 +
184 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); 211 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
185 - this.icmpType = bb.get(); 212 + icmp.icmpType = bb.get();
186 - this.icmpCode = bb.get(); 213 + icmp.icmpCode = bb.get();
187 - this.checksum = bb.getShort(); 214 + icmp.checksum = bb.getShort();
188 215
189 - this.payload = new Data(); 216 + icmp.payload = Data.deserializer()
190 - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() 217 + .deserialize(data, bb.position(), bb.limit()
191 - bb.position()); 218 - bb.position());
192 - this.payload.setParent(this); 219 + icmp.payload.setParent(icmp);
193 - return this; 220 + return icmp;
221 + };
194 } 222 }
195 } 223 }
......
...@@ -24,10 +24,13 @@ import org.onlab.packet.ndp.NeighborSolicitation; ...@@ -24,10 +24,13 @@ import org.onlab.packet.ndp.NeighborSolicitation;
24 import org.onlab.packet.ndp.Redirect; 24 import org.onlab.packet.ndp.Redirect;
25 import org.onlab.packet.ndp.RouterAdvertisement; 25 import org.onlab.packet.ndp.RouterAdvertisement;
26 import org.onlab.packet.ndp.RouterSolicitation; 26 import org.onlab.packet.ndp.RouterSolicitation;
27 +
27 import java.nio.ByteBuffer; 28 import java.nio.ByteBuffer;
28 import java.util.HashMap; 29 import java.util.HashMap;
29 import java.util.Map; 30 import java.util.Map;
30 31
32 +import static org.onlab.packet.PacketUtils.checkInput;
33 +
31 /** 34 /**
32 * Implements ICMPv6 packet format. (RFC 4443) 35 * Implements ICMPv6 packet format. (RFC 4443)
33 */ 36 */
...@@ -96,15 +99,15 @@ public class ICMP6 extends BasePacket { ...@@ -96,15 +99,15 @@ public class ICMP6 extends BasePacket {
96 /** Unrecognized IPv6 option encountered. */ 99 /** Unrecognized IPv6 option encountered. */
97 public static final byte IPV6_OPT_ERR = (byte) 0x01; 100 public static final byte IPV6_OPT_ERR = (byte) 0x01;
98 101
99 - public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP = 102 + public static final Map<Byte, Deserializer<? extends IPacket>> TYPE_DESERIALIZER_MAP =
100 new HashMap<>(); 103 new HashMap<>();
101 104
102 static { 105 static {
103 - ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.ROUTER_SOLICITATION, RouterSolicitation.class); 106 + ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.ROUTER_SOLICITATION, RouterSolicitation.deserializer());
104 - ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.ROUTER_ADVERTISEMENT, RouterAdvertisement.class); 107 + ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.ROUTER_ADVERTISEMENT, RouterAdvertisement.deserializer());
105 - ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.NEIGHBOR_SOLICITATION, NeighborSolicitation.class); 108 + ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.NEIGHBOR_SOLICITATION, NeighborSolicitation.deserializer());
106 - ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.NEIGHBOR_ADVERTISEMENT, NeighborAdvertisement.class); 109 + ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.NEIGHBOR_ADVERTISEMENT, NeighborAdvertisement.deserializer());
107 - ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.REDIRECT, Redirect.class); 110 + ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.REDIRECT, Redirect.deserializer());
108 } 111 }
109 112
110 protected byte icmpType; 113 protected byte icmpType;
...@@ -261,6 +264,31 @@ public class ICMP6 extends BasePacket { ...@@ -261,6 +264,31 @@ public class ICMP6 extends BasePacket {
261 return data; 264 return data;
262 } 265 }
263 266
267 + @Override
268 + public IPacket deserialize(final byte[] data, final int offset,
269 + final int length) {
270 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
271 + this.icmpType = bb.get();
272 + this.icmpCode = bb.get();
273 + this.checksum = bb.getShort();
274 +
275 + Deserializer<? extends IPacket> deserializer;
276 + if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmpType)) {
277 + deserializer = TYPE_DESERIALIZER_MAP.get(icmpType);
278 + } else {
279 + deserializer = Data.deserializer();
280 + }
281 + try {
282 + this.payload = deserializer.deserialize(data, bb.position(),
283 + bb.limit() - bb.position());
284 + this.payload.setParent(this);
285 + } catch (DeserializationException e) {
286 + return this;
287 + }
288 +
289 + return this;
290 + }
291 +
264 /* 292 /*
265 * (non-Javadoc) 293 * (non-Javadoc)
266 * 294 *
...@@ -305,31 +333,34 @@ public class ICMP6 extends BasePacket { ...@@ -305,31 +333,34 @@ public class ICMP6 extends BasePacket {
305 return true; 333 return true;
306 } 334 }
307 335
308 - @Override 336 + /**
309 - public IPacket deserialize(final byte[] data, final int offset, 337 + * Deserializer function for ICMPv6 packets.
310 - final int length) { 338 + *
311 - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); 339 + * @return deserializer function
312 - this.icmpType = bb.get(); 340 + */
313 - this.icmpCode = bb.get(); 341 + public static Deserializer<ICMP6> deserializer() {
314 - this.checksum = bb.getShort(); 342 + return (data, offset, length) -> {
343 + checkInput(data, offset, length, HEADER_LENGTH);
315 344
316 - IPacket payload; 345 + ICMP6 icmp6 = new ICMP6();
317 - if (ICMP6.PROTOCOL_CLASS_MAP.containsKey(this.icmpType)) { 346 +
318 - final Class<? extends IPacket> clazz = ICMP6.PROTOCOL_CLASS_MAP 347 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
319 - .get(this.icmpType); 348 +
320 - try { 349 + icmp6.icmpType = bb.get();
321 - payload = clazz.newInstance(); 350 + icmp6.icmpCode = bb.get();
322 - } catch (final Exception e) { 351 + icmp6.checksum = bb.getShort();
323 - throw new RuntimeException( 352 +
324 - "Error parsing payload for ICMP6 packet", e); 353 + Deserializer<? extends IPacket> deserializer;
325 - } 354 + if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmp6.icmpType)) {
355 + deserializer = TYPE_DESERIALIZER_MAP.get(icmp6.icmpType);
326 } else { 356 } else {
327 - payload = new Data(); 357 + deserializer = Data.deserializer();
328 } 358 }
329 - this.payload = payload.deserialize(data, bb.position(), 359 + icmp6.payload = deserializer.deserialize(data, bb.position(),
330 bb.limit() - bb.position()); 360 bb.limit() - bb.position());
331 - this.payload.setParent(this); 361 + icmp6.payload.setParent(icmp6);
332 362
333 - return this; 363 + return icmp6;
364 + };
334 } 365 }
335 } 366 }
......
...@@ -64,6 +64,11 @@ public interface IPacket { ...@@ -64,6 +64,11 @@ public interface IPacket {
64 /** 64 /**
65 * Deserializes this packet layer and all possible payloads. 65 * Deserializes this packet layer and all possible payloads.
66 * 66 *
67 + * NOTE: This method has been deprecated and will be removed in a future
68 + * release. It is now recommended to use the Deserializer function provided
69 + * by the deserialize() method on each packet to deserialize them. The
70 + * Deserializer functions are robust to malformed input.
71 + *
67 * @param data bytes to deserialize 72 * @param data bytes to deserialize
68 * @param offset 73 * @param offset
69 * offset to start deserializing from 74 * offset to start deserializing from
...@@ -71,6 +76,7 @@ public interface IPacket { ...@@ -71,6 +76,7 @@ public interface IPacket {
71 * length of the data to deserialize 76 * length of the data to deserialize
72 * @return the deserialized data 77 * @return the deserialized data
73 */ 78 */
79 + @Deprecated
74 IPacket deserialize(byte[] data, int offset, int length); 80 IPacket deserialize(byte[] data, int offset, int length);
75 81
76 /** 82 /**
......
...@@ -25,6 +25,8 @@ import java.util.Collection; ...@@ -25,6 +25,8 @@ import java.util.Collection;
25 import java.util.HashMap; 25 import java.util.HashMap;
26 import java.util.Map; 26 import java.util.Map;
27 27
28 +import static org.onlab.packet.PacketUtils.*;
29 +
28 /** 30 /**
29 * 31 *
30 */ 32 */
...@@ -32,19 +34,21 @@ public class IPv4 extends BasePacket { ...@@ -32,19 +34,21 @@ public class IPv4 extends BasePacket {
32 public static final byte PROTOCOL_ICMP = 0x1; 34 public static final byte PROTOCOL_ICMP = 0x1;
33 public static final byte PROTOCOL_TCP = 0x6; 35 public static final byte PROTOCOL_TCP = 0x6;
34 public static final byte PROTOCOL_UDP = 0x11; 36 public static final byte PROTOCOL_UDP = 0x11;
35 - public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP = 37 + public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
36 new HashMap<>(); 38 new HashMap<>();
37 39
38 static { 40 static {
39 - IPv4.PROTOCOL_CLASS_MAP.put(IPv4.PROTOCOL_ICMP, ICMP.class); 41 + IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_ICMP, ICMP.deserializer());
40 - IPv4.PROTOCOL_CLASS_MAP.put(IPv4.PROTOCOL_TCP, TCP.class); 42 + IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_TCP, TCP.deserializer());
41 - IPv4.PROTOCOL_CLASS_MAP.put(IPv4.PROTOCOL_UDP, UDP.class); 43 + IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_UDP, UDP.deserializer());
42 } 44 }
43 45
44 private static final byte DSCP_MASK = 0x3f; 46 private static final byte DSCP_MASK = 0x3f;
45 private static final byte DSCP_OFFSET = 2; 47 private static final byte DSCP_OFFSET = 2;
46 private static final byte ECN_MASK = 0x3; 48 private static final byte ECN_MASK = 0x3;
47 49
50 + private static final short HEADER_LENGTH = 20;
51 +
48 protected byte version; 52 protected byte version;
49 protected byte headerLength; 53 protected byte headerLength;
50 protected byte diffServ; 54 protected byte diffServ;
...@@ -439,27 +443,24 @@ s */ ...@@ -439,27 +443,24 @@ s */
439 bb.get(this.options); 443 bb.get(this.options);
440 } 444 }
441 445
442 - IPacket payload; 446 + if (this.totalLength != length) {
443 - if (IPv4.PROTOCOL_CLASS_MAP.containsKey(this.protocol)) { 447 + this.isTruncated = true;
444 - final Class<? extends IPacket> clazz = IPv4.PROTOCOL_CLASS_MAP 448 + } else {
445 - .get(this.protocol); 449 + this.isTruncated = false;
446 - try {
447 - payload = clazz.newInstance();
448 - } catch (final Exception e) {
449 - throw new RuntimeException(
450 - "Error parsing payload for IPv4 packet", e);
451 } 450 }
451 +
452 + Deserializer<? extends IPacket> deserializer;
453 + if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(this.protocol)) {
454 + deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(this.protocol);
452 } else { 455 } else {
453 - payload = new Data(); 456 + deserializer = Data.deserializer();
454 } 457 }
455 - this.payload = payload.deserialize(data, bb.position(), 458 + try {
459 + this.payload = deserializer.deserialize(data, bb.position(),
456 bb.limit() - bb.position()); 460 bb.limit() - bb.position());
457 this.payload.setParent(this); 461 this.payload.setParent(this);
458 - 462 + } catch (DeserializationException e) {
459 - if (this.totalLength != length) { 463 + return this;
460 - this.isTruncated = true;
461 - } else {
462 - this.isTruncated = false;
463 } 464 }
464 465
465 return this; 466 return this;
...@@ -669,4 +670,60 @@ s */ ...@@ -669,4 +670,60 @@ s */
669 } 670 }
670 return true; 671 return true;
671 } 672 }
673 +
674 + /**
675 + * Deserializer function for IPv4 packets.
676 + *
677 + * @return deserializer function
678 + */
679 + public static Deserializer<IPv4> deserializer() {
680 + return (data, offset, length) -> {
681 + checkInput(data, offset, length, HEADER_LENGTH);
682 +
683 + IPv4 ipv4 = new IPv4();
684 +
685 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
686 +
687 + byte versionByte = bb.get();
688 + ipv4.headerLength = (byte) (versionByte & 0xf);
689 + ipv4.setVersion((byte) (versionByte >> 4 & 0xf));
690 + ipv4.setDiffServ(bb.get());
691 + ipv4.totalLength = bb.getShort();
692 + ipv4.identification = bb.getShort();
693 + short flagsFragment = bb.getShort();
694 + ipv4.flags = (byte) (flagsFragment >> 13 & 0x7);
695 + ipv4.fragmentOffset = (short) (flagsFragment & 0x1fff);
696 + ipv4.ttl = bb.get();
697 + ipv4.protocol = bb.get();
698 + ipv4.checksum = bb.getShort();
699 + ipv4.sourceAddress = bb.getInt();
700 + ipv4.destinationAddress = bb.getInt();
701 +
702 + if (ipv4.headerLength > 5) {
703 + checkHeaderLength(length, ipv4.headerLength * 4);
704 +
705 + int optionsLength = (ipv4.headerLength - 5) * 4;
706 + ipv4.options = new byte[optionsLength];
707 + bb.get(ipv4.options);
708 + }
709 +
710 + Deserializer<? extends IPacket> deserializer;
711 + if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv4.protocol)) {
712 + deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(ipv4.protocol);
713 + } else {
714 + deserializer = Data.deserializer();
715 + }
716 + ipv4.payload = deserializer.deserialize(data, bb.position(),
717 + bb.limit() - bb.position());
718 + 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 + }
672 } 729 }
......
...@@ -22,14 +22,17 @@ import org.onlab.packet.ipv6.Authentication; ...@@ -22,14 +22,17 @@ import org.onlab.packet.ipv6.Authentication;
22 import org.onlab.packet.ipv6.DestinationOptions; 22 import org.onlab.packet.ipv6.DestinationOptions;
23 import org.onlab.packet.ipv6.EncapSecurityPayload; 23 import org.onlab.packet.ipv6.EncapSecurityPayload;
24 import org.onlab.packet.ipv6.Fragment; 24 import org.onlab.packet.ipv6.Fragment;
25 -import org.onlab.packet.ipv6.IExtensionHeader;
26 import org.onlab.packet.ipv6.HopByHopOptions; 25 import org.onlab.packet.ipv6.HopByHopOptions;
26 +import org.onlab.packet.ipv6.IExtensionHeader;
27 import org.onlab.packet.ipv6.Routing; 27 import org.onlab.packet.ipv6.Routing;
28 +
28 import java.nio.ByteBuffer; 29 import java.nio.ByteBuffer;
29 import java.util.Arrays; 30 import java.util.Arrays;
30 import java.util.HashMap; 31 import java.util.HashMap;
31 import java.util.Map; 32 import java.util.Map;
32 33
34 +import static org.onlab.packet.PacketUtils.checkInput;
35 +
33 /** 36 /**
34 * Implements IPv6 packet format. (RFC 2460) 37 * Implements IPv6 packet format. (RFC 2460)
35 */ 38 */
...@@ -47,19 +50,19 @@ public class IPv6 extends BasePacket implements IExtensionHeader { ...@@ -47,19 +50,19 @@ public class IPv6 extends BasePacket implements IExtensionHeader {
47 public static final byte PROTOCOL_DSTOPT = 0x3C; 50 public static final byte PROTOCOL_DSTOPT = 0x3C;
48 51
49 52
50 - public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP = 53 + public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
51 new HashMap<>(); 54 new HashMap<>();
52 55
53 static { 56 static {
54 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.class); 57 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.deserializer());
55 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_TCP, TCP.class); 58 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_TCP, TCP.deserializer());
56 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_UDP, UDP.class); 59 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_UDP, UDP.deserializer());
57 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.class); 60 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.deserializer());
58 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.class); 61 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.deserializer());
59 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.class); 62 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.deserializer());
60 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.class); 63 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.deserializer());
61 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_AH, Authentication.class); 64 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_AH, Authentication.deserializer());
62 - IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.class); 65 + IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.deserializer());
63 } 66 }
64 67
65 protected byte version; 68 protected byte version;
...@@ -256,22 +259,19 @@ public class IPv6 extends BasePacket implements IExtensionHeader { ...@@ -256,22 +259,19 @@ public class IPv6 extends BasePacket implements IExtensionHeader {
256 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH); 259 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
257 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH); 260 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
258 261
259 - IPacket payload; 262 + Deserializer<? extends IPacket> deserializer;
260 - if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) { 263 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
261 - final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP 264 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
262 - .get(this.nextHeader);
263 - try {
264 - payload = clazz.newInstance();
265 - } catch (final Exception e) {
266 - throw new RuntimeException(
267 - "Error parsing payload for IPv6 packet", e);
268 - }
269 } else { 265 } else {
270 - payload = new Data(); 266 + deserializer = Data.deserializer();
271 } 267 }
272 - this.payload = payload.deserialize(data, bb.position(), 268 + try {
269 + this.payload = deserializer.deserialize(data, bb.position(),
273 bb.limit() - bb.position()); 270 bb.limit() - bb.position());
274 this.payload.setParent(this); 271 this.payload.setParent(this);
272 + } catch (DeserializationException e) {
273 + return this;
274 + }
275 275
276 return this; 276 return this;
277 } 277 }
...@@ -343,4 +343,42 @@ public class IPv6 extends BasePacket implements IExtensionHeader { ...@@ -343,4 +343,42 @@ public class IPv6 extends BasePacket implements IExtensionHeader {
343 } 343 }
344 return true; 344 return true;
345 } 345 }
346 +
347 + /**
348 + * Deserializer function for IPv6 packets.
349 + *
350 + * @return deserializer function
351 + */
352 + public static Deserializer<IPv6> deserializer() {
353 + return (data, offset, length) -> {
354 + checkInput(data, offset, length, FIXED_HEADER_LENGTH);
355 +
356 + IPv6 ipv6 = new IPv6();
357 +
358 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
359 +
360 + int iscratch = bb.getInt();
361 +
362 + ipv6.version = (byte) (iscratch >> 28 & 0xf);
363 + ipv6.trafficClass = (byte) (iscratch >> 20 & 0xff);
364 + ipv6.flowLabel = iscratch & 0xfffff;
365 + ipv6.payloadLength = bb.getShort();
366 + ipv6.nextHeader = bb.get();
367 + ipv6.hopLimit = bb.get();
368 + bb.get(ipv6.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
369 + bb.get(ipv6.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
370 +
371 + Deserializer<? extends IPacket> deserializer;
372 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv6.nextHeader)) {
373 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(ipv6.nextHeader);
374 + } else {
375 + deserializer = Data.deserializer();
376 + }
377 + ipv6.payload = deserializer.deserialize(data, bb.position(),
378 + bb.limit() - bb.position());
379 + ipv6.payload.setParent(ipv6);
380 +
381 + return ipv6;
382 + };
383 + }
346 } 384 }
......
...@@ -20,6 +20,8 @@ package org.onlab.packet; ...@@ -20,6 +20,8 @@ package org.onlab.packet;
20 20
21 import java.nio.ByteBuffer; 21 import java.nio.ByteBuffer;
22 22
23 +import static org.onlab.packet.PacketUtils.*;
24 +
23 /** 25 /**
24 * This class represents an Link Local Control header that is used in Ethernet 26 * This class represents an Link Local Control header that is used in Ethernet
25 * 802.3. 27 * 802.3.
...@@ -27,6 +29,9 @@ import java.nio.ByteBuffer; ...@@ -27,6 +29,9 @@ import java.nio.ByteBuffer;
27 * 29 *
28 */ 30 */
29 public class LLC extends BasePacket { 31 public class LLC extends BasePacket {
32 +
33 + public static final byte LLC_HEADER_LENGTH = 3;
34 +
30 private byte dsap = 0; 35 private byte dsap = 0;
31 private byte ssap = 0; 36 private byte ssap = 0;
32 private byte ctrl = 0; 37 private byte ctrl = 0;
...@@ -74,4 +79,24 @@ public class LLC extends BasePacket { ...@@ -74,4 +79,24 @@ public class LLC extends BasePacket {
74 this.ctrl = bb.get(); 79 this.ctrl = bb.get();
75 return this; 80 return this;
76 } 81 }
82 +
83 + /**
84 + * Deserializer function for LLC packets.
85 + *
86 + * @return deserializer function
87 + */
88 + public static Deserializer<LLC> deserializer() {
89 + return (data, offset, length) -> {
90 + checkInput(data, offset, length, LLC_HEADER_LENGTH);
91 +
92 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
93 + LLC llc = new LLC();
94 +
95 + llc.dsap = bb.get();
96 + llc.ssap = bb.get();
97 + llc.ctrl = bb.get();
98 +
99 + return llc;
100 + };
101 + }
77 } 102 }
......
...@@ -20,13 +20,26 @@ ...@@ -20,13 +20,26 @@
20 package org.onlab.packet; 20 package org.onlab.packet;
21 21
22 import java.nio.ByteBuffer; 22 import java.nio.ByteBuffer;
23 -import java.util.ArrayList; 23 +import java.util.LinkedList;
24 import java.util.List; 24 import java.util.List;
25 25
26 +import static org.onlab.packet.PacketUtils.*;
27 +
26 /** 28 /**
27 * 29 *
28 */ 30 */
29 public class LLDP extends BasePacket { 31 public class LLDP extends BasePacket {
32 + public static final byte CHASSIS_TLV_TYPE = 1;
33 + public static final short CHASSIS_TLV_SIZE = 7;
34 + public static final byte CHASSIS_TLV_SUBTYPE = 4;
35 +
36 + public static final byte PORT_TLV_TYPE = 2;
37 + public static final short PORT_TLV_SIZE = 5;
38 + public static final byte PORT_TLV_SUBTYPE = 2;
39 +
40 + public static final byte TTL_TLV_TYPE = 3;
41 + public static final short TTL_TLV_SIZE = 2;
42 +
30 protected LLDPTLV chassisId; 43 protected LLDPTLV chassisId;
31 protected LLDPTLV portId; 44 protected LLDPTLV portId;
32 protected LLDPTLV ttl; 45 protected LLDPTLV ttl;
...@@ -34,7 +47,7 @@ public class LLDP extends BasePacket { ...@@ -34,7 +47,7 @@ public class LLDP extends BasePacket {
34 protected short ethType; 47 protected short ethType;
35 48
36 public LLDP() { 49 public LLDP() {
37 - this.optionalTLVList = new ArrayList<LLDPTLV>(); 50 + this.optionalTLVList = new LinkedList<>();
38 this.ethType = Ethernet.TYPE_LLDP; 51 this.ethType = Ethernet.TYPE_LLDP;
39 } 52 }
40 53
...@@ -138,7 +151,11 @@ public class LLDP extends BasePacket { ...@@ -138,7 +151,11 @@ public class LLDP extends BasePacket {
138 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); 151 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
139 LLDPTLV tlv; 152 LLDPTLV tlv;
140 do { 153 do {
154 + try {
141 tlv = new LLDPOrganizationalTLV().deserialize(bb); 155 tlv = new LLDPOrganizationalTLV().deserialize(bb);
156 + } catch (DeserializationException e) {
157 + break;
158 + }
142 159
143 // if there was a failure to deserialize stop processing TLVs 160 // if there was a failure to deserialize stop processing TLVs
144 if (tlv == null) { 161 if (tlv == null) {
...@@ -227,4 +244,57 @@ public class LLDP extends BasePacket { ...@@ -227,4 +244,57 @@ public class LLDP extends BasePacket {
227 } 244 }
228 return true; 245 return true;
229 } 246 }
247 +
248 + /**
249 + * Deserializer function for LLDP packets.
250 + *
251 + * @return deserializer function
252 + */
253 + public static Deserializer<LLDP> deserializer() {
254 + return (data, offset, length) -> {
255 + checkInput(data, offset, length, 0);
256 +
257 + LLDP lldp = new LLDP();
258 +
259 + int currentIndex = 0;
260 +
261 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
262 + LLDPTLV tlv;
263 + do {
264 + // Each new TLV must be a minimum of 2 bytes
265 + // (containing the type and length fields).
266 + currentIndex += 2;
267 + checkHeaderLength(length, currentIndex);
268 +
269 + tlv = new LLDPOrganizationalTLV().deserialize(bb);
270 +
271 + // if there was a failure to deserialize stop processing TLVs
272 + if (tlv == null) {
273 + break;
274 + }
275 + switch (tlv.getType()) {
276 + case 0x0:
277 + // can throw this one away, it's just an end delimiter
278 + break;
279 + case 0x1:
280 + lldp.chassisId = tlv;
281 + break;
282 + case 0x2:
283 + lldp.portId = tlv;
284 + break;
285 + case 0x3:
286 + lldp.ttl = tlv;
287 + break;
288 + default:
289 + lldp.optionalTLVList.add(tlv);
290 + break;
291 + }
292 +
293 + currentIndex += tlv.getLength();
294 + } while (tlv.getType() != 0);
295 +
296 + return lldp;
297 + };
298 + }
299 +
230 } 300 }
......
...@@ -154,10 +154,15 @@ public class LLDPOrganizationalTLV extends LLDPTLV { ...@@ -154,10 +154,15 @@ public class LLDPOrganizationalTLV extends LLDPTLV {
154 } 154 }
155 155
156 @Override 156 @Override
157 - public LLDPTLV deserialize(final ByteBuffer bb) { 157 + public LLDPTLV deserialize(final ByteBuffer bb) throws DeserializationException {
158 - LLDPTLV tlv = super.deserialize(bb); 158 + super.deserialize(bb);
159 - if (tlv.getType() != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) { 159 + if (this.getType() != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
160 - return tlv; 160 + return this;
161 + }
162 +
163 + if (this.getLength() <= OUI_LENGTH + SUBTYPE_LENGTH) {
164 + throw new DeserializationException(
165 + "TLV length is less than required for organizational TLV");
161 } 166 }
162 167
163 final ByteBuffer optionalField = ByteBuffer.wrap(this.value); 168 final ByteBuffer optionalField = ByteBuffer.wrap(this.value);
......
...@@ -95,18 +95,23 @@ public class LLDPTLV { ...@@ -95,18 +95,23 @@ public class LLDPTLV {
95 return data; 95 return data;
96 } 96 }
97 97
98 - public LLDPTLV deserialize(final ByteBuffer bb) { 98 + public LLDPTLV deserialize(final ByteBuffer bb) throws DeserializationException {
99 - short sscratch; 99 + if (bb.remaining() < 2) {
100 - sscratch = bb.getShort(); 100 + throw new DeserializationException(
101 - this.type = (byte) (sscratch >> 9 & 0x7f); 101 + "Not enough bytes to deserialize TLV type and length");
102 - this.length = (short) (sscratch & 0x1ff); 102 + }
103 + short typeLength;
104 + typeLength = bb.getShort();
105 + this.type = (byte) (typeLength >> 9 & 0x7f);
106 + this.length = (short) (typeLength & 0x1ff);
103 107
104 if (this.length > 0) { 108 if (this.length > 0) {
105 this.value = new byte[this.length]; 109 this.value = new byte[this.length];
106 110
107 // if there is an underrun just toss the TLV 111 // if there is an underrun just toss the TLV
108 if (bb.remaining() < this.length) { 112 if (bb.remaining() < this.length) {
109 - return null; 113 + throw new DeserializationException(
114 + "Remaining bytes are less then the length of the TLV");
110 } 115 }
111 bb.get(this.value); 116 bb.get(this.value);
112 } 117 }
......
...@@ -4,16 +4,19 @@ import java.nio.ByteBuffer; ...@@ -4,16 +4,19 @@ import java.nio.ByteBuffer;
4 import java.util.HashMap; 4 import java.util.HashMap;
5 import java.util.Map; 5 import java.util.Map;
6 6
7 +import static org.onlab.packet.PacketUtils.checkInput;
8 +
7 public class MPLS extends BasePacket { 9 public class MPLS extends BasePacket {
8 - public static final int ADDRESS_LENGTH = 4; 10 + public static final int HEADER_LENGTH = 4;
11 +
9 public static final byte PROTOCOL_IPV4 = 0x1; 12 public static final byte PROTOCOL_IPV4 = 0x1;
10 public static final byte PROTOCOL_MPLS = 0x6; 13 public static final byte PROTOCOL_MPLS = 0x6;
11 - public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP; 14 + static Map<Byte, Deserializer<? extends IPacket>> protocolDeserializerMap
15 + = new HashMap<>();
12 16
13 static { 17 static {
14 - PROTOCOL_CLASS_MAP = new HashMap<Byte, Class<? extends IPacket>>(); 18 + protocolDeserializerMap.put(PROTOCOL_IPV4, IPv4.deserializer());
15 - PROTOCOL_CLASS_MAP.put(PROTOCOL_IPV4, IPv4.class); 19 + protocolDeserializerMap.put(PROTOCOL_MPLS, MPLS.deserializer());
16 - PROTOCOL_CLASS_MAP.put(PROTOCOL_MPLS, MPLS.class);
17 } 20 }
18 21
19 protected int label; //20bits 22 protected int label; //20bits
...@@ -59,19 +62,18 @@ public class MPLS extends BasePacket { ...@@ -59,19 +62,18 @@ public class MPLS extends BasePacket {
59 this.bos = (byte) (mplsheader & 0x000000ff); 62 this.bos = (byte) (mplsheader & 0x000000ff);
60 this.protocol = (this.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS; 63 this.protocol = (this.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;
61 64
62 - IPacket payload; 65 + Deserializer<? extends IPacket> deserializer;
63 - if (IPv4.PROTOCOL_CLASS_MAP.containsKey(this.protocol)) { 66 + if (protocolDeserializerMap.containsKey(this.protocol)) {
64 - Class<? extends IPacket> clazz = IPv4.PROTOCOL_CLASS_MAP.get(this.protocol); 67 + deserializer = protocolDeserializerMap.get(this.protocol);
65 - try {
66 - payload = clazz.newInstance();
67 - } catch (Exception e) {
68 - throw new RuntimeException("Error parsing payload for MPLS packet", e);
69 - }
70 } else { 68 } else {
71 - payload = new Data(); 69 + deserializer = Data.deserializer();
72 } 70 }
73 - this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position()); 71 + try {
72 + this.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
74 this.payload.setParent(this); 73 this.payload.setParent(this);
74 + } catch (DeserializationException e) {
75 + return this;
76 + }
75 77
76 return this; 78 return this;
77 } 79 }
...@@ -112,4 +114,34 @@ public class MPLS extends BasePacket { ...@@ -112,4 +114,34 @@ public class MPLS extends BasePacket {
112 this.ttl = ttl; 114 this.ttl = ttl;
113 } 115 }
114 116
117 + /**
118 + * Deserializer function for MPLS packets.
119 + *
120 + * @return deserializer function
121 + */
122 + public static Deserializer<MPLS> deserializer() {
123 + return (data, offset, length) -> {
124 + checkInput(data, offset, length, HEADER_LENGTH);
125 +
126 + MPLS mpls = new MPLS();
127 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
128 +
129 + int mplsheader = bb.getInt();
130 + mpls.label = ((mplsheader & 0xfffff000) >>> 12);
131 + mpls.bos = (byte) ((mplsheader & 0x00000100) >> 8);
132 + mpls.ttl = (byte) (mplsheader & 0x000000ff);
133 + mpls.protocol = (mpls.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;
134 +
135 + Deserializer<? extends IPacket> deserializer;
136 + if (protocolDeserializerMap.containsKey(mpls.protocol)) {
137 + deserializer = protocolDeserializerMap.get(mpls.protocol);
138 + } else {
139 + deserializer = Data.deserializer();
140 + }
141 + mpls.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
142 + mpls.payload.setParent(mpls);
143 +
144 + return mpls;
145 + };
146 + }
115 } 147 }
......
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import static com.google.common.base.Preconditions.checkNotNull;
20 +
21 +/**
22 + * Utilities for working with packet headers.
23 + */
24 +public final class PacketUtils {
25 +
26 + private PacketUtils() {
27 + }
28 +
29 + /**
30 + * Check the length of the input buffer is appropriate given the offset and
31 + * length parameters.
32 + *
33 + * @param byteLength length of the input buffer array
34 + * @param offset offset given to begin reading bytes from
35 + * @param length length given to read up until
36 + * @throws DeserializationException if the input parameters don't match up (i.e
37 + * we can't read that many bytes from the buffer at the given offest)
38 + */
39 + public static void checkBufferLength(int byteLength, int offset, int length)
40 + throws DeserializationException {
41 + boolean ok = (offset >= 0 && offset < byteLength);
42 + ok = ok & (length >= 0 && offset + length <= byteLength);
43 +
44 + if (!ok) {
45 + throw new DeserializationException("Unable to read " + length + " bytes from a "
46 + + byteLength + " byte array starting at offset " + offset);
47 + }
48 + }
49 +
50 + /**
51 + * Check that there are enough bytes in the buffer to read some number of
52 + * bytes that we need to read a full header.
53 + *
54 + * @param givenLength given size of the buffer
55 + * @param requiredLength number of bytes we need to read some header fully
56 + * @throws DeserializationException if there aren't enough bytes
57 + */
58 + public static void checkHeaderLength(int givenLength, int requiredLength)
59 + throws DeserializationException {
60 + if (requiredLength > givenLength) {
61 + throw new DeserializationException(requiredLength
62 + + " bytes are needed to continue deserialization, however only "
63 + + givenLength + " remain in buffer");
64 + }
65 + }
66 +
67 + /**
68 + * Check the input parameters are sane and there's enough bytes to read
69 + * the required length.
70 + *
71 + * @param data input byte buffer
72 + * @param offset offset of the start of the header
73 + * @param length length given to deserialize the header
74 + * @param requiredLength length needed to deserialize header
75 + * @throws DeserializationException if we're unable to deserialize the
76 + * packet based on the input parameters
77 + */
78 + public static void checkInput(byte[] data, int offset, int length, int requiredLength)
79 + throws DeserializationException {
80 + checkNotNull(data);
81 + checkBufferLength(data.length, offset, length);
82 + checkHeaderLength(length, requiredLength);
83 + }
84 +}
...@@ -20,11 +20,16 @@ package org.onlab.packet; ...@@ -20,11 +20,16 @@ package org.onlab.packet;
20 20
21 import java.nio.ByteBuffer; 21 import java.nio.ByteBuffer;
22 22
23 +import static org.onlab.packet.PacketUtils.*;
24 +
23 /** 25 /**
24 * Implements TCP packet format. 26 * Implements TCP packet format.
25 */ 27 */
26 28
27 public class TCP extends BasePacket { 29 public class TCP extends BasePacket {
30 +
31 + private static final short TCP_HEADER_LENGTH = 20;
32 +
28 protected short sourcePort; 33 protected short sourcePort;
29 protected short destinationPort; 34 protected short destinationPort;
30 protected int sequence; 35 protected int sequence;
...@@ -339,6 +344,40 @@ public class TCP extends BasePacket { ...@@ -339,6 +344,40 @@ public class TCP extends BasePacket {
339 return data; 344 return data;
340 } 345 }
341 346
347 + @Override
348 + public IPacket deserialize(final byte[] data, final int offset,
349 + final int length) {
350 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
351 + this.sourcePort = bb.getShort();
352 + this.destinationPort = bb.getShort();
353 + this.sequence = bb.getInt();
354 + this.acknowledge = bb.getInt();
355 + this.flags = bb.getShort();
356 + this.dataOffset = (byte) (this.flags >> 12 & 0xf);
357 + this.flags = (short) (this.flags & 0x1ff);
358 + this.windowSize = bb.getShort();
359 + this.checksum = bb.getShort();
360 + this.urgentPointer = bb.getShort();
361 + if (this.dataOffset > 5) {
362 + int optLength = (this.dataOffset << 2) - 20;
363 + if (bb.limit() < bb.position() + optLength) {
364 + optLength = bb.limit() - bb.position();
365 + }
366 + try {
367 + this.options = new byte[optLength];
368 + bb.get(this.options, 0, optLength);
369 + } catch (final IndexOutOfBoundsException e) {
370 + this.options = null;
371 + }
372 + }
373 +
374 + this.payload = new Data();
375 + this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
376 + - bb.position());
377 + this.payload.setParent(this);
378 + return this;
379 + }
380 +
342 /* 381 /*
343 * (non-Javadoc) 382 * (non-Javadoc)
344 * 383 *
...@@ -384,37 +423,39 @@ public class TCP extends BasePacket { ...@@ -384,37 +423,39 @@ public class TCP extends BasePacket {
384 && (this.dataOffset == 5 || this.options.equals(other.options)); 423 && (this.dataOffset == 5 || this.options.equals(other.options));
385 } 424 }
386 425
387 - @Override 426 + /**
388 - public IPacket deserialize(final byte[] data, final int offset, 427 + * Deserializer function for TCP packets.
389 - final int length) { 428 + *
390 - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); 429 + * @return deserializer function
391 - this.sourcePort = bb.getShort(); 430 + */
392 - this.destinationPort = bb.getShort(); 431 + public static Deserializer<TCP> deserializer() {
393 - this.sequence = bb.getInt(); 432 + return (data, offset, length) -> {
394 - this.acknowledge = bb.getInt(); 433 + checkInput(data, offset, length, TCP_HEADER_LENGTH);
395 - this.flags = bb.getShort();
396 - this.dataOffset = (byte) (this.flags >> 12 & 0xf);
397 - this.flags = (short) (this.flags & 0x1ff);
398 - this.windowSize = bb.getShort();
399 - this.checksum = bb.getShort();
400 - this.urgentPointer = bb.getShort();
401 - if (this.dataOffset > 5) {
402 - int optLength = (this.dataOffset << 2) - 20;
403 - if (bb.limit() < bb.position() + optLength) {
404 - optLength = bb.limit() - bb.position();
405 - }
406 - try {
407 - this.options = new byte[optLength];
408 - bb.get(this.options, 0, optLength);
409 - } catch (final IndexOutOfBoundsException e) {
410 - this.options = null;
411 - }
412 - }
413 434
414 - this.payload = new Data(); 435 + TCP tcp = new TCP();
415 - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() 436 +
416 - - bb.position()); 437 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
417 - this.payload.setParent(this); 438 + tcp.sourcePort = bb.getShort();
418 - return this; 439 + tcp.destinationPort = bb.getShort();
440 + tcp.sequence = bb.getInt();
441 + tcp.acknowledge = bb.getInt();
442 + tcp.flags = bb.getShort();
443 + tcp.dataOffset = (byte) (tcp.flags >> 12 & 0xf);
444 + tcp.flags = (short) (tcp.flags & 0x1ff);
445 + tcp.windowSize = bb.getShort();
446 + tcp.checksum = bb.getShort();
447 + tcp.urgentPointer = bb.getShort();
448 + if (tcp.dataOffset > 5) {
449 + int optLength = (tcp.dataOffset << 2) - 20;
450 + checkHeaderLength(length, TCP_HEADER_LENGTH + tcp.dataOffset);
451 + tcp.options = new byte[optLength];
452 + bb.get(tcp.options, 0, optLength);
453 + }
454 +
455 + tcp.payload = Data.deserializer()
456 + .deserialize(data, bb.position(), bb.limit() - bb.position());
457 + tcp.payload.setParent(tcp);
458 + return tcp;
459 + };
419 } 460 }
420 } 461 }
......
...@@ -22,23 +22,27 @@ import java.nio.ByteBuffer; ...@@ -22,23 +22,27 @@ import java.nio.ByteBuffer;
22 import java.util.HashMap; 22 import java.util.HashMap;
23 import java.util.Map; 23 import java.util.Map;
24 24
25 +import static org.onlab.packet.PacketUtils.*;
26 +
25 /** 27 /**
26 * 28 *
27 */ 29 */
28 30
29 public class UDP extends BasePacket { 31 public class UDP extends BasePacket {
30 - public static final Map<Short, Class<? extends IPacket>> DECODE_MAP = 32 + public static final Map<Short, Deserializer<? extends IPacket>> PORT_DESERIALIZER_MAP =
31 new HashMap<>(); 33 new HashMap<>();
32 public static final short DHCP_SERVER_PORT = (short) 67; 34 public static final short DHCP_SERVER_PORT = (short) 67;
33 public static final short DHCP_CLIENT_PORT = (short) 68; 35 public static final short DHCP_CLIENT_PORT = (short) 68;
34 36
37 + private static final short UDP_HEADER_LENGTH = 8;
38 +
35 static { 39 static {
36 /* 40 /*
37 * Disable DHCP until the deserialize code is hardened to deal with 41 * Disable DHCP until the deserialize code is hardened to deal with
38 * garbage input 42 * garbage input
39 */ 43 */
40 - UDP.DECODE_MAP.put(UDP.DHCP_SERVER_PORT, DHCP.class); 44 + UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_SERVER_PORT, DHCP.deserializer());
41 - UDP.DECODE_MAP.put(UDP.DHCP_CLIENT_PORT, DHCP.class); 45 + UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_CLIENT_PORT, DHCP.deserializer());
42 46
43 } 47 }
44 48
...@@ -192,6 +196,34 @@ public class UDP extends BasePacket { ...@@ -192,6 +196,34 @@ public class UDP extends BasePacket {
192 return data; 196 return data;
193 } 197 }
194 198
199 + @Override
200 + public IPacket deserialize(final byte[] data, final int offset,
201 + final int length) {
202 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
203 + this.sourcePort = bb.getShort();
204 + this.destinationPort = bb.getShort();
205 + this.length = bb.getShort();
206 + this.checksum = bb.getShort();
207 +
208 + Deserializer<? extends IPacket> deserializer;
209 + if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.destinationPort)) {
210 + deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.destinationPort);
211 + } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.sourcePort)) {
212 + deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.sourcePort);
213 + } else {
214 + deserializer = Data.deserializer();
215 + }
216 +
217 + try {
218 + this.payload = deserializer.deserialize(data, bb.position(),
219 + bb.limit() - bb.position());
220 + this.payload.setParent(this);
221 + } catch (DeserializationException e) {
222 + return this;
223 + }
224 + return this;
225 + }
226 +
195 /* 227 /*
196 * (non-Javadoc) 228 * (non-Javadoc)
197 * 229 *
...@@ -240,35 +272,36 @@ public class UDP extends BasePacket { ...@@ -240,35 +272,36 @@ public class UDP extends BasePacket {
240 return true; 272 return true;
241 } 273 }
242 274
243 - @Override 275 + /**
244 - public IPacket deserialize(final byte[] data, final int offset, 276 + * Deserializer function for UDP packets.
245 - final int length) { 277 + *
246 - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); 278 + * @return deserializer function
247 - this.sourcePort = bb.getShort(); 279 + */
248 - this.destinationPort = bb.getShort(); 280 + public static Deserializer<UDP> deserializer() {
249 - this.length = bb.getShort(); 281 + return (data, offset, length) -> {
250 - this.checksum = bb.getShort(); 282 + checkInput(data, offset, length, UDP_HEADER_LENGTH);
251 283
252 - if (UDP.DECODE_MAP.containsKey(this.destinationPort)) { 284 + UDP udp = new UDP();
253 - try { 285 +
254 - this.payload = UDP.DECODE_MAP.get(this.destinationPort) 286 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
255 - .getConstructor().newInstance(); 287 + udp.sourcePort = bb.getShort();
256 - } catch (final Exception e) { 288 + udp.destinationPort = bb.getShort();
257 - throw new RuntimeException("Failure instantiating class", e); 289 + udp.length = bb.getShort();
258 - } 290 + udp.checksum = bb.getShort();
259 - } else if (UDP.DECODE_MAP.containsKey(this.sourcePort)) { 291 +
260 - try { 292 + Deserializer<? extends IPacket> deserializer;
261 - this.payload = UDP.DECODE_MAP.get(this.sourcePort) 293 + if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.destinationPort)) {
262 - .getConstructor().newInstance(); 294 + deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.destinationPort);
263 - } catch (final Exception e) { 295 + } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.sourcePort)) {
264 - throw new RuntimeException("Failure instantiating class", e); 296 + deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.sourcePort);
265 - }
266 } else { 297 } else {
267 - this.payload = new Data(); 298 + deserializer = Data.deserializer();
268 } 299 }
269 - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() 300 +
270 - - bb.position()); 301 + udp.payload = deserializer.deserialize(data, bb.position(),
271 - this.payload.setParent(this); 302 + bb.limit() - bb.position());
272 - return this; 303 + udp.payload.setParent(udp);
304 + return udp;
305 + };
273 } 306 }
274 } 307 }
......
...@@ -18,11 +18,16 @@ package org.onlab.packet.ipv6; ...@@ -18,11 +18,16 @@ package org.onlab.packet.ipv6;
18 18
19 import org.onlab.packet.BasePacket; 19 import org.onlab.packet.BasePacket;
20 import org.onlab.packet.Data; 20 import org.onlab.packet.Data;
21 +import org.onlab.packet.DeserializationException;
22 +import org.onlab.packet.Deserializer;
21 import org.onlab.packet.IPacket; 23 import org.onlab.packet.IPacket;
22 import org.onlab.packet.IPv6; 24 import org.onlab.packet.IPv6;
25 +
23 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
24 import java.util.Arrays; 27 import java.util.Arrays;
25 28
29 +import static org.onlab.packet.PacketUtils.checkInput;
30 +
26 /** 31 /**
27 * Implements IPv6 authentication extension header format. (RFC 4302) 32 * Implements IPv6 authentication extension header format. (RFC 4302)
28 */ 33 */
...@@ -186,22 +191,20 @@ public class Authentication extends BasePacket implements IExtensionHeader { ...@@ -186,22 +191,20 @@ public class Authentication extends BasePacket implements IExtensionHeader {
186 this.integrityCheck = new byte[icvLength]; 191 this.integrityCheck = new byte[icvLength];
187 bb.get(this.integrityCheck, 0, icvLength); 192 bb.get(this.integrityCheck, 0, icvLength);
188 193
189 - IPacket payload; 194 + Deserializer<? extends IPacket> deserializer;
190 - if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) { 195 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
191 - final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP 196 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
192 - .get(this.nextHeader);
193 - try {
194 - payload = clazz.newInstance();
195 - } catch (final Exception e) {
196 - throw new RuntimeException(
197 - "Error parsing payload for Authentication packet", e);
198 - }
199 } else { 197 } else {
200 - payload = new Data(); 198 + deserializer = Data.deserializer();
201 } 199 }
202 - this.payload = payload.deserialize(data, bb.position(), 200 +
201 + try {
202 + this.payload = deserializer.deserialize(data, bb.position(),
203 bb.limit() - bb.position()); 203 bb.limit() - bb.position());
204 this.payload.setParent(this); 204 this.payload.setParent(this);
205 + } catch (DeserializationException e) {
206 + return this;
207 + }
205 208
206 return this; 209 return this;
207 } 210 }
...@@ -259,4 +262,39 @@ public class Authentication extends BasePacket implements IExtensionHeader { ...@@ -259,4 +262,39 @@ public class Authentication extends BasePacket implements IExtensionHeader {
259 } 262 }
260 return true; 263 return true;
261 } 264 }
265 +
266 + /**
267 + * Deserializer function for authentication headers.
268 + *
269 + * @return deserializer function
270 + */
271 + public static Deserializer<Authentication> deserializer() {
272 + return (data, offset, length) -> {
273 + checkInput(data, offset, length, FIXED_HEADER_LENGTH);
274 +
275 + Authentication authentication = new Authentication();
276 +
277 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
278 + authentication.nextHeader = bb.get();
279 + authentication.payloadLength = bb.get();
280 + bb.getShort();
281 + authentication.securityParamIndex = bb.getInt();
282 + authentication.sequence = bb.getInt();
283 + int icvLength = (authentication.payloadLength + MINUS) * LENGTH_UNIT - FIXED_HEADER_LENGTH;
284 + authentication.integrityCheck = new byte[icvLength];
285 + bb.get(authentication.integrityCheck, 0, icvLength);
286 +
287 + Deserializer<? extends IPacket> deserializer;
288 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(authentication.nextHeader)) {
289 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(authentication.nextHeader);
290 + } else {
291 + deserializer = Data.deserializer();
292 + }
293 + authentication.payload = deserializer.deserialize(data, bb.position(),
294 + bb.limit() - bb.position());
295 + authentication.payload.setParent(authentication);
296 +
297 + return authentication;
298 + };
299 + }
262 } 300 }
......
...@@ -18,12 +18,17 @@ package org.onlab.packet.ipv6; ...@@ -18,12 +18,17 @@ package org.onlab.packet.ipv6;
18 18
19 import org.onlab.packet.BasePacket; 19 import org.onlab.packet.BasePacket;
20 import org.onlab.packet.Data; 20 import org.onlab.packet.Data;
21 +import org.onlab.packet.DeserializationException;
22 +import org.onlab.packet.Deserializer;
21 import org.onlab.packet.IPacket; 23 import org.onlab.packet.IPacket;
22 import org.onlab.packet.IPv6; 24 import org.onlab.packet.IPv6;
23 25
24 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
25 import java.util.Arrays; 27 import java.util.Arrays;
26 28
29 +import static org.onlab.packet.PacketUtils.checkHeaderLength;
30 +import static org.onlab.packet.PacketUtils.checkInput;
31 +
27 /** 32 /**
28 * Base class for hop-by-hop options and destination options. 33 * Base class for hop-by-hop options and destination options.
29 */ 34 */
...@@ -151,22 +156,19 @@ public class BaseOptions extends BasePacket implements IExtensionHeader { ...@@ -151,22 +156,19 @@ public class BaseOptions extends BasePacket implements IExtensionHeader {
151 this.options = new byte[optionLength]; 156 this.options = new byte[optionLength];
152 bb.get(this.options, 0, optionLength); 157 bb.get(this.options, 0, optionLength);
153 158
154 - IPacket payload; 159 + Deserializer<? extends IPacket> deserializer;
155 - if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) { 160 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
156 - final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP 161 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
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 { 162 } else {
165 - payload = new Data(); 163 + deserializer = Data.deserializer();
166 } 164 }
167 - this.payload = payload.deserialize(data, bb.position(), 165 + try {
166 + this.payload = deserializer.deserialize(data, bb.position(),
168 bb.limit() - bb.position()); 167 bb.limit() - bb.position());
169 this.payload.setParent(this); 168 this.payload.setParent(this);
169 + } catch (DeserializationException e) {
170 + return this;
171 + }
170 172
171 return this; 173 return this;
172 } 174 }
...@@ -219,4 +221,40 @@ public class BaseOptions extends BasePacket implements IExtensionHeader { ...@@ -219,4 +221,40 @@ public class BaseOptions extends BasePacket implements IExtensionHeader {
219 } 221 }
220 return true; 222 return true;
221 } 223 }
224 +
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 + }
222 } 260 }
......
...@@ -18,10 +18,14 @@ package org.onlab.packet.ipv6; ...@@ -18,10 +18,14 @@ package org.onlab.packet.ipv6;
18 18
19 import org.onlab.packet.BasePacket; 19 import org.onlab.packet.BasePacket;
20 import org.onlab.packet.Data; 20 import org.onlab.packet.Data;
21 +import org.onlab.packet.Deserializer;
21 import org.onlab.packet.IPacket; 22 import org.onlab.packet.IPacket;
22 import org.onlab.packet.IPv6; 23 import org.onlab.packet.IPv6;
24 +
23 import java.nio.ByteBuffer; 25 import java.nio.ByteBuffer;
24 26
27 +import static org.onlab.packet.PacketUtils.checkInput;
28 +
25 /** 29 /**
26 * Implements IPv6 Encapsulating Security Payload (ESP) extension header format. 30 * Implements IPv6 Encapsulating Security Payload (ESP) extension header format.
27 * (RFC 4303) 31 * (RFC 4303)
...@@ -158,4 +162,27 @@ public class EncapSecurityPayload extends BasePacket { ...@@ -158,4 +162,27 @@ public class EncapSecurityPayload extends BasePacket {
158 } 162 }
159 return true; 163 return true;
160 } 164 }
165 +
166 + /**
167 + * Deserializer function for encapsulated security payload headers.
168 + *
169 + * @return deserializer function
170 + */
171 + public static Deserializer<EncapSecurityPayload> deserializer() {
172 + return (data, offset, length) -> {
173 + checkInput(data, offset, length, HEADER_LENGTH);
174 +
175 + EncapSecurityPayload encapSecurityPayload = new EncapSecurityPayload();
176 +
177 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
178 + encapSecurityPayload.securityParamIndex = bb.getInt();
179 + encapSecurityPayload.sequence = bb.getInt();
180 +
181 + encapSecurityPayload.payload = Data.deserializer().deserialize(
182 + data, bb.position(), bb.limit() - bb.position());
183 + encapSecurityPayload.payload.setParent(encapSecurityPayload);
184 +
185 + return encapSecurityPayload;
186 + };
187 + }
161 } 188 }
......
...@@ -18,11 +18,15 @@ package org.onlab.packet.ipv6; ...@@ -18,11 +18,15 @@ package org.onlab.packet.ipv6;
18 18
19 import org.onlab.packet.BasePacket; 19 import org.onlab.packet.BasePacket;
20 import org.onlab.packet.Data; 20 import org.onlab.packet.Data;
21 +import org.onlab.packet.DeserializationException;
22 +import org.onlab.packet.Deserializer;
21 import org.onlab.packet.IPacket; 23 import org.onlab.packet.IPacket;
22 import org.onlab.packet.IPv6; 24 import org.onlab.packet.IPv6;
23 25
24 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
25 27
28 +import static org.onlab.packet.PacketUtils.checkInput;
29 +
26 /** 30 /**
27 * Implements IPv6 fragment extension header format. (RFC 2460) 31 * Implements IPv6 fragment extension header format. (RFC 2460)
28 */ 32 */
...@@ -149,22 +153,19 @@ public class Fragment extends BasePacket implements IExtensionHeader { ...@@ -149,22 +153,19 @@ public class Fragment extends BasePacket implements IExtensionHeader {
149 this.moreFragment = (byte) (sscratch & 0x1); 153 this.moreFragment = (byte) (sscratch & 0x1);
150 this.identification = bb.getInt(); 154 this.identification = bb.getInt();
151 155
152 - IPacket payload; 156 + Deserializer<? extends IPacket> deserializer;
153 - if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) { 157 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
154 - final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP 158 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
155 - .get(this.nextHeader);
156 - try {
157 - payload = clazz.newInstance();
158 - } catch (final Exception e) {
159 - throw new RuntimeException(
160 - "Error parsing payload for Fragment packet", e);
161 - }
162 } else { 159 } else {
163 - payload = new Data(); 160 + deserializer = Data.deserializer();
164 } 161 }
165 - this.payload = payload.deserialize(data, bb.position(), 162 + try {
163 + this.payload = deserializer.deserialize(data, bb.position(),
166 bb.limit() - bb.position()); 164 bb.limit() - bb.position());
167 this.payload.setParent(this); 165 this.payload.setParent(this);
166 + } catch (DeserializationException e) {
167 + return this;
168 + }
168 169
169 return this; 170 return this;
170 } 171 }
...@@ -216,4 +217,37 @@ public class Fragment extends BasePacket implements IExtensionHeader { ...@@ -216,4 +217,37 @@ public class Fragment extends BasePacket implements IExtensionHeader {
216 } 217 }
217 return true; 218 return true;
218 } 219 }
220 +
221 + /**
222 + * Deserializer function for fragment headers.
223 + *
224 + * @return deserializer function
225 + */
226 + public static Deserializer<Fragment> deserializer() {
227 + return (data, offset, length) -> {
228 + checkInput(data, offset, length, HEADER_LENGTH);
229 +
230 + Fragment fragment = new Fragment();
231 +
232 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
233 + fragment.nextHeader = bb.get();
234 + bb.get();
235 + short sscratch = bb.getShort();
236 + fragment.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
237 + fragment.moreFragment = (byte) (sscratch & 0x1);
238 + fragment.identification = bb.getInt();
239 +
240 + Deserializer<? extends IPacket> deserializer;
241 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(fragment.nextHeader)) {
242 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(fragment.nextHeader);
243 + } else {
244 + deserializer = Data.deserializer();
245 + }
246 + fragment.payload = deserializer.deserialize(data, bb.position(),
247 + bb.limit() - bb.position());
248 + fragment.payload.setParent(fragment);
249 +
250 + return fragment;
251 + };
252 + }
219 } 253 }
......
...@@ -18,12 +18,17 @@ package org.onlab.packet.ipv6; ...@@ -18,12 +18,17 @@ package org.onlab.packet.ipv6;
18 18
19 import org.onlab.packet.BasePacket; 19 import org.onlab.packet.BasePacket;
20 import org.onlab.packet.Data; 20 import org.onlab.packet.Data;
21 +import org.onlab.packet.DeserializationException;
22 +import org.onlab.packet.Deserializer;
21 import org.onlab.packet.IPacket; 23 import org.onlab.packet.IPacket;
22 import org.onlab.packet.IPv6; 24 import org.onlab.packet.IPv6;
23 25
24 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
25 import java.util.Arrays; 27 import java.util.Arrays;
26 28
29 +import static org.onlab.packet.PacketUtils.checkHeaderLength;
30 +import static org.onlab.packet.PacketUtils.checkInput;
31 +
27 /** 32 /**
28 * Implements IPv6 routing extension header format. (RFC 2460) 33 * Implements IPv6 routing extension header format. (RFC 2460)
29 */ 34 */
...@@ -175,22 +180,19 @@ public class Routing extends BasePacket implements IExtensionHeader { ...@@ -175,22 +180,19 @@ public class Routing extends BasePacket implements IExtensionHeader {
175 this.routingData = new byte[dataLength]; 180 this.routingData = new byte[dataLength];
176 bb.get(this.routingData, 0, dataLength); 181 bb.get(this.routingData, 0, dataLength);
177 182
178 - IPacket payload; 183 + Deserializer<? extends IPacket> deserializer;
179 - if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) { 184 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
180 - final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP 185 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
181 - .get(this.nextHeader);
182 - try {
183 - payload = clazz.newInstance();
184 - } catch (final Exception e) {
185 - throw new RuntimeException(
186 - "Error parsing payload for Routing packet", e);
187 - }
188 } else { 186 } else {
189 - payload = new Data(); 187 + deserializer = new Data().deserializer();
190 } 188 }
191 - this.payload = payload.deserialize(data, bb.position(), 189 + try {
190 + this.payload = deserializer.deserialize(data, bb.position(),
192 bb.limit() - bb.position()); 191 bb.limit() - bb.position());
193 this.payload.setParent(this); 192 this.payload.setParent(this);
193 + } catch (DeserializationException e) {
194 + return this;
195 + }
194 196
195 return this; 197 return this;
196 } 198 }
...@@ -248,4 +250,42 @@ public class Routing extends BasePacket implements IExtensionHeader { ...@@ -248,4 +250,42 @@ public class Routing extends BasePacket implements IExtensionHeader {
248 } 250 }
249 return true; 251 return true;
250 } 252 }
253 +
254 + /**
255 + * Deserializer function for routing headers.
256 + *
257 + * @return deserializer function
258 + */
259 + public static Deserializer<Routing> deserializer() {
260 + return (data, offset, length) -> {
261 + checkInput(data, offset, length, FIXED_HEADER_LENGTH);
262 +
263 + Routing routing = new Routing();
264 +
265 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
266 + routing.nextHeader = bb.get();
267 + routing.headerExtLength = bb.get();
268 + routing.routingType = bb.get();
269 + routing.segmentsLeft = bb.get();
270 + int dataLength =
271 + FIXED_ROUTING_DATA_LENGTH + LENGTH_UNIT * routing.headerExtLength;
272 +
273 + checkHeaderLength(bb.remaining(), dataLength);
274 +
275 + routing.routingData = new byte[dataLength];
276 + bb.get(routing.routingData, 0, dataLength);
277 +
278 + Deserializer<? extends IPacket> deserializer;
279 + if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(routing.nextHeader)) {
280 + deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(routing.nextHeader);
281 + } else {
282 + deserializer = new Data().deserializer();
283 + }
284 + routing.payload = deserializer.deserialize(data, bb.position(),
285 + bb.limit() - bb.position());
286 + routing.payload.setParent(routing);
287 +
288 + return routing;
289 + };
290 + }
251 } 291 }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onlab.packet.ndp; 16 package org.onlab.packet.ndp;
17 17
18 import org.onlab.packet.BasePacket; 18 import org.onlab.packet.BasePacket;
19 +import org.onlab.packet.Deserializer;
19 import org.onlab.packet.IPacket; 20 import org.onlab.packet.IPacket;
20 import org.onlab.packet.Ip6Address; 21 import org.onlab.packet.Ip6Address;
21 22
...@@ -23,6 +24,8 @@ import java.nio.ByteBuffer; ...@@ -23,6 +24,8 @@ import java.nio.ByteBuffer;
23 import java.util.Arrays; 24 import java.util.Arrays;
24 import java.util.List; 25 import java.util.List;
25 26
27 +import static org.onlab.packet.PacketUtils.checkInput;
28 +
26 /** 29 /**
27 * Implements ICMPv6 Neighbor Advertisement packet format (RFC 4861). 30 * Implements ICMPv6 Neighbor Advertisement packet format (RFC 4861).
28 */ 31 */
...@@ -238,4 +241,36 @@ public class NeighborAdvertisement extends BasePacket { ...@@ -238,4 +241,36 @@ public class NeighborAdvertisement extends BasePacket {
238 } 241 }
239 return true; 242 return true;
240 } 243 }
244 +
245 + /**
246 + * Deserializer function for neighbor advertisement packets.
247 + *
248 + * @return deserializer function
249 + */
250 + public static Deserializer<NeighborAdvertisement> deserializer() {
251 + return (data, offset, length) -> {
252 + checkInput(data, offset, length, HEADER_LENGTH);
253 +
254 + NeighborAdvertisement neighborAdvertisement = new NeighborAdvertisement();
255 +
256 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
257 +
258 + int iscratch;
259 +
260 + iscratch = bb.getInt();
261 + neighborAdvertisement.routerFlag = (byte) (iscratch >> 31 & 0x1);
262 + neighborAdvertisement.solicitedFlag = (byte) (iscratch >> 30 & 0x1);
263 + neighborAdvertisement.overrideFlag = (byte) (iscratch >> 29 & 0x1);
264 + bb.get(neighborAdvertisement.targetAddress, 0, Ip6Address.BYTE_LENGTH);
265 +
266 + NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
267 + .deserialize(data, bb.position(), bb.limit() - bb.position());
268 +
269 + for (NeighborDiscoveryOptions.Option option : options.options()) {
270 + neighborAdvertisement.addOption(option.type(), option.data());
271 + }
272 +
273 + return neighborAdvertisement;
274 + };
275 + }
241 } 276 }
......
...@@ -15,13 +15,17 @@ ...@@ -15,13 +15,17 @@
15 */ 15 */
16 package org.onlab.packet.ndp; 16 package org.onlab.packet.ndp;
17 17
18 +import org.onlab.packet.BasePacket;
19 +import org.onlab.packet.DeserializationException;
20 +import org.onlab.packet.Deserializer;
21 +import org.onlab.packet.IPacket;
22 +
18 import java.nio.ByteBuffer; 23 import java.nio.ByteBuffer;
19 import java.util.ArrayList; 24 import java.util.ArrayList;
20 import java.util.Arrays; 25 import java.util.Arrays;
21 import java.util.List; 26 import java.util.List;
22 27
23 -import org.onlab.packet.BasePacket; 28 +import static org.onlab.packet.PacketUtils.checkInput;
24 -import org.onlab.packet.IPacket;
25 29
26 /** 30 /**
27 * Neighbor Discovery Protocol packet options. 31 * Neighbor Discovery Protocol packet options.
...@@ -33,6 +37,11 @@ public class NeighborDiscoveryOptions extends BasePacket { ...@@ -33,6 +37,11 @@ public class NeighborDiscoveryOptions extends BasePacket {
33 public static final byte TYPE_REDIRECTED_HEADER = 4; 37 public static final byte TYPE_REDIRECTED_HEADER = 4;
34 public static final byte TYPE_MTU = 5; 38 public static final byte TYPE_MTU = 5;
35 39
40 + public static final byte INITIAL_HEADER_REQUIRED = 2;
41 +
42 + private static final String BUFFER_UNDERFLOW_ERROR =
43 + "Not enough bytes in buffer to read option";
44 +
36 private final List<Option> options = new ArrayList<>(); 45 private final List<Option> options = new ArrayList<>();
37 46
38 /** 47 /**
...@@ -229,4 +238,44 @@ public class NeighborDiscoveryOptions extends BasePacket { ...@@ -229,4 +238,44 @@ public class NeighborDiscoveryOptions extends BasePacket {
229 } 238 }
230 return false; 239 return false;
231 } 240 }
241 +
242 + public static Deserializer<NeighborDiscoveryOptions> deserializer() {
243 + return (data, offset, length) -> {
244 + checkInput(data, offset, length, INITIAL_HEADER_REQUIRED);
245 +
246 + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
247 +
248 + NeighborDiscoveryOptions ndo = new NeighborDiscoveryOptions();
249 +
250 + ndo.options.clear();
251 +
252 + //
253 + // Deserialize all options
254 + //
255 + while (bb.hasRemaining()) {
256 + byte type = bb.get();
257 + if (!bb.hasRemaining()) {
258 + throw new DeserializationException(BUFFER_UNDERFLOW_ERROR);
259 + }
260 + byte lengthField = bb.get();
261 + int dataLength = lengthField * 8; // The data length field is in
262 + // unit of 8 octets
263 +
264 + // Exclude the type and length fields
265 + if (dataLength < 2) {
266 + break;
267 + }
268 + dataLength -= 2;
269 +
270 + if (bb.remaining() < dataLength) {
271 + throw new DeserializationException(BUFFER_UNDERFLOW_ERROR);
272 + }
273 + byte[] optionData = new byte[dataLength];
274 + bb.get(optionData, 0, optionData.length);
275 + ndo.addOption(type, optionData);
276 + }
277 +
278 + return ndo;
279 + };
280 + }
232 } 281 }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onlab.packet.ndp; 16 package org.onlab.packet.ndp;
17 17
18 import org.onlab.packet.BasePacket; 18 import org.onlab.packet.BasePacket;
19 +import org.onlab.packet.Deserializer;
19 import org.onlab.packet.IPacket; 20 import org.onlab.packet.IPacket;
20 import org.onlab.packet.Ip6Address; 21 import org.onlab.packet.Ip6Address;
21 22
...@@ -23,6 +24,8 @@ import java.nio.ByteBuffer; ...@@ -23,6 +24,8 @@ import java.nio.ByteBuffer;
23 import java.util.Arrays; 24 import java.util.Arrays;
24 import java.util.List; 25 import java.util.List;
25 26
27 +import static org.onlab.packet.PacketUtils.checkInput;
28 +
26 /** 29 /**
27 * Implements ICMPv6 Neighbor Solicitation packet format. (RFC 4861) 30 * Implements ICMPv6 Neighbor Solicitation packet format. (RFC 4861)
28 */ 31 */
...@@ -157,4 +160,31 @@ public class NeighborSolicitation extends BasePacket { ...@@ -157,4 +160,31 @@ public class NeighborSolicitation extends BasePacket {
157 } 160 }
158 return true; 161 return true;
159 } 162 }
163 +
164 + /**
165 + * Deserializer function for neighbor solicitation packets.
166 + *
167 + * @return deserializer function
168 + */
169 + public static Deserializer<NeighborSolicitation> deserializer() {
170 + return (data, offset, length) -> {
171 + checkInput(data, offset, length, HEADER_LENGTH);
172 +
173 + NeighborSolicitation neighborSolicitation = new NeighborSolicitation();
174 +
175 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
176 +
177 + bb.getInt();
178 + bb.get(neighborSolicitation.targetAddress, 0, Ip6Address.BYTE_LENGTH);
179 +
180 + NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
181 + .deserialize(data, bb.position(), bb.limit() - bb.position());
182 +
183 + for (NeighborDiscoveryOptions.Option option : options.options()) {
184 + neighborSolicitation.addOption(option.type(), option.data());
185 + }
186 +
187 + return neighborSolicitation;
188 + };
189 + }
160 } 190 }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onlab.packet.ndp; 16 package org.onlab.packet.ndp;
17 17
18 import org.onlab.packet.BasePacket; 18 import org.onlab.packet.BasePacket;
19 +import org.onlab.packet.Deserializer;
19 import org.onlab.packet.IPacket; 20 import org.onlab.packet.IPacket;
20 import org.onlab.packet.Ip6Address; 21 import org.onlab.packet.Ip6Address;
21 22
...@@ -23,6 +24,8 @@ import java.nio.ByteBuffer; ...@@ -23,6 +24,8 @@ import java.nio.ByteBuffer;
23 import java.util.Arrays; 24 import java.util.Arrays;
24 import java.util.List; 25 import java.util.List;
25 26
27 +import static org.onlab.packet.PacketUtils.checkInput;
28 +
26 /** 29 /**
27 * Implements ICMPv6 Redirect packet format. (RFC 4861) 30 * Implements ICMPv6 Redirect packet format. (RFC 4861)
28 */ 31 */
...@@ -188,4 +191,33 @@ public class Redirect extends BasePacket { ...@@ -188,4 +191,33 @@ public class Redirect extends BasePacket {
188 } 191 }
189 return true; 192 return true;
190 } 193 }
194 +
195 + /**
196 + * Deserializer function for redirect packets.
197 + *
198 + * @return deserializer function
199 + */
200 + public static Deserializer<Redirect> deserializer() {
201 + return (data, offset, length) -> {
202 + checkInput(data, offset, length, HEADER_LENGTH);
203 +
204 + Redirect redirect = new Redirect();
205 +
206 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
207 +
208 + bb.getInt();
209 +
210 + bb.get(redirect.targetAddress, 0, Ip6Address.BYTE_LENGTH);
211 + bb.get(redirect.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
212 +
213 + NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
214 + .deserialize(data, bb.position(), bb.limit() - bb.position());
215 +
216 + for (NeighborDiscoveryOptions.Option option : options.options()) {
217 + redirect.addOption(option.type(), option.data());
218 + }
219 +
220 + return redirect;
221 + };
222 + }
191 } 223 }
......
...@@ -16,11 +16,14 @@ ...@@ -16,11 +16,14 @@
16 package org.onlab.packet.ndp; 16 package org.onlab.packet.ndp;
17 17
18 import org.onlab.packet.BasePacket; 18 import org.onlab.packet.BasePacket;
19 +import org.onlab.packet.Deserializer;
19 import org.onlab.packet.IPacket; 20 import org.onlab.packet.IPacket;
20 21
21 import java.nio.ByteBuffer; 22 import java.nio.ByteBuffer;
22 import java.util.List; 23 import java.util.List;
23 24
25 +import static org.onlab.packet.PacketUtils.checkInput;
26 +
24 /** 27 /**
25 * Implements ICMPv6 Router Advertisement packet format. (RFC 4861) 28 * Implements ICMPv6 Router Advertisement packet format. (RFC 4861)
26 */ 29 */
...@@ -284,4 +287,37 @@ public class RouterAdvertisement extends BasePacket { ...@@ -284,4 +287,37 @@ public class RouterAdvertisement extends BasePacket {
284 } 287 }
285 return true; 288 return true;
286 } 289 }
290 +
291 + /**
292 + * Deserializer function for router advertisement packets.
293 + *
294 + * @return deserializer function
295 + */
296 + public static Deserializer<RouterAdvertisement> deserializer() {
297 + return (data, offset, length) -> {
298 + checkInput(data, offset, length, HEADER_LENGTH);
299 +
300 + RouterAdvertisement routerAdvertisement = new RouterAdvertisement();
301 +
302 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
303 + int bscratch;
304 +
305 + routerAdvertisement.currentHopLimit = bb.get();
306 + bscratch = bb.get();
307 + routerAdvertisement.mFlag = (byte) ((bscratch >> 7) & 0x1);
308 + routerAdvertisement.oFlag = (byte) ((bscratch >> 6) & 0x1);
309 + routerAdvertisement.routerLifetime = bb.getShort();
310 + routerAdvertisement.reachableTime = bb.getInt();
311 + routerAdvertisement.retransmitTimer = bb.getInt();
312 +
313 + NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
314 + .deserialize(data, bb.position(), bb.limit() - bb.position());
315 +
316 + for (NeighborDiscoveryOptions.Option option : options.options()) {
317 + routerAdvertisement.addOption(option.type(), option.data());
318 + }
319 +
320 + return routerAdvertisement;
321 + };
322 + }
287 } 323 }
......
...@@ -16,19 +16,21 @@ ...@@ -16,19 +16,21 @@
16 package org.onlab.packet.ndp; 16 package org.onlab.packet.ndp;
17 17
18 import org.onlab.packet.BasePacket; 18 import org.onlab.packet.BasePacket;
19 +import org.onlab.packet.Deserializer;
19 import org.onlab.packet.IPacket; 20 import org.onlab.packet.IPacket;
20 21
21 import java.nio.ByteBuffer; 22 import java.nio.ByteBuffer;
22 import java.util.List; 23 import java.util.List;
23 24
25 +import static org.onlab.packet.PacketUtils.checkInput;
26 +
24 /** 27 /**
25 * Implements ICMPv6 Router Solicitation packet format. (RFC 4861) 28 * Implements ICMPv6 Router Solicitation packet format. (RFC 4861)
26 */ 29 */
27 public class RouterSolicitation extends BasePacket { 30 public class RouterSolicitation extends BasePacket {
28 public static final byte HEADER_LENGTH = 4; // bytes 31 public static final byte HEADER_LENGTH = 4; // bytes
29 32
30 - private final NeighborDiscoveryOptions options = 33 + private final NeighborDiscoveryOptions options = new NeighborDiscoveryOptions();
31 - new NeighborDiscoveryOptions();
32 34
33 /** 35 /**
34 * Gets the Neighbor Discovery Protocol packet options. 36 * Gets the Neighbor Discovery Protocol packet options.
...@@ -122,4 +124,30 @@ public class RouterSolicitation extends BasePacket { ...@@ -122,4 +124,30 @@ public class RouterSolicitation extends BasePacket {
122 } 124 }
123 return true; 125 return true;
124 } 126 }
127 +
128 + /**
129 + * Deserializer function for router solicitation packets.
130 + *
131 + * @return deserializer function
132 + */
133 + public static Deserializer<RouterSolicitation> deserializer() {
134 + return (data, offset, length) -> {
135 + checkInput(data, offset, length, HEADER_LENGTH);
136 +
137 + RouterSolicitation routerSolicitation = new RouterSolicitation();
138 +
139 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
140 +
141 + bb.getInt();
142 +
143 + NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
144 + .deserialize(data, bb.position(), bb.limit() - bb.position());
145 +
146 + for (NeighborDiscoveryOptions.Option option : options.options()) {
147 + routerSolicitation.addOption(option.type(), option.data());
148 + }
149 +
150 + return routerSolicitation;
151 + };
152 + }
125 } 153 }
......
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +
22 +import java.nio.ByteBuffer;
23 +import java.util.Arrays;
24 +
25 +import static org.junit.Assert.assertEquals;
26 +import static org.junit.Assert.assertTrue;
27 +
28 +/**
29 + * Unit tests for the ARP class.
30 + */
31 +public class ArpTest {
32 +
33 + private Deserializer<ARP> deserializer = ARP.deserializer();
34 +
35 + private final byte hwAddressLength = 6;
36 + private final byte protoAddressLength = 4;
37 +
38 + private MacAddress srcMac = MacAddress.valueOf(1);
39 + private MacAddress targetMac = MacAddress.valueOf(2);
40 + private Ip4Address srcIp = Ip4Address.valueOf(1);
41 + private Ip4Address targetIp = Ip4Address.valueOf(2);
42 +
43 + private byte[] byteHeader;
44 +
45 + @Before
46 + public void setUp() {
47 + ByteBuffer bb = ByteBuffer.allocate(ARP.INITIAL_HEADER_LENGTH +
48 + 2 * hwAddressLength + 2 * protoAddressLength);
49 + bb.putShort(ARP.HW_TYPE_ETHERNET);
50 + bb.putShort(ARP.PROTO_TYPE_IP);
51 + bb.put(hwAddressLength);
52 + bb.put(protoAddressLength);
53 + bb.putShort(ARP.OP_REPLY);
54 +
55 + bb.put(srcMac.toBytes());
56 + bb.put(srcIp.toOctets());
57 + bb.put(targetMac.toBytes());
58 + bb.put(targetIp.toOctets());
59 +
60 + byteHeader = bb.array();
61 + }
62 +
63 + @Test
64 + public void testDeserializeBadInput() throws Exception {
65 + PacketTestUtils.testDeserializeBadInput(deserializer);
66 + }
67 +
68 + @Test
69 + public void testDeserializeTruncated() throws Exception {
70 + PacketTestUtils.testDeserializeTruncated(deserializer, byteHeader);
71 + }
72 +
73 + @Test
74 + public void testDeserialize() throws Exception {
75 + ARP arp = deserializer.deserialize(byteHeader, 0, byteHeader.length);
76 +
77 + assertEquals(ARP.HW_TYPE_ETHERNET, arp.getHardwareType());
78 + assertEquals(ARP.PROTO_TYPE_IP, arp.getProtocolType());
79 + assertEquals(hwAddressLength, arp.getHardwareAddressLength());
80 + assertEquals(protoAddressLength, arp.getProtocolAddressLength());
81 + assertEquals(ARP.OP_REPLY, arp.getOpCode());
82 +
83 + assertTrue(Arrays.equals(srcMac.toBytes(), arp.getSenderHardwareAddress()));
84 + assertTrue(Arrays.equals(srcIp.toOctets(), arp.getSenderProtocolAddress()));
85 + assertTrue(Arrays.equals(targetMac.toBytes(), arp.getTargetHardwareAddress()));
86 + assertTrue(Arrays.equals(targetIp.toOctets(), arp.getTargetProtocolAddress()));
87 + }
88 +}
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import com.google.common.base.Charsets;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +
23 +import java.nio.ByteBuffer;
24 +import java.util.Arrays;
25 +
26 +import static org.junit.Assert.assertEquals;
27 +import static org.junit.Assert.assertTrue;
28 +
29 +/**
30 + * Unit tests for DHCP class.
31 + */
32 +public class DhcpTest {
33 +
34 + private Deserializer<DHCP> deserializer = DHCP.deserializer();
35 +
36 + private byte opCode = 1;
37 + private byte hardwareType = 1;
38 + private byte hardwareAddressLength = Ethernet.DATALAYER_ADDRESS_LENGTH;
39 + private byte hops = 0;
40 + private int transactionId = 0x2ed4eb50;
41 + private short seconds = 0;
42 + private short flags = 0;
43 + private int clientIpAddress = 1;
44 + private int yourIpAddress = 2;
45 + private int serverIpAddress = 3;
46 + private int gatewayIpAddress = 4;
47 + private byte[] clientHardwareAddress = MacAddress.valueOf(500).toBytes();
48 + private String serverName = "test-server";
49 + private String bootFileName = "test-file";
50 +
51 + private String hostName = "test-host";
52 + private DHCPOption hostNameOption = new DHCPOption();
53 +
54 + private byte[] byteHeader;
55 +
56 + @Before
57 + public void setUp() {
58 + hostNameOption.setCode((byte) 55);
59 + hostNameOption.setLength((byte) hostName.length());
60 + hostNameOption.setData(hostName.getBytes(Charsets.US_ASCII));
61 +
62 + // Packet length is the fixed DHCP header plus option length plus an
63 + // extra byte to indicate 'end of options'.
64 + ByteBuffer bb = ByteBuffer.allocate(DHCP.MIN_HEADER_LENGTH +
65 + 2 + hostNameOption.getLength() + 1);
66 +
67 + bb.put(opCode);
68 + bb.put(hardwareType);
69 + bb.put(hardwareAddressLength);
70 + bb.put(hops);
71 + bb.putInt(transactionId);
72 + bb.putShort(seconds);
73 + bb.putShort(flags);
74 + bb.putInt(clientIpAddress);
75 + bb.putInt(yourIpAddress);
76 + bb.putInt(serverIpAddress);
77 + bb.putInt(gatewayIpAddress);
78 + bb.put(clientHardwareAddress);
79 +
80 + // need 16 bytes of zeros to pad out the client hardware address field
81 + bb.put(new byte[16 - hardwareAddressLength]);
82 +
83 + // Put server name and pad out to 64 bytes
84 + bb.put(serverName.getBytes(Charsets.US_ASCII));
85 + bb.put(new byte[64 - serverName.length()]);
86 +
87 + // Put boot file name and pad out to 128 bytes
88 + bb.put(bootFileName.getBytes(Charsets.US_ASCII));
89 + bb.put(new byte[128 - bootFileName.length()]);
90 +
91 + // Magic cookie
92 + bb.put("DHCP".getBytes(Charsets.US_ASCII));
93 +
94 + bb.put(hostNameOption.getCode());
95 + bb.put(hostNameOption.getLength());
96 + bb.put(hostNameOption.getData());
97 +
98 + // End of options marker
99 + bb.put((byte) (0xff & 255));
100 +
101 + byteHeader = bb.array();
102 + }
103 +
104 + @Test
105 + public void testDeserializeBadInput() throws Exception {
106 + PacketTestUtils.testDeserializeBadInput(deserializer);
107 + }
108 +
109 + @Test
110 + public void testDeserializeTruncated() throws Exception {
111 + PacketTestUtils.testDeserializeTruncated(deserializer, byteHeader);
112 + }
113 +
114 + @Test
115 + public void testDeserialize() throws Exception {
116 + DHCP dhcp = deserializer.deserialize(byteHeader, 0, byteHeader.length);
117 +
118 + assertEquals(opCode, dhcp.opCode);
119 + assertEquals(hardwareType, dhcp.hardwareType);
120 + assertEquals(hardwareAddressLength, dhcp.hardwareAddressLength);
121 + assertEquals(hops, dhcp.hops);
122 + assertEquals(transactionId, dhcp.transactionId);
123 + assertEquals(seconds, dhcp.seconds);
124 + assertEquals(flags, dhcp.flags);
125 + assertEquals(clientIpAddress, dhcp.clientIPAddress);
126 + assertEquals(yourIpAddress, dhcp.yourIPAddress);
127 + assertEquals(serverIpAddress, dhcp.serverIPAddress);
128 + assertEquals(gatewayIpAddress, dhcp.gatewayIPAddress);
129 + assertTrue(Arrays.equals(clientHardwareAddress, dhcp.clientHardwareAddress));
130 +
131 + assertEquals(serverName, dhcp.serverName);
132 + assertEquals(bootFileName, dhcp.bootFileName);
133 + assertEquals(1, dhcp.options.size());
134 + assertEquals(hostNameOption, dhcp.options.get(0));
135 + }
136 +
137 +}
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +
22 +import java.nio.ByteBuffer;
23 +
24 +import static org.junit.Assert.assertEquals;
25 +
26 +/**
27 + * Unit tests for the Ethernet class.
28 + */
29 +public class EthernetTest {
30 +
31 + private MacAddress dstMac;
32 + private MacAddress srcMac;
33 + private short ethertype = 6;
34 + private short vlan = 5;
35 +
36 + private Deserializer<Ethernet> deserializer;
37 +
38 + private byte[] byteHeader;
39 + private byte[] vlanByteHeader;
40 +
41 + @Before
42 + public void setUp() {
43 + deserializer = Ethernet.deserializer();
44 +
45 + byte[] dstMacBytes = {
46 + (byte) 0x88, (byte) 0x88, (byte) 0x88, (byte) 0x88, (byte) 0x88,
47 + (byte) 0x88 };
48 + dstMac = MacAddress.valueOf(dstMacBytes);
49 + byte[] srcMacBytes = {
50 + (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa,
51 + (byte) 0xaa };
52 + srcMac = MacAddress.valueOf(srcMacBytes);
53 +
54 + // Create Ethernet byte array with no VLAN header
55 + ByteBuffer bb = ByteBuffer.allocate(Ethernet.ETHERNET_HEADER_LENGTH);
56 + bb.put(dstMacBytes);
57 + bb.put(srcMacBytes);
58 + bb.putShort(ethertype);
59 +
60 + byteHeader = bb.array();
61 +
62 + // Create Ethernet byte array with a VLAN header
63 + bb = ByteBuffer.allocate(Ethernet.ETHERNET_HEADER_LENGTH + Ethernet.VLAN_HEADER_LENGTH);
64 + bb.put(dstMacBytes);
65 + bb.put(srcMacBytes);
66 + bb.putShort(Ethernet.TYPE_VLAN);
67 + bb.putShort(vlan);
68 + bb.putShort(ethertype);
69 +
70 + vlanByteHeader = bb.array();
71 + }
72 +
73 + @Test
74 + public void testDeserializeBadInput() throws Exception {
75 + PacketTestUtils.testDeserializeBadInput(deserializer);
76 + }
77 +
78 + @Test
79 + public void testDeserializeTruncated() throws DeserializationException {
80 + PacketTestUtils.testDeserializeTruncated(deserializer, vlanByteHeader);
81 + }
82 +
83 + @Test
84 + public void testDeserializeNoVlan() throws Exception {
85 + Ethernet eth = deserializer.deserialize(byteHeader, 0, byteHeader.length);
86 +
87 + assertEquals(dstMac, eth.getDestinationMAC());
88 + assertEquals(srcMac, eth.getSourceMAC());
89 + assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
90 + assertEquals(ethertype, eth.getEtherType());
91 + }
92 +
93 + @Test
94 + public void testDeserializeWithVlan() throws Exception {
95 + Ethernet eth = deserializer.deserialize(vlanByteHeader, 0, vlanByteHeader.length);
96 +
97 + assertEquals(dstMac, eth.getDestinationMAC());
98 + assertEquals(srcMac, eth.getSourceMAC());
99 + assertEquals(vlan, eth.getVlanID());
100 + assertEquals(ethertype, eth.getEtherType());
101 + }
102 +
103 +}
...@@ -67,13 +67,22 @@ public class ICMP6Test { ...@@ -67,13 +67,22 @@ public class ICMP6Test {
67 assertArrayEquals(bytePacket, icmp6.serialize()); 67 assertArrayEquals(bytePacket, icmp6.serialize());
68 } 68 }
69 69
70 + @Test
71 + public void testDeserializeBadInput() throws Exception {
72 + PacketTestUtils.testDeserializeBadInput(ICMP6.deserializer());
73 + }
74 +
75 + @Test
76 + public void testDeserializeTruncated() throws Exception {
77 + PacketTestUtils.testDeserializeTruncated(ICMP6.deserializer(), bytePacket);
78 + }
79 +
70 /** 80 /**
71 * Tests deserialize and getters. 81 * Tests deserialize and getters.
72 */ 82 */
73 @Test 83 @Test
74 - public void testDeserialize() { 84 + public void testDeserialize() throws Exception {
75 - ICMP6 icmp6 = new ICMP6(); 85 + ICMP6 icmp6 = ICMP6.deserializer().deserialize(bytePacket, 0, bytePacket.length);
76 - icmp6.deserialize(bytePacket, 0, bytePacket.length);
77 86
78 assertThat(icmp6.getIcmpType(), is(ICMP6.ECHO_REQUEST)); 87 assertThat(icmp6.getIcmpType(), is(ICMP6.ECHO_REQUEST));
79 assertThat(icmp6.getIcmpCode(), is((byte) 0x00)); 88 assertThat(icmp6.getIcmpCode(), is((byte) 0x00));
......
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +
22 +import java.nio.ByteBuffer;
23 +
24 +import static org.junit.Assert.assertEquals;
25 +
26 +/**
27 + * Unit tests for the ICMP class.
28 + */
29 +public class ICMPTest {
30 +
31 + private Deserializer<ICMP> deserializer;
32 +
33 + private byte icmpType = ICMP.TYPE_ECHO_REQUEST;
34 + private byte icmpCode = 4;
35 + private short checksum = 870;
36 +
37 + private byte[] headerBytes;
38 +
39 + @Before
40 + public void setUp() throws Exception {
41 + deserializer = ICMP.deserializer();
42 +
43 + ByteBuffer bb = ByteBuffer.allocate(ICMP.ICMP_HEADER_LENGTH);
44 +
45 + bb.put(icmpType);
46 + bb.put(icmpCode);
47 + bb.putShort(checksum);
48 +
49 + headerBytes = bb.array();
50 + }
51 +
52 + @Test
53 + public void testDeserializeBadInput() throws Exception {
54 + PacketTestUtils.testDeserializeBadInput(deserializer);
55 + }
56 +
57 + @Test
58 + public void testDeserializeTruncated() throws Exception {
59 + PacketTestUtils.testDeserializeTruncated(deserializer, headerBytes);
60 + }
61 +
62 + @Test
63 + public void testDeserialize() throws Exception {
64 + ICMP icmp = deserializer.deserialize(headerBytes, 0, headerBytes.length);
65 +
66 + assertEquals(icmpType, icmp.getIcmpType());
67 + assertEquals(icmpCode, icmp.getIcmpCode());
68 + assertEquals(checksum, icmp.getChecksum());
69 + }
70 +}
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +
22 +import java.nio.ByteBuffer;
23 +
24 +import static org.junit.Assert.assertEquals;
25 +import static org.junit.Assert.assertTrue;
26 +
27 +/**
28 + * Unit tests for IPv4 class.
29 + */
30 +public class IPv4Test {
31 +
32 + private Deserializer<IPv4> deserializer;
33 +
34 + private byte version = 4;
35 + private byte headerLength = 6;
36 + private byte diffServ = 2;
37 + private short totalLength = 20;
38 + private short identification = 1;
39 + private byte flags = 1;
40 + private short fragmentOffset = 1;
41 + private byte ttl = 60;
42 + private byte protocol = 4;
43 + private short checksum = 4;
44 + private int sourceAddress = 1;
45 + private int destinationAddress = 2;
46 + private byte[] options = new byte[] {0x1, 0x2, 0x3, 0x4};
47 +
48 + private byte[] headerBytes;
49 +
50 + @Before
51 + public void setUp() throws Exception {
52 + deserializer = IPv4.deserializer();
53 +
54 + ByteBuffer bb = ByteBuffer.allocate(headerLength * 4);
55 +
56 + bb.put((byte) ((version & 0xf) << 4 | headerLength & 0xf));
57 + bb.put(diffServ);
58 + bb.putShort(totalLength);
59 + bb.putShort(identification);
60 + bb.putShort((short) ((flags & 0x7) << 13 | fragmentOffset & 0x1fff));
61 + bb.put(ttl);
62 + bb.put(protocol);
63 + bb.putShort(checksum);
64 + bb.putInt(sourceAddress);
65 + bb.putInt(destinationAddress);
66 + bb.put(options);
67 +
68 + headerBytes = bb.array();
69 + }
70 +
71 + @Test
72 + public void testDeserializeBadInput() throws Exception {
73 + PacketTestUtils.testDeserializeBadInput(deserializer);
74 + }
75 +
76 + @Test
77 + public void testDeserializeTruncated() throws Exception {
78 + PacketTestUtils.testDeserializeTruncated(deserializer, headerBytes);
79 + }
80 +
81 + @Test
82 + public void testDeserialize() throws Exception {
83 + IPv4 ipv4 = deserializer.deserialize(headerBytes, 0, headerBytes.length);
84 +
85 + assertEquals(version, ipv4.getVersion());
86 + assertEquals(headerLength, ipv4.getHeaderLength());
87 + assertEquals(diffServ, ipv4.getDiffServ());
88 + assertEquals(totalLength, ipv4.getTotalLength());
89 + assertEquals(identification, ipv4.getIdentification());
90 + assertEquals(flags, ipv4.getFlags());
91 + assertEquals(fragmentOffset, ipv4.getFragmentOffset());
92 + assertEquals(ttl, ipv4.getTtl());
93 + assertEquals(protocol, ipv4.getProtocol());
94 + assertEquals(checksum, ipv4.getChecksum());
95 + assertEquals(sourceAddress, ipv4.getSourceAddress());
96 + assertEquals(destinationAddress, ipv4.getDestinationAddress());
97 + assertTrue(ipv4.isTruncated());
98 + }
99 +}
...@@ -18,14 +18,17 @@ ...@@ -18,14 +18,17 @@
18 18
19 package org.onlab.packet; 19 package org.onlab.packet;
20 20
21 +import org.junit.Before;
21 import org.junit.BeforeClass; 22 import org.junit.BeforeClass;
22 import org.junit.Test; 23 import org.junit.Test;
23 24
25 +import java.nio.ByteBuffer;
26 +
24 import static org.hamcrest.Matchers.is; 27 import static org.hamcrest.Matchers.is;
25 -import static org.junit.Assert.assertThat;
26 import static org.junit.Assert.assertArrayEquals; 28 import static org.junit.Assert.assertArrayEquals;
27 -import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.assertFalse; 29 import static org.junit.Assert.assertFalse;
30 +import static org.junit.Assert.assertThat;
31 +import static org.junit.Assert.assertTrue;
29 32
30 /** 33 /**
31 * Tests for class {@link IPv6}. 34 * Tests for class {@link IPv6}.
...@@ -43,6 +46,8 @@ public class IPv6Test { ...@@ -43,6 +46,8 @@ public class IPv6Test {
43 private static UDP udp; 46 private static UDP udp;
44 private static byte[] bytePacket; 47 private static byte[] bytePacket;
45 48
49 + private Deserializer<IPv6> deserializer;
50 +
46 @BeforeClass 51 @BeforeClass
47 public static void setUpBeforeClass() throws Exception { 52 public static void setUpBeforeClass() throws Exception {
48 data = new Data(); 53 data = new Data();
...@@ -65,6 +70,11 @@ public class IPv6Test { ...@@ -65,6 +70,11 @@ public class IPv6Test {
65 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); 70 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
66 } 71 }
67 72
73 + @Before
74 + public void setUp() {
75 + deserializer = IPv6.deserializer();
76 + }
77 +
68 /** 78 /**
69 * Tests serialize and setters. 79 * Tests serialize and setters.
70 */ 80 */
...@@ -83,13 +93,26 @@ public class IPv6Test { ...@@ -83,13 +93,26 @@ public class IPv6Test {
83 assertArrayEquals(ipv6.serialize(), bytePacket); 93 assertArrayEquals(ipv6.serialize(), bytePacket);
84 } 94 }
85 95
96 + @Test
97 + public void testDeserializeBadInput() throws Exception {
98 + PacketTestUtils.testDeserializeBadInput(deserializer);
99 + }
100 +
101 + @Test
102 + public void testDeserializeTruncated() throws Exception {
103 + // Run the truncation test only on the IPv6 header
104 + byte[] ipv6Header = new byte[IPv6.FIXED_HEADER_LENGTH];
105 + ByteBuffer.wrap(bytePacket).get(ipv6Header);
106 +
107 + PacketTestUtils.testDeserializeTruncated(deserializer, ipv6Header);
108 + }
109 +
86 /** 110 /**
87 * Tests deserialize and getters. 111 * Tests deserialize and getters.
88 */ 112 */
89 @Test 113 @Test
90 - public void testDeserialize() { 114 + public void testDeserialize() throws DeserializationException {
91 - IPv6 ipv6 = new IPv6(); 115 + IPv6 ipv6 = deserializer.deserialize(bytePacket, 0, bytePacket.length);
92 - ipv6.deserialize(bytePacket, 0, bytePacket.length);
93 116
94 assertThat(ipv6.getVersion(), is((byte) 6)); 117 assertThat(ipv6.getVersion(), is((byte) 6));
95 assertThat(ipv6.getTrafficClass(), is((byte) 0x93)); 118 assertThat(ipv6.getTrafficClass(), is((byte) 0x93));
......
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +
22 +import java.nio.ByteBuffer;
23 +
24 +import static org.junit.Assert.assertEquals;
25 +
26 +/**
27 + * Unit tests for LLC class.
28 + */
29 +public class LLCTest {
30 +
31 + private Deserializer<LLC> deserializer;
32 +
33 + private byte dsap = 10;
34 + private byte ssap = 20;
35 + private byte ctrl = 30;
36 +
37 + private byte[] bytes;
38 +
39 + @Before
40 + public void setUp() throws Exception {
41 + deserializer = LLC.deserializer();
42 +
43 + ByteBuffer bb = ByteBuffer.allocate(LLC.LLC_HEADER_LENGTH);
44 +
45 + bb.put(dsap);
46 + bb.put(ssap);
47 + bb.put(ctrl);
48 +
49 + bytes = bb.array();
50 + }
51 +
52 + @Test
53 + public void testDeserializeBadInput() throws Exception {
54 + PacketTestUtils.testDeserializeBadInput(deserializer);
55 + }
56 +
57 + @Test
58 + public void testDeserializeTruncated() throws Exception {
59 + PacketTestUtils.testDeserializeTruncated(deserializer, bytes);
60 + }
61 +
62 + @Test
63 + public void testDeserialize() throws Exception {
64 + LLC llc = deserializer.deserialize(bytes, 0, bytes.length);
65 +
66 + assertEquals(dsap, llc.getDsap());
67 + assertEquals(ssap, llc.getSsap());
68 + assertEquals(ctrl, llc.getCtrl());
69 + }
70 +}
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +
22 +import java.nio.ByteBuffer;
23 +import java.util.Arrays;
24 +
25 +import static org.junit.Assert.assertEquals;
26 +import static org.junit.Assert.assertTrue;
27 +
28 +/**
29 + * Unit tests for the LLDP class.
30 + */
31 +public class LLDPTest {
32 +
33 + private Deserializer<LLDP> deserializer;
34 +
35 + private byte[] chassisValue = new byte[] {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
36 + private byte[] portValue = new byte[] {0x1, 0x2, 0x3, 0x4, 0x5};
37 + private byte[] ttlValue = new byte[] {0x0, 0x20};
38 +
39 + private short optionalTlvSize = 6;
40 + private byte[] optionalTlvValue = new byte[] {0x6, 0x5, 0x4, 0x3, 0x2, 0x1};
41 +
42 + private byte[] bytes;
43 +
44 + @Before
45 + public void setUp() throws Exception {
46 + deserializer = LLDP.deserializer();
47 +
48 + // Each TLV is 2 bytes for the type+length, plus the size of the value
49 + // There are 2 zero-bytes at the end
50 + ByteBuffer bb = ByteBuffer.allocate(2 + LLDP.CHASSIS_TLV_SIZE +
51 + 2 + LLDP.PORT_TLV_SIZE +
52 + 2 + LLDP.TTL_TLV_SIZE +
53 + 2 + optionalTlvSize +
54 + 2);
55 +
56 + // Chassis TLV
57 + bb.putShort(getTypeLength(LLDP.CHASSIS_TLV_TYPE, LLDP.CHASSIS_TLV_SIZE));
58 + bb.put(chassisValue);
59 +
60 + // Port TLV
61 + bb.putShort(getTypeLength(LLDP.PORT_TLV_TYPE, LLDP.PORT_TLV_SIZE));
62 + bb.put(portValue);
63 +
64 + // TTL TLV
65 + bb.putShort(getTypeLength(LLDP.TTL_TLV_TYPE, LLDP.TTL_TLV_SIZE));
66 + bb.put(ttlValue);
67 +
68 + // Optional TLV
69 + bb.putShort(getTypeLength(LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE, optionalTlvSize));
70 + bb.put(optionalTlvValue);
71 +
72 + bb.putShort((short) 0);
73 +
74 + bytes = bb.array();
75 +
76 + }
77 +
78 + private short getTypeLength(byte type, short length) {
79 + return (short) ((0x7f & type) << 9 | 0x1ff & length);
80 + }
81 +
82 + @Test
83 + public void testDeserializeBadInput() throws Exception {
84 + PacketTestUtils.testDeserializeBadInput(deserializer);
85 + }
86 +
87 + @Test
88 + public void testDeserializeTruncated() throws Exception {
89 + PacketTestUtils.testDeserializeTruncated(deserializer, bytes);
90 + }
91 +
92 + @Test
93 + public void testDeserialize() throws Exception {
94 + LLDP lldp = deserializer.deserialize(bytes, 0, bytes.length);
95 +
96 + assertEquals(LLDP.CHASSIS_TLV_TYPE, lldp.getChassisId().getType());
97 + assertEquals(LLDP.CHASSIS_TLV_SIZE, lldp.getChassisId().getLength());
98 + assertTrue(Arrays.equals(chassisValue, lldp.getChassisId().getValue()));
99 +
100 + assertEquals(LLDP.PORT_TLV_TYPE, lldp.getPortId().getType());
101 + assertEquals(LLDP.PORT_TLV_SIZE, lldp.getPortId().getLength());
102 + assertTrue(Arrays.equals(portValue, lldp.getPortId().getValue()));
103 +
104 + assertEquals(LLDP.TTL_TLV_TYPE, lldp.getTtl().getType());
105 + assertEquals(LLDP.TTL_TLV_SIZE, lldp.getTtl().getLength());
106 + assertTrue(Arrays.equals(ttlValue, lldp.getTtl().getValue()));
107 +
108 + assertEquals(1, lldp.getOptionalTLVList().size());
109 + LLDPTLV optionalTlv = lldp.getOptionalTLVList().get(0);
110 +
111 + assertEquals(LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE, optionalTlv.getType());
112 + assertEquals(optionalTlvSize, optionalTlv.getLength());
113 + assertTrue(Arrays.equals(optionalTlvValue, optionalTlv.getValue()));
114 + }
115 +}
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +
22 +import java.nio.ByteBuffer;
23 +import java.util.HashMap;
24 +
25 +import static org.junit.Assert.assertEquals;
26 +
27 +/**
28 + * Unit tests for MPLS class.
29 + */
30 +public class MplsTest {
31 +
32 + private Deserializer<MPLS> deserializer;
33 +
34 + private int label = 1048575;
35 + private byte bos = 1;
36 + private byte ttl = 20;
37 + private byte protocol = MPLS.PROTOCOL_IPV4;
38 +
39 + private byte[] bytes;
40 +
41 + @Before
42 + public void setUp() throws Exception {
43 + // Replace normal deserializer map with an empty map. This will cause
44 + // the DataDeserializer to be used which will silently handle 0-byte input.
45 + MPLS.protocolDeserializerMap = new HashMap<>();
46 +
47 + deserializer = MPLS.deserializer();
48 +
49 + ByteBuffer bb = ByteBuffer.allocate(MPLS.HEADER_LENGTH);
50 + bb.putInt(((label & 0x000fffff) << 12) | ((bos & 0x1) << 8 | (ttl & 0xff)));
51 +
52 + bytes = bb.array();
53 + }
54 +
55 + @Test
56 + public void testDeserializeBadInput() throws Exception {
57 + PacketTestUtils.testDeserializeBadInput(deserializer);
58 + }
59 +
60 + @Test
61 + public void testDeserializeTruncated() throws Exception {
62 + PacketTestUtils.testDeserializeTruncated(deserializer, bytes);
63 + }
64 +
65 + @Test
66 + public void testDeserialize() throws Exception {
67 + MPLS mpls = deserializer.deserialize(bytes, 0, bytes.length);
68 +
69 + assertEquals(label, mpls.label);
70 + assertEquals(bos, mpls.bos);
71 + assertEquals(ttl, mpls.ttl);
72 + assertEquals(protocol, mpls.protocol);
73 + }
74 +}
1 +/*
2 + * Copyright 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 +
17 +package org.onlab.packet;
18 +
19 +import java.nio.ByteBuffer;
20 +
21 +import static junit.framework.TestCase.fail;
22 +import static org.junit.Assert.assertTrue;
23 +
24 +/**
25 + * Utilities for testing packet methods.
26 + */
27 +public final class PacketTestUtils {
28 +
29 + private PacketTestUtils() {
30 + }
31 +
32 + /**
33 + * Tests that the Deserializer function is resilient to bad input parameters
34 + * such as null input, negative offset and length, etc.
35 + *
36 + * @param deserializer deserializer function to test
37 + */
38 + public static void testDeserializeBadInput(Deserializer deserializer) {
39 + byte[] bytes = ByteBuffer.allocate(4).array();
40 +
41 + try {
42 + deserializer.deserialize(null, 0, 4);
43 + fail("NullPointerException was not thrown");
44 + } catch (NullPointerException e) {
45 + assertTrue(true);
46 + } catch (DeserializationException e) {
47 + fail("NullPointerException was not thrown");
48 + }
49 +
50 + // input byte array length, offset and length don't make sense
51 + expectDeserializationException(deserializer, bytes, -1, 0);
52 + expectDeserializationException(deserializer, bytes, 0, -1);
53 + expectDeserializationException(deserializer, bytes, 0, 5);
54 + expectDeserializationException(deserializer, bytes, 2, 3);
55 + expectDeserializationException(deserializer, bytes, 5, 0);
56 + }
57 +
58 + /**
59 + * Tests that the Deserializer function is resilient to truncated input, or
60 + * cases where the input byte array does not contain enough bytes to
61 + * deserialize the packet.
62 + *
63 + * @param deserializer deserializer function to test
64 + * @param header byte array of a full-size packet
65 + */
66 + public static void testDeserializeTruncated(Deserializer deserializer,
67 + byte[] header) {
68 + byte[] truncated;
69 +
70 + for (int i = 0; i < header.length; i++) {
71 + truncated = new byte[i];
72 +
73 + ByteBuffer.wrap(header).get(truncated);
74 +
75 + expectDeserializationException(deserializer, truncated, 0, truncated.length);
76 + }
77 + }
78 +
79 + /**
80 + * Run the given deserializer function against the given inputs and verify
81 + * that a DeserializationException is thrown. The the test will fail if a
82 + * DeserializationException is not thrown by the deserializer function.
83 + *
84 + * @param deserializer deserializer function to test
85 + * @param bytes input byte array
86 + * @param offset input offset
87 + * @param length input length
88 + */
89 + public static void expectDeserializationException(Deserializer deserializer,
90 + byte[] bytes, int offset, int length) {
91 + try {
92 + deserializer.deserialize(bytes, offset, length);
93 + fail("DeserializationException was not thrown");
94 + } catch (DeserializationException e) {
95 + assertTrue(true);
96 + }
97 + }
98 +}
...@@ -67,8 +67,12 @@ public class TCPTest { ...@@ -67,8 +67,12 @@ public class TCPTest {
67 (byte) 0x00, (byte) 0x01 // urgent 67 (byte) 0x00, (byte) 0x01 // urgent
68 }; 68 };
69 69
70 + private static Deserializer<TCP> deserializer;
71 +
70 @BeforeClass 72 @BeforeClass
71 public static void setUpBeforeClass() throws Exception { 73 public static void setUpBeforeClass() throws Exception {
74 + deserializer = TCP.deserializer();
75 +
72 ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS)); 76 ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS));
73 ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS)); 77 ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS));
74 ipv4.setProtocol(IPv4.PROTOCOL_TCP); 78 ipv4.setProtocol(IPv4.PROTOCOL_TCP);
...@@ -100,13 +104,22 @@ public class TCPTest { ...@@ -100,13 +104,22 @@ public class TCPTest {
100 assertArrayEquals(bytePacketTCP6, tcp.serialize()); 104 assertArrayEquals(bytePacketTCP6, tcp.serialize());
101 } 105 }
102 106
107 + @Test
108 + public void testDeserializeBadInput() throws Exception {
109 + PacketTestUtils.testDeserializeBadInput(deserializer);
110 + }
111 +
112 + @Test
113 + public void testDeserializeTruncated() throws Exception {
114 + PacketTestUtils.testDeserializeTruncated(deserializer, bytePacketTCP4);
115 + }
116 +
103 /** 117 /**
104 * Tests deserialize and getters. 118 * Tests deserialize and getters.
105 */ 119 */
106 @Test 120 @Test
107 - public void testDeserialize() { 121 + public void testDeserialize() throws Exception {
108 - TCP tcp = new TCP(); 122 + TCP tcp = deserializer.deserialize(bytePacketTCP4, 0, bytePacketTCP4.length);
109 - tcp.deserialize(bytePacketTCP4, 0, bytePacketTCP4.length);
110 123
111 assertThat(tcp.getSourcePort(), is((short) 0x50)); 124 assertThat(tcp.getSourcePort(), is((short) 0x50));
112 assertThat(tcp.getDestinationPort(), is((short) 0x60)); 125 assertThat(tcp.getDestinationPort(), is((short) 0x60));
......
...@@ -61,8 +61,12 @@ public class UDPTest { ...@@ -61,8 +61,12 @@ public class UDPTest {
61 (byte) 0x02, (byte) 0x2a, // checksum 61 (byte) 0x02, (byte) 0x2a, // checksum
62 }; 62 };
63 63
64 + private static Deserializer<UDP> deserializer;
65 +
64 @BeforeClass 66 @BeforeClass
65 public static void setUpBeforeClass() throws Exception { 67 public static void setUpBeforeClass() throws Exception {
68 + deserializer = UDP.deserializer();
69 +
66 ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS)); 70 ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS));
67 ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS)); 71 ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS));
68 ipv4.setProtocol(IPv4.PROTOCOL_UDP); 72 ipv4.setProtocol(IPv4.PROTOCOL_UDP);
...@@ -88,13 +92,22 @@ public class UDPTest { ...@@ -88,13 +92,22 @@ public class UDPTest {
88 assertArrayEquals(bytePacketUDP6, udp.serialize()); 92 assertArrayEquals(bytePacketUDP6, udp.serialize());
89 } 93 }
90 94
95 + @Test
96 + public void testDeserializeBadInput() throws Exception {
97 + PacketTestUtils.testDeserializeBadInput(deserializer);
98 + }
99 +
100 + @Test
101 + public void testDeserializeTruncated() throws Exception {
102 + PacketTestUtils.testDeserializeTruncated(deserializer, bytePacketUDP4);
103 + }
104 +
91 /** 105 /**
92 * Tests deserialize and getters. 106 * Tests deserialize and getters.
93 */ 107 */
94 @Test 108 @Test
95 - public void testDeserialize() { 109 + public void testDeserialize() throws Exception {
96 - UDP udp = new UDP(); 110 + UDP udp = deserializer.deserialize(bytePacketUDP4, 0, bytePacketUDP4.length);
97 - udp.deserialize(bytePacketUDP4, 0, bytePacketUDP4.length);
98 111
99 assertThat(udp.getSourcePort(), is((short) 0x50)); 112 assertThat(udp.getSourcePort(), is((short) 0x50));
100 assertThat(udp.getDestinationPort(), is((short) 0x60)); 113 assertThat(udp.getDestinationPort(), is((short) 0x60));
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
16 16
17 package org.onlab.packet.ipv6; 17 package org.onlab.packet.ipv6;
18 18
19 +import org.junit.Before;
19 import org.junit.BeforeClass; 20 import org.junit.BeforeClass;
20 import org.junit.Test; 21 import org.junit.Test;
21 import org.onlab.packet.Data; 22 import org.onlab.packet.Data;
23 +import org.onlab.packet.Deserializer;
22 import org.onlab.packet.UDP; 24 import org.onlab.packet.UDP;
23 25
24 import static org.hamcrest.Matchers.is; 26 import static org.hamcrest.Matchers.is;
...@@ -38,6 +40,8 @@ public class AuthenticationTest { ...@@ -38,6 +40,8 @@ public class AuthenticationTest {
38 }; 40 };
39 private static byte[] bytePacket; 41 private static byte[] bytePacket;
40 42
43 + private Deserializer<Authentication> deserializer;
44 +
41 @BeforeClass 45 @BeforeClass
42 public static void setUpBeforeClass() throws Exception { 46 public static void setUpBeforeClass() throws Exception {
43 data = new Data(); 47 data = new Data();
...@@ -57,6 +61,11 @@ public class AuthenticationTest { ...@@ -57,6 +61,11 @@ public class AuthenticationTest {
57 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); 61 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
58 } 62 }
59 63
64 + @Before
65 + public void setUp() {
66 + deserializer = Authentication.deserializer();
67 + }
68 +
60 /** 69 /**
61 * Tests serialize and setters. 70 * Tests serialize and setters.
62 */ 71 */
...@@ -77,9 +86,8 @@ public class AuthenticationTest { ...@@ -77,9 +86,8 @@ public class AuthenticationTest {
77 * Tests deserialize and getters. 86 * Tests deserialize and getters.
78 */ 87 */
79 @Test 88 @Test
80 - public void testDeserialize() { 89 + public void testDeserialize() throws Exception {
81 - Authentication auth = new Authentication(); 90 + Authentication auth = deserializer.deserialize(bytePacket, 0, bytePacket.length);
82 - auth.deserialize(bytePacket, 0, bytePacket.length);
83 91
84 assertThat(auth.getNextHeader(), is((byte) 0x11)); 92 assertThat(auth.getNextHeader(), is((byte) 0x11));
85 assertThat(auth.getPayloadLength(), is((byte) 0x02)); 93 assertThat(auth.getPayloadLength(), is((byte) 0x02));
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
16 16
17 package org.onlab.packet.ipv6; 17 package org.onlab.packet.ipv6;
18 18
19 +import org.junit.Before;
19 import org.junit.BeforeClass; 20 import org.junit.BeforeClass;
20 import org.junit.Test; 21 import org.junit.Test;
21 import org.onlab.packet.Data; 22 import org.onlab.packet.Data;
23 +import org.onlab.packet.Deserializer;
22 import org.onlab.packet.IPv6; 24 import org.onlab.packet.IPv6;
23 import org.onlab.packet.UDP; 25 import org.onlab.packet.UDP;
24 26
...@@ -40,6 +42,8 @@ public class BaseOptionsTest { ...@@ -40,6 +42,8 @@ public class BaseOptionsTest {
40 }; 42 };
41 private static byte[] bytePacket; 43 private static byte[] bytePacket;
42 44
45 + private Deserializer<BaseOptions> deserializer;
46 +
43 @BeforeClass 47 @BeforeClass
44 public static void setUpBeforeClass() throws Exception { 48 public static void setUpBeforeClass() throws Exception {
45 data = new Data(); 49 data = new Data();
...@@ -57,6 +61,11 @@ public class BaseOptionsTest { ...@@ -57,6 +61,11 @@ public class BaseOptionsTest {
57 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); 61 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
58 } 62 }
59 63
64 + @Before
65 + public void setUp() {
66 + deserializer = BaseOptions.deserializer();
67 + }
68 +
60 /** 69 /**
61 * Tests serialize and setters. 70 * Tests serialize and setters.
62 */ 71 */
...@@ -75,9 +84,8 @@ public class BaseOptionsTest { ...@@ -75,9 +84,8 @@ public class BaseOptionsTest {
75 * Tests deserialize and getters. 84 * Tests deserialize and getters.
76 */ 85 */
77 @Test 86 @Test
78 - public void testDeserialize() { 87 + public void testDeserialize() throws Exception {
79 - BaseOptions baseopt = new BaseOptions(); 88 + BaseOptions baseopt = deserializer.deserialize(bytePacket, 0, bytePacket.length);
80 - baseopt.deserialize(bytePacket, 0, bytePacket.length);
81 89
82 assertThat(baseopt.getNextHeader(), is((byte) 0x11)); 90 assertThat(baseopt.getNextHeader(), is((byte) 0x11));
83 assertThat(baseopt.getHeaderExtLength(), is((byte) 0x00)); 91 assertThat(baseopt.getHeaderExtLength(), is((byte) 0x00));
......
...@@ -16,9 +16,13 @@ ...@@ -16,9 +16,13 @@
16 16
17 package org.onlab.packet.ipv6; 17 package org.onlab.packet.ipv6;
18 18
19 +import org.junit.Before;
19 import org.junit.BeforeClass; 20 import org.junit.BeforeClass;
20 import org.junit.Test; 21 import org.junit.Test;
21 import org.onlab.packet.Data; 22 import org.onlab.packet.Data;
23 +import org.onlab.packet.DeserializationException;
24 +import org.onlab.packet.Deserializer;
25 +
22 import java.util.Arrays; 26 import java.util.Arrays;
23 27
24 import static org.hamcrest.Matchers.is; 28 import static org.hamcrest.Matchers.is;
...@@ -35,6 +39,8 @@ public class EncapSecurityPayloadTest { ...@@ -35,6 +39,8 @@ public class EncapSecurityPayloadTest {
35 private static byte[] dataByte = new byte[32]; 39 private static byte[] dataByte = new byte[32];
36 private static byte[] bytePacket; 40 private static byte[] bytePacket;
37 41
42 + private Deserializer<EncapSecurityPayload> deserializer;
43 +
38 @BeforeClass 44 @BeforeClass
39 public static void setUpBeforeClass() throws Exception { 45 public static void setUpBeforeClass() throws Exception {
40 Arrays.fill(dataByte, (byte) 0xff); 46 Arrays.fill(dataByte, (byte) 0xff);
...@@ -50,6 +56,11 @@ public class EncapSecurityPayloadTest { ...@@ -50,6 +56,11 @@ public class EncapSecurityPayloadTest {
50 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); 56 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
51 } 57 }
52 58
59 + @Before
60 + public void setUp() {
61 + deserializer = EncapSecurityPayload.deserializer();
62 + }
63 +
53 /** 64 /**
54 * Tests serialize and setters. 65 * Tests serialize and setters.
55 */ 66 */
...@@ -67,9 +78,8 @@ public class EncapSecurityPayloadTest { ...@@ -67,9 +78,8 @@ public class EncapSecurityPayloadTest {
67 * Tests deserialize and getters. 78 * Tests deserialize and getters.
68 */ 79 */
69 @Test 80 @Test
70 - public void testDeserialize() { 81 + public void testDeserialize() throws DeserializationException {
71 - EncapSecurityPayload esp = new EncapSecurityPayload(); 82 + EncapSecurityPayload esp = deserializer.deserialize(bytePacket, 0, bytePacket.length);
72 - esp.deserialize(bytePacket, 0, bytePacket.length);
73 83
74 assertThat(esp.getSecurityParamIndex(), is(0x13572468)); 84 assertThat(esp.getSecurityParamIndex(), is(0x13572468));
75 assertThat(esp.getSequence(), is(0xffff00)); 85 assertThat(esp.getSequence(), is(0xffff00));
......
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
16 16
17 package org.onlab.packet.ipv6; 17 package org.onlab.packet.ipv6;
18 18
19 +import org.junit.Before;
19 import org.junit.BeforeClass; 20 import org.junit.BeforeClass;
20 import org.junit.Test; 21 import org.junit.Test;
21 import org.onlab.packet.Data; 22 import org.onlab.packet.Data;
23 +import org.onlab.packet.DeserializationException;
24 +import org.onlab.packet.Deserializer;
22 import org.onlab.packet.UDP; 25 import org.onlab.packet.UDP;
23 26
24 import static org.hamcrest.Matchers.is; 27 import static org.hamcrest.Matchers.is;
...@@ -35,6 +38,8 @@ public class FragmentTest { ...@@ -35,6 +38,8 @@ public class FragmentTest {
35 private static UDP udp; 38 private static UDP udp;
36 private static byte[] bytePacket; 39 private static byte[] bytePacket;
37 40
41 + private Deserializer<Fragment> deserializer;
42 +
38 @BeforeClass 43 @BeforeClass
39 public static void setUpBeforeClass() throws Exception { 44 public static void setUpBeforeClass() throws Exception {
40 data = new Data(); 45 data = new Data();
...@@ -52,6 +57,11 @@ public class FragmentTest { ...@@ -52,6 +57,11 @@ public class FragmentTest {
52 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); 57 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
53 } 58 }
54 59
60 + @Before
61 + public void setUp() {
62 + deserializer = Fragment.deserializer();
63 + }
64 +
55 /** 65 /**
56 * Tests serialize and setters. 66 * Tests serialize and setters.
57 */ 67 */
...@@ -71,9 +81,8 @@ public class FragmentTest { ...@@ -71,9 +81,8 @@ public class FragmentTest {
71 * Tests deserialize and getters. 81 * Tests deserialize and getters.
72 */ 82 */
73 @Test 83 @Test
74 - public void testDeserialize() { 84 + public void testDeserialize() throws DeserializationException {
75 - Fragment frag = new Fragment(); 85 + Fragment frag = deserializer.deserialize(bytePacket, 0, bytePacket.length);
76 - frag.deserialize(bytePacket, 0, bytePacket.length);
77 86
78 assertThat(frag.getNextHeader(), is((byte) 0x11)); 87 assertThat(frag.getNextHeader(), is((byte) 0x11));
79 assertThat(frag.getFragmentOffset(), is((short) 0x1f)); 88 assertThat(frag.getFragmentOffset(), is((short) 0x1f));
......
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
16 16
17 package org.onlab.packet.ipv6; 17 package org.onlab.packet.ipv6;
18 18
19 +import org.junit.Before;
19 import org.junit.BeforeClass; 20 import org.junit.BeforeClass;
20 import org.junit.Test; 21 import org.junit.Test;
21 import org.onlab.packet.Data; 22 import org.onlab.packet.Data;
23 +import org.onlab.packet.DeserializationException;
24 +import org.onlab.packet.Deserializer;
22 import org.onlab.packet.UDP; 25 import org.onlab.packet.UDP;
23 26
24 import static org.hamcrest.Matchers.is; 27 import static org.hamcrest.Matchers.is;
...@@ -42,6 +45,8 @@ public class RoutingTest { ...@@ -42,6 +45,8 @@ public class RoutingTest {
42 }; 45 };
43 private static byte[] bytePacket; 46 private static byte[] bytePacket;
44 47
48 + private Deserializer<Routing> deserializer;
49 +
45 @BeforeClass 50 @BeforeClass
46 public static void setUpBeforeClass() throws Exception { 51 public static void setUpBeforeClass() throws Exception {
47 data = new Data(); 52 data = new Data();
...@@ -63,6 +68,11 @@ public class RoutingTest { ...@@ -63,6 +68,11 @@ public class RoutingTest {
63 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); 68 System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
64 } 69 }
65 70
71 + @Before
72 + public void setUp() {
73 + deserializer = Routing.deserializer();
74 + }
75 +
66 /** 76 /**
67 * Tests serialize and setters. 77 * Tests serialize and setters.
68 */ 78 */
...@@ -83,9 +93,8 @@ public class RoutingTest { ...@@ -83,9 +93,8 @@ public class RoutingTest {
83 * Tests deserialize and getters. 93 * Tests deserialize and getters.
84 */ 94 */
85 @Test 95 @Test
86 - public void testDeserialize() { 96 + public void testDeserialize() throws DeserializationException {
87 - Routing routing = new Routing(); 97 + Routing routing = deserializer.deserialize(bytePacket, 0, bytePacket.length);
88 - routing.deserialize(bytePacket, 0, bytePacket.length);
89 98
90 assertThat(routing.getNextHeader(), is((byte) 0x11)); 99 assertThat(routing.getNextHeader(), is((byte) 0x11));
91 assertThat(routing.getHeaderExtLength(), is((byte) 0x02)); 100 assertThat(routing.getHeaderExtLength(), is((byte) 0x02));
......
...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp; ...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
17 17
18 import org.junit.BeforeClass; 18 import org.junit.BeforeClass;
19 import org.junit.Test; 19 import org.junit.Test;
20 +import org.onlab.packet.DeserializationException;
21 +import org.onlab.packet.Deserializer;
20 import org.onlab.packet.MacAddress; 22 import org.onlab.packet.MacAddress;
21 23
22 import static org.hamcrest.Matchers.is; 24 import static org.hamcrest.Matchers.is;
...@@ -40,6 +42,9 @@ public class NeighborAdvertisementTest { ...@@ -40,6 +42,9 @@ public class NeighborAdvertisementTest {
40 42
41 private static byte[] bytePacket; 43 private static byte[] bytePacket;
42 44
45 + private Deserializer<NeighborAdvertisement> deserializer
46 + = NeighborAdvertisement.deserializer();
47 +
43 @BeforeClass 48 @BeforeClass
44 public static void setUpBeforeClass() throws Exception { 49 public static void setUpBeforeClass() throws Exception {
45 byte[] byteHeader = { 50 byte[] byteHeader = {
...@@ -75,9 +80,8 @@ public class NeighborAdvertisementTest { ...@@ -75,9 +80,8 @@ public class NeighborAdvertisementTest {
75 * Tests deserialize and getters. 80 * Tests deserialize and getters.
76 */ 81 */
77 @Test 82 @Test
78 - public void testDeserialize() { 83 + public void testDeserialize() throws DeserializationException {
79 - NeighborAdvertisement na = new NeighborAdvertisement(); 84 + NeighborAdvertisement na = deserializer.deserialize(bytePacket, 0, bytePacket.length);
80 - na.deserialize(bytePacket, 0, bytePacket.length);
81 85
82 assertThat(na.getRouterFlag(), is((byte) 1)); 86 assertThat(na.getRouterFlag(), is((byte) 1));
83 assertThat(na.getSolicitedFlag(), is((byte) 1)); 87 assertThat(na.getSolicitedFlag(), is((byte) 1));
......
...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp; ...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
17 17
18 import org.junit.BeforeClass; 18 import org.junit.BeforeClass;
19 import org.junit.Test; 19 import org.junit.Test;
20 +import org.onlab.packet.DeserializationException;
21 +import org.onlab.packet.Deserializer;
20 import org.onlab.packet.MacAddress; 22 import org.onlab.packet.MacAddress;
21 23
22 import static org.hamcrest.Matchers.is; 24 import static org.hamcrest.Matchers.is;
...@@ -46,6 +48,9 @@ public class NeighborSolicitationTest { ...@@ -46,6 +48,9 @@ public class NeighborSolicitationTest {
46 48
47 private static byte[] bytePacket; 49 private static byte[] bytePacket;
48 50
51 + private Deserializer<NeighborSolicitation> deserializer
52 + = NeighborSolicitation.deserializer();
53 +
49 @BeforeClass 54 @BeforeClass
50 public static void setUpBeforeClass() throws Exception { 55 public static void setUpBeforeClass() throws Exception {
51 byte[] byteHeader = { 56 byte[] byteHeader = {
...@@ -78,9 +83,8 @@ public class NeighborSolicitationTest { ...@@ -78,9 +83,8 @@ public class NeighborSolicitationTest {
78 * Tests deserialize and getters. 83 * Tests deserialize and getters.
79 */ 84 */
80 @Test 85 @Test
81 - public void testDeserialize() { 86 + public void testDeserialize() throws DeserializationException {
82 - NeighborSolicitation ns = new NeighborSolicitation(); 87 + NeighborSolicitation ns = deserializer.deserialize(bytePacket, 0, bytePacket.length);
83 - ns.deserialize(bytePacket, 0, bytePacket.length);
84 88
85 assertArrayEquals(ns.getTargetAddress(), TARGET_ADDRESS); 89 assertArrayEquals(ns.getTargetAddress(), TARGET_ADDRESS);
86 90
......
...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp; ...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
17 17
18 import org.junit.BeforeClass; 18 import org.junit.BeforeClass;
19 import org.junit.Test; 19 import org.junit.Test;
20 +import org.onlab.packet.DeserializationException;
21 +import org.onlab.packet.Deserializer;
20 import org.onlab.packet.MacAddress; 22 import org.onlab.packet.MacAddress;
21 23
22 import static org.hamcrest.Matchers.is; 24 import static org.hamcrest.Matchers.is;
...@@ -52,6 +54,8 @@ public class RedirectTest { ...@@ -52,6 +54,8 @@ public class RedirectTest {
52 54
53 private static byte[] bytePacket; 55 private static byte[] bytePacket;
54 56
57 + private Deserializer<Redirect> deserializer = Redirect.deserializer();
58 +
55 @BeforeClass 59 @BeforeClass
56 public static void setUpBeforeClass() throws Exception { 60 public static void setUpBeforeClass() throws Exception {
57 byte[] byteHeader = { 61 byte[] byteHeader = {
...@@ -89,9 +93,8 @@ public class RedirectTest { ...@@ -89,9 +93,8 @@ public class RedirectTest {
89 * Tests deserialize and getters. 93 * Tests deserialize and getters.
90 */ 94 */
91 @Test 95 @Test
92 - public void testDeserialize() { 96 + public void testDeserialize() throws DeserializationException {
93 - Redirect rd = new Redirect(); 97 + Redirect rd = deserializer.deserialize(bytePacket, 0, bytePacket.length);
94 - rd.deserialize(bytePacket, 0, bytePacket.length);
95 98
96 assertArrayEquals(rd.getTargetAddress(), TARGET_ADDRESS); 99 assertArrayEquals(rd.getTargetAddress(), TARGET_ADDRESS);
97 assertArrayEquals(rd.getDestinationAddress(), DESTINATION_ADDRESS); 100 assertArrayEquals(rd.getDestinationAddress(), DESTINATION_ADDRESS);
......
...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp; ...@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
17 17
18 import org.junit.BeforeClass; 18 import org.junit.BeforeClass;
19 import org.junit.Test; 19 import org.junit.Test;
20 +import org.onlab.packet.DeserializationException;
21 +import org.onlab.packet.Deserializer;
20 import org.onlab.packet.MacAddress; 22 import org.onlab.packet.MacAddress;
21 23
22 import static org.hamcrest.Matchers.is; 24 import static org.hamcrest.Matchers.is;
...@@ -34,6 +36,9 @@ public class RouterAdvertisementTest { ...@@ -34,6 +36,9 @@ public class RouterAdvertisementTest {
34 36
35 private static byte[] bytePacket; 37 private static byte[] bytePacket;
36 38
39 + private Deserializer<RouterAdvertisement> deserializer
40 + = RouterAdvertisement.deserializer();
41 +
37 @BeforeClass 42 @BeforeClass
38 public static void setUpBeforeClass() throws Exception { 43 public static void setUpBeforeClass() throws Exception {
39 byte[] byteHeader = { 44 byte[] byteHeader = {
...@@ -69,9 +74,8 @@ public class RouterAdvertisementTest { ...@@ -69,9 +74,8 @@ public class RouterAdvertisementTest {
69 * Tests deserialize and getters. 74 * Tests deserialize and getters.
70 */ 75 */
71 @Test 76 @Test
72 - public void testDeserialize() { 77 + public void testDeserialize() throws DeserializationException {
73 - RouterAdvertisement ra = new RouterAdvertisement(); 78 + RouterAdvertisement ra = deserializer.deserialize(bytePacket, 0, bytePacket.length);
74 - ra.deserialize(bytePacket, 0, bytePacket.length);
75 79
76 assertThat(ra.getCurrentHopLimit(), is((byte) 3)); 80 assertThat(ra.getCurrentHopLimit(), is((byte) 3));
77 assertThat(ra.getMFlag(), is((byte) 1)); 81 assertThat(ra.getMFlag(), is((byte) 1));
......
...@@ -17,7 +17,9 @@ package org.onlab.packet.ndp; ...@@ -17,7 +17,9 @@ package org.onlab.packet.ndp;
17 17
18 import org.junit.BeforeClass; 18 import org.junit.BeforeClass;
19 import org.junit.Test; 19 import org.junit.Test;
20 +import org.onlab.packet.Deserializer;
20 import org.onlab.packet.MacAddress; 21 import org.onlab.packet.MacAddress;
22 +import org.onlab.packet.PacketTestUtils;
21 23
22 import static org.hamcrest.Matchers.is; 24 import static org.hamcrest.Matchers.is;
23 import static org.junit.Assert.assertArrayEquals; 25 import static org.junit.Assert.assertArrayEquals;
...@@ -36,6 +38,9 @@ public class RouterSolicitationTest { ...@@ -36,6 +38,9 @@ public class RouterSolicitationTest {
36 38
37 private static byte[] bytePacket; 39 private static byte[] bytePacket;
38 40
41 + private Deserializer<RouterSolicitation> deserializer
42 + = RouterSolicitation.deserializer();
43 +
39 @BeforeClass 44 @BeforeClass
40 public static void setUpBeforeClass() throws Exception { 45 public static void setUpBeforeClass() throws Exception {
41 byte[] byteHeader = { 46 byte[] byteHeader = {
...@@ -59,13 +64,22 @@ public class RouterSolicitationTest { ...@@ -59,13 +64,22 @@ public class RouterSolicitationTest {
59 assertArrayEquals(rs.serialize(), bytePacket); 64 assertArrayEquals(rs.serialize(), bytePacket);
60 } 65 }
61 66
67 + @Test
68 + public void testDeserializeBadInput() throws Exception {
69 + PacketTestUtils.testDeserializeBadInput(RouterSolicitation.deserializer());
70 + }
71 +
72 + @Test
73 + public void testDeserializeTruncated() throws Exception {
74 + PacketTestUtils.testDeserializeTruncated(RouterSolicitation.deserializer(), bytePacket);
75 + }
76 +
62 /** 77 /**
63 * Tests deserialize and getters. 78 * Tests deserialize and getters.
64 */ 79 */
65 @Test 80 @Test
66 - public void testDeserialize() { 81 + public void testDeserialize() throws Exception {
67 - RouterSolicitation rs = new RouterSolicitation(); 82 + RouterSolicitation rs = deserializer.deserialize(bytePacket, 0, bytePacket.length);
68 - rs.deserialize(bytePacket, 0, bytePacket.length);
69 83
70 // Check the option(s) 84 // Check the option(s)
71 assertThat(rs.getOptions().size(), is(1)); 85 assertThat(rs.getOptions().size(), is(1));
......