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