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
2496 additions
and
370 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() |
| 62 | - outPacket().data().array().length); | 67 | + .deserialize(outPacket().data().array(), 0, |
| 63 | - sendPacket(eth); | 68 | + outPacket().data().array().length); |
| 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; |
| ... | @@ -247,7 +251,7 @@ public class ARP extends BasePacket { | ... | @@ -247,7 +251,7 @@ public class ARP extends BasePacket { |
| 247 | 251 | ||
| 248 | @Override | 252 | @Override |
| 249 | public IPacket deserialize(final byte[] data, final int offset, | 253 | public IPacket deserialize(final byte[] data, final int offset, |
| 250 | - final int length) { | 254 | + final int length) { |
| 251 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | 255 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 252 | this.hardwareType = bb.getShort(); | 256 | this.hardwareType = bb.getShort(); |
| 253 | this.protocolType = bb.getShort(); | 257 | this.protocolType = bb.getShort(); |
| ... | @@ -386,10 +390,50 @@ public class ARP extends BasePacket { | ... | @@ -386,10 +390,50 @@ public class ARP extends BasePacket { |
| 386 | arp.setTargetHardwareAddress(request.getSourceMACAddress()); | 390 | arp.setTargetHardwareAddress(request.getSourceMACAddress()); |
| 387 | 391 | ||
| 388 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) | 392 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) |
| 389 | - .getSenderProtocolAddress()); | 393 | + .getSenderProtocolAddress()); |
| 390 | arp.setSenderProtocolAddress(srcIp.toInt()); | 394 | arp.setSenderProtocolAddress(srcIp.toInt()); |
| 391 | 395 | ||
| 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,33 +431,9 @@ public class DHCP extends BasePacket { | ... | @@ -429,33 +431,9 @@ 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) { |
| 459 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | 437 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 460 | if (bb.remaining() < DHCP.MIN_HEADER_LENGTH) { | 438 | if (bb.remaining() < DHCP.MIN_HEADER_LENGTH) { |
| 461 | return this; | 439 | return this; |
| ... | @@ -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 | /** |
| ... | @@ -63,7 +66,7 @@ public class Data extends BasePacket { | ... | @@ -63,7 +66,7 @@ public class Data extends BasePacket { |
| 63 | 66 | ||
| 64 | @Override | 67 | @Override |
| 65 | public IPacket deserialize(final byte[] data, final int offset, | 68 | public IPacket deserialize(final byte[] data, final int offset, |
| 66 | - final int length) { | 69 | + final int length) { |
| 67 | this.data = Arrays.copyOfRange(data, offset, data.length); | 70 | this.data = Arrays.copyOfRange(data, offset, data.length); |
| 68 | return this; | 71 | return this; |
| 69 | } | 72 | } |
| ... | @@ -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 | + |
| 48 | - new HashMap<>(); | 54 | + private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP = |
| 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 | } |
| ... | @@ -300,7 +307,7 @@ public class Ethernet extends BasePacket { | ... | @@ -300,7 +307,7 @@ public class Ethernet extends BasePacket { |
| 300 | 307 | ||
| 301 | @Override | 308 | @Override |
| 302 | public IPacket deserialize(final byte[] data, final int offset, | 309 | public IPacket deserialize(final byte[] data, final int offset, |
| 303 | - final int length) { | 310 | + final int length) { |
| 304 | if (length <= 0) { | 311 | if (length <= 0) { |
| 305 | return null; | 312 | return null; |
| 306 | } | 313 | } |
| ... | @@ -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(); |
| 346 | + } | ||
| 347 | + try { | ||
| 348 | + this.payload = deserializer.deserialize(data, bb.position(), | ||
| 349 | + bb.limit() - bb.position()); | ||
| 350 | + this.payload.setParent(this); | ||
| 351 | + } catch (DeserializationException e) { | ||
| 352 | + return this; | ||
| 345 | } | 353 | } |
| 346 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 347 | - bb.limit() - bb.position()); | ||
| 348 | - this.payload.setParent(this); | ||
| 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 | + * |
| 184 | - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | 203 | + * @return deserializer function |
| 185 | - this.icmpType = bb.get(); | 204 | + */ |
| 186 | - this.icmpCode = bb.get(); | 205 | + public static Deserializer<ICMP> deserializer() { |
| 187 | - this.checksum = bb.getShort(); | 206 | + return (data, offset, length) -> { |
| 188 | - | 207 | + checkInput(data, offset, length, ICMP_HEADER_LENGTH); |
| 189 | - this.payload = new Data(); | 208 | + |
| 190 | - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() | 209 | + ICMP icmp = new ICMP(); |
| 191 | - - bb.position()); | 210 | + |
| 192 | - this.payload.setParent(this); | 211 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 193 | - return this; | 212 | + icmp.icmpType = bb.get(); |
| 213 | + icmp.icmpCode = bb.get(); | ||
| 214 | + icmp.checksum = bb.getShort(); | ||
| 215 | + | ||
| 216 | + icmp.payload = Data.deserializer() | ||
| 217 | + .deserialize(data, bb.position(), bb.limit() | ||
| 218 | + - bb.position()); | ||
| 219 | + icmp.payload.setParent(icmp); | ||
| 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); | ||
| 344 | + | ||
| 345 | + ICMP6 icmp6 = new ICMP6(); | ||
| 346 | + | ||
| 347 | + ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | ||
| 315 | 348 | ||
| 316 | - IPacket payload; | 349 | + icmp6.icmpType = bb.get(); |
| 317 | - if (ICMP6.PROTOCOL_CLASS_MAP.containsKey(this.icmpType)) { | 350 | + icmp6.icmpCode = bb.get(); |
| 318 | - final Class<? extends IPacket> clazz = ICMP6.PROTOCOL_CLASS_MAP | 351 | + icmp6.checksum = bb.getShort(); |
| 319 | - .get(this.icmpType); | 352 | + |
| 320 | - try { | 353 | + Deserializer<? extends IPacket> deserializer; |
| 321 | - payload = clazz.newInstance(); | 354 | + if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmp6.icmpType)) { |
| 322 | - } catch (final Exception e) { | 355 | + deserializer = TYPE_DESERIALIZER_MAP.get(icmp6.icmpType); |
| 323 | - throw new RuntimeException( | 356 | + } else { |
| 324 | - "Error parsing payload for ICMP6 packet", e); | 357 | + deserializer = Data.deserializer(); |
| 325 | } | 358 | } |
| 326 | - } else { | 359 | + icmp6.payload = deserializer.deserialize(data, bb.position(), |
| 327 | - payload = new Data(); | 360 | + bb.limit() - bb.position()); |
| 328 | - } | 361 | + icmp6.payload.setParent(icmp6); |
| 329 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 330 | - bb.limit() - bb.position()); | ||
| 331 | - this.payload.setParent(this); | ||
| 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; |
| ... | @@ -414,7 +418,7 @@ s */ | ... | @@ -414,7 +418,7 @@ s */ |
| 414 | 418 | ||
| 415 | @Override | 419 | @Override |
| 416 | public IPacket deserialize(final byte[] data, final int offset, | 420 | public IPacket deserialize(final byte[] data, final int offset, |
| 417 | - final int length) { | 421 | + final int length) { |
| 418 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | 422 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 419 | short sscratch; | 423 | short sscratch; |
| 420 | 424 | ||
| ... | @@ -439,29 +443,26 @@ s */ | ... | @@ -439,29 +443,26 @@ s */ |
| 439 | bb.get(this.options); | 443 | bb.get(this.options); |
| 440 | } | 444 | } |
| 441 | 445 | ||
| 442 | - IPacket payload; | ||
| 443 | - if (IPv4.PROTOCOL_CLASS_MAP.containsKey(this.protocol)) { | ||
| 444 | - final Class<? extends IPacket> clazz = IPv4.PROTOCOL_CLASS_MAP | ||
| 445 | - .get(this.protocol); | ||
| 446 | - try { | ||
| 447 | - payload = clazz.newInstance(); | ||
| 448 | - } catch (final Exception e) { | ||
| 449 | - throw new RuntimeException( | ||
| 450 | - "Error parsing payload for IPv4 packet", e); | ||
| 451 | - } | ||
| 452 | - } else { | ||
| 453 | - payload = new Data(); | ||
| 454 | - } | ||
| 455 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 456 | - bb.limit() - bb.position()); | ||
| 457 | - this.payload.setParent(this); | ||
| 458 | - | ||
| 459 | if (this.totalLength != length) { | 446 | if (this.totalLength != length) { |
| 460 | this.isTruncated = true; | 447 | this.isTruncated = true; |
| 461 | } else { | 448 | } else { |
| 462 | this.isTruncated = false; | 449 | this.isTruncated = false; |
| 463 | } | 450 | } |
| 464 | 451 | ||
| 452 | + Deserializer<? extends IPacket> deserializer; | ||
| 453 | + if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(this.protocol)) { | ||
| 454 | + deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(this.protocol); | ||
| 455 | + } else { | ||
| 456 | + deserializer = Data.deserializer(); | ||
| 457 | + } | ||
| 458 | + try { | ||
| 459 | + this.payload = deserializer.deserialize(data, bb.position(), | ||
| 460 | + bb.limit() - bb.position()); | ||
| 461 | + this.payload.setParent(this); | ||
| 462 | + } catch (DeserializationException e) { | ||
| 463 | + return this; | ||
| 464 | + } | ||
| 465 | + | ||
| 465 | return this; | 466 | return this; |
| 466 | } | 467 | } |
| 467 | 468 | ||
| ... | @@ -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(); |
| 267 | + } | ||
| 268 | + try { | ||
| 269 | + this.payload = deserializer.deserialize(data, bb.position(), | ||
| 270 | + bb.limit() - bb.position()); | ||
| 271 | + this.payload.setParent(this); | ||
| 272 | + } catch (DeserializationException e) { | ||
| 273 | + return this; | ||
| 271 | } | 274 | } |
| 272 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 273 | - bb.limit() - bb.position()); | ||
| 274 | - this.payload.setParent(this); | ||
| 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; |
| ... | @@ -67,11 +72,31 @@ public class LLC extends BasePacket { | ... | @@ -67,11 +72,31 @@ public class LLC extends BasePacket { |
| 67 | 72 | ||
| 68 | @Override | 73 | @Override |
| 69 | public IPacket deserialize(final byte[] data, final int offset, | 74 | public IPacket deserialize(final byte[] data, final int offset, |
| 70 | - final int length) { | 75 | + final int length) { |
| 71 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | 76 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 72 | this.dsap = bb.get(); | 77 | this.dsap = bb.get(); |
| 73 | this.ssap = bb.get(); | 78 | this.ssap = bb.get(); |
| 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 | ||
| ... | @@ -134,11 +147,15 @@ public class LLDP extends BasePacket { | ... | @@ -134,11 +147,15 @@ public class LLDP extends BasePacket { |
| 134 | 147 | ||
| 135 | @Override | 148 | @Override |
| 136 | public IPacket deserialize(final byte[] data, final int offset, | 149 | public IPacket deserialize(final byte[] data, final int offset, |
| 137 | - final int length) { | 150 | + final int length) { |
| 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 { |
| 141 | - tlv = new LLDPOrganizationalTLV().deserialize(bb); | 154 | + try { |
| 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(); |
| 70 | + } | ||
| 71 | + try { | ||
| 72 | + this.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position()); | ||
| 73 | + this.payload.setParent(this); | ||
| 74 | + } catch (DeserializationException e) { | ||
| 75 | + return this; | ||
| 72 | } | 76 | } |
| 73 | - this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position()); | ||
| 74 | - this.payload.setParent(this); | ||
| 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(); | 434 | + |
| 396 | - this.dataOffset = (byte) (this.flags >> 12 & 0xf); | 435 | + TCP tcp = new TCP(); |
| 397 | - this.flags = (short) (this.flags & 0x1ff); | 436 | + |
| 398 | - this.windowSize = bb.getShort(); | 437 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 399 | - this.checksum = bb.getShort(); | 438 | + tcp.sourcePort = bb.getShort(); |
| 400 | - this.urgentPointer = bb.getShort(); | 439 | + tcp.destinationPort = bb.getShort(); |
| 401 | - if (this.dataOffset > 5) { | 440 | + tcp.sequence = bb.getInt(); |
| 402 | - int optLength = (this.dataOffset << 2) - 20; | 441 | + tcp.acknowledge = bb.getInt(); |
| 403 | - if (bb.limit() < bb.position() + optLength) { | 442 | + tcp.flags = bb.getShort(); |
| 404 | - optLength = bb.limit() - bb.position(); | 443 | + tcp.dataOffset = (byte) (tcp.flags >> 12 & 0xf); |
| 405 | - } | 444 | + tcp.flags = (short) (tcp.flags & 0x1ff); |
| 406 | - try { | 445 | + tcp.windowSize = bb.getShort(); |
| 407 | - this.options = new byte[optLength]; | 446 | + tcp.checksum = bb.getShort(); |
| 408 | - bb.get(this.options, 0, optLength); | 447 | + tcp.urgentPointer = bb.getShort(); |
| 409 | - } catch (final IndexOutOfBoundsException e) { | 448 | + if (tcp.dataOffset > 5) { |
| 410 | - this.options = null; | 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); | ||
| 411 | } | 453 | } |
| 412 | - } | ||
| 413 | 454 | ||
| 414 | - this.payload = new Data(); | 455 | + tcp.payload = Data.deserializer() |
| 415 | - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() | 456 | + .deserialize(data, bb.position(), bb.limit() - bb.position()); |
| 416 | - - bb.position()); | 457 | + tcp.payload.setParent(tcp); |
| 417 | - this.payload.setParent(this); | 458 | + return tcp; |
| 418 | - return this; | 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); |
| 297 | + } else { | ||
| 298 | + deserializer = Data.deserializer(); | ||
| 265 | } | 299 | } |
| 266 | - } else { | 300 | + |
| 267 | - this.payload = new Data(); | 301 | + udp.payload = deserializer.deserialize(data, bb.position(), |
| 268 | - } | 302 | + bb.limit() - bb.position()); |
| 269 | - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() | 303 | + udp.payload.setParent(udp); |
| 270 | - - bb.position()); | 304 | + return udp; |
| 271 | - this.payload.setParent(this); | 305 | + }; |
| 272 | - return this; | ||
| 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(); |
| 199 | + } | ||
| 200 | + | ||
| 201 | + try { | ||
| 202 | + this.payload = deserializer.deserialize(data, bb.position(), | ||
| 203 | + bb.limit() - bb.position()); | ||
| 204 | + this.payload.setParent(this); | ||
| 205 | + } catch (DeserializationException e) { | ||
| 206 | + return this; | ||
| 201 | } | 207 | } |
| 202 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 203 | - bb.limit() - bb.position()); | ||
| 204 | - this.payload.setParent(this); | ||
| 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(); |
| 164 | + } | ||
| 165 | + try { | ||
| 166 | + this.payload = deserializer.deserialize(data, bb.position(), | ||
| 167 | + bb.limit() - bb.position()); | ||
| 168 | + this.payload.setParent(this); | ||
| 169 | + } catch (DeserializationException e) { | ||
| 170 | + return this; | ||
| 166 | } | 171 | } |
| 167 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 168 | - bb.limit() - bb.position()); | ||
| 169 | - this.payload.setParent(this); | ||
| 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) |
| ... | @@ -113,7 +117,7 @@ public class EncapSecurityPayload extends BasePacket { | ... | @@ -113,7 +117,7 @@ public class EncapSecurityPayload extends BasePacket { |
| 113 | 117 | ||
| 114 | this.payload = new Data(); | 118 | this.payload = new Data(); |
| 115 | this.payload.deserialize(data, bb.position(), | 119 | this.payload.deserialize(data, bb.position(), |
| 116 | - bb.limit() - bb.position()); | 120 | + bb.limit() - bb.position()); |
| 117 | this.payload.setParent(this); | 121 | this.payload.setParent(this); |
| 118 | 122 | ||
| 119 | return this; | 123 | return this; |
| ... | @@ -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(); |
| 161 | + } | ||
| 162 | + try { | ||
| 163 | + this.payload = deserializer.deserialize(data, bb.position(), | ||
| 164 | + bb.limit() - bb.position()); | ||
| 165 | + this.payload.setParent(this); | ||
| 166 | + } catch (DeserializationException e) { | ||
| 167 | + return this; | ||
| 164 | } | 168 | } |
| 165 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 166 | - bb.limit() - bb.position()); | ||
| 167 | - this.payload.setParent(this); | ||
| 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(); |
| 188 | + } | ||
| 189 | + try { | ||
| 190 | + this.payload = deserializer.deserialize(data, bb.position(), | ||
| 191 | + bb.limit() - bb.position()); | ||
| 192 | + this.payload.setParent(this); | ||
| 193 | + } catch (DeserializationException e) { | ||
| 194 | + return this; | ||
| 190 | } | 195 | } |
| 191 | - this.payload = payload.deserialize(data, bb.position(), | ||
| 192 | - bb.limit() - bb.position()); | ||
| 193 | - this.payload.setParent(this); | ||
| 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 | } |
| 251 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 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 | + } | ||
| 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 | /** |
| ... | @@ -187,7 +196,7 @@ public class NeighborDiscoveryOptions extends BasePacket { | ... | @@ -187,7 +196,7 @@ public class NeighborDiscoveryOptions extends BasePacket { |
| 187 | } | 196 | } |
| 188 | byte lengthField = bb.get(); | 197 | byte lengthField = bb.get(); |
| 189 | int dataLength = lengthField * 8; // The data length field is in | 198 | int dataLength = lengthField * 8; // The data length field is in |
| 190 | - // unit of 8 octets | 199 | + // unit of 8 octets |
| 191 | 200 | ||
| 192 | // Exclude the type and length fields | 201 | // Exclude the type and length fields |
| 193 | if (dataLength < 2) { | 202 | if (dataLength < 2) { |
| ... | @@ -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)); | ... | ... |
-
Please register or login to post a comment