Jonathan Hart
Committed by Gerrit Code Review

Improve the resiliency of the packet deserialization code.

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

ONOS-1589

Change-Id: I9073d5e6e7991e15d43830cfd810989256b71c56
Showing 60 changed files with 2496 additions and 370 deletions
......@@ -15,8 +15,6 @@
*/
package org.onosproject.bgprouter;
import java.nio.ByteBuffer;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onlab.packet.IPv4;
......@@ -36,6 +34,8 @@ import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
public class IcmpHandler {
private static final Logger log = LoggerFactory.getLogger(IcmpHandler.class);
......@@ -100,7 +100,7 @@ public class IcmpHandler {
icmpReplyIpv4.setTtl((byte) 64);
icmpReplyIpv4.setChecksum((short) 0);
ICMP icmpReply = (ICMP) icmpRequestIpv4.getPayload().clone();
ICMP icmpReply = new ICMP();
icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
icmpReply.setChecksum((short) 0);
......
......@@ -15,8 +15,6 @@
*/
package org.onosproject.segmentrouting;
import java.nio.ByteBuffer;
import java.util.List;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onlab.packet.IPv4;
......@@ -33,6 +31,9 @@ import org.onosproject.net.packet.OutboundPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
public class IcmpHandler {
......@@ -109,7 +110,7 @@ public class IcmpHandler {
icmpReplyIpv4.setTtl((byte) 64);
icmpReplyIpv4.setChecksum((short) 0);
ICMP icmpReply = (ICMP) icmpRequestIpv4.getPayload().clone();
ICMP icmpReply = new ICMP();
icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
icmpReply.setChecksum((short) 0);
......
......@@ -49,8 +49,14 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class HostMonitorTest {
......@@ -151,10 +157,9 @@ public class HostMonitorTest {
assertEquals(portNum, oi.port());
// Check the output packet is correct (well the important bits anyway)
Ethernet eth = new Ethernet();
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
eth.deserialize(pktData, 0, pktData.length);
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
assertArrayEquals(SOURCE_ADDR.toOctets(),
......@@ -220,10 +225,9 @@ public class HostMonitorTest {
assertEquals(portNum, oi.port());
// Check the output packet is correct (well the important bits anyway)
Ethernet eth = new Ethernet();
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
eth.deserialize(pktData, 0, pktData.length);
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(vlan, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
assertArrayEquals(SOURCE_ADDR.toOctets(),
......
......@@ -15,7 +15,7 @@
*/
package org.onosproject.openflow.controller;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Ethernet;
import org.onosproject.core.Permission;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
......@@ -26,6 +26,8 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.BufferUnderflowException;
import java.util.Collections;
......@@ -97,11 +99,12 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext
public Ethernet parsed() {
checkPermission(Permission.PACKET_READ);
Ethernet eth = new Ethernet();
try {
eth.deserialize(pktin.getData(), 0, pktin.getData().length);
return eth;
} catch (BufferUnderflowException | NullPointerException e) {
return Ethernet.deserializer().deserialize(pktin.getData(), 0, pktin.getData().length);
} catch (BufferUnderflowException | NullPointerException |
DeserializationException e) {
Logger log = LoggerFactory.getLogger(getClass());
log.warn("packet deserialization problem");
return null;
}
}
......
......@@ -15,6 +15,8 @@
*/
package org.onosproject.provider.of.packet.impl;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Ethernet;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instruction.Type;
......@@ -23,8 +25,9 @@ import org.onosproject.net.packet.DefaultPacketContext;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.openflow.controller.OpenFlowPacketContext;
import org.onlab.packet.Ethernet;
import org.projectfloodlight.openflow.types.OFPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
......@@ -33,6 +36,8 @@ import java.util.List;
*/
public class OpenFlowCorePacketContext extends DefaultPacketContext {
private static final Logger log = LoggerFactory.getLogger(OpenFlowCorePacketContext.class);
private final OpenFlowPacketContext ofPktCtx;
/**
......@@ -57,12 +62,15 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext {
if (outPacket() == null) {
sendPacket(null);
} else {
Ethernet eth = new Ethernet();
eth.deserialize(outPacket().data().array(), 0,
outPacket().data().array().length);
sendPacket(eth);
try {
Ethernet eth = Ethernet.deserializer()
.deserialize(outPacket().data().array(), 0,
outPacket().data().array().length);
sendPacket(eth);
} catch (DeserializationException e) {
log.warn("Unable to deserialize packet");
}
}
}
}
......
......@@ -42,6 +42,11 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
</dependency>
......
......@@ -21,6 +21,8 @@ package org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.onlab.packet.PacketUtils.*;
/**
*
*
......@@ -35,6 +37,8 @@ public class ARP extends BasePacket {
public static final short OP_RARP_REQUEST = 0x3;
public static final short OP_RARP_REPLY = 0x4;
public static final short INITIAL_HEADER_LENGTH = 8;
protected short hardwareType;
protected short protocolType;
protected byte hardwareAddressLength;
......@@ -247,7 +251,7 @@ public class ARP extends BasePacket {
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.hardwareType = bb.getShort();
this.protocolType = bb.getShort();
......@@ -386,10 +390,50 @@ public class ARP extends BasePacket {
arp.setTargetHardwareAddress(request.getSourceMACAddress());
arp.setTargetProtocolAddress(((ARP) request.getPayload())
.getSenderProtocolAddress());
.getSenderProtocolAddress());
arp.setSenderProtocolAddress(srcIp.toInt());
eth.setPayload(arp);
return eth;
}
/**
* Deserializer function for ARP packets.
*
* @return deserializer function
*/
public static Deserializer<ARP> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, INITIAL_HEADER_LENGTH);
ARP arp = new ARP();
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
arp.setHardwareType(bb.getShort());
arp.setProtocolType(bb.getShort());
byte hwAddressLength = bb.get();
arp.setHardwareAddressLength(hwAddressLength);
byte protocolAddressLength = bb.get();
arp.setProtocolAddressLength(protocolAddressLength);
arp.setOpCode(bb.getShort());
// Check we have enough space for the addresses
checkHeaderLength(length, INITIAL_HEADER_LENGTH +
2 * hwAddressLength +
2 * protocolAddressLength);
arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);
return arp;
};
}
}
......
......@@ -24,6 +24,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import static org.onlab.packet.PacketUtils.*;
/**
*
*/
......@@ -429,33 +431,9 @@ public class DHCP extends BasePacket {
return data;
}
protected void writeString(final String string, final ByteBuffer bb,
final int maxLength) {
if (string == null) {
for (int i = 0; i < maxLength; ++i) {
bb.put((byte) 0x0);
}
} else {
byte[] bytes = null;
try {
bytes = string.getBytes("ascii");
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException("Failure encoding server name", e);
}
int writeLength = bytes.length;
if (writeLength > maxLength) {
writeLength = maxLength;
}
bb.put(bytes, 0, writeLength);
for (int i = writeLength; i < maxLength; ++i) {
bb.put((byte) 0x0);
}
}
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
if (bb.remaining() < DHCP.MIN_HEADER_LENGTH) {
return this;
......@@ -529,7 +507,31 @@ public class DHCP extends BasePacket {
return this;
}
protected String readString(final ByteBuffer bb, final int maxLength) {
protected void writeString(final String string, final ByteBuffer bb,
final int maxLength) {
if (string == null) {
for (int i = 0; i < maxLength; ++i) {
bb.put((byte) 0x0);
}
} else {
byte[] bytes = null;
try {
bytes = string.getBytes("ascii");
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException("Failure encoding server name", e);
}
int writeLength = bytes.length;
if (writeLength > maxLength) {
writeLength = maxLength;
}
bb.put(bytes, 0, writeLength);
for (int i = writeLength; i < maxLength; ++i) {
bb.put((byte) 0x0);
}
}
}
private static String readString(final ByteBuffer bb, final int maxLength) {
final byte[] bytes = new byte[maxLength];
bb.get(bytes);
String result = null;
......@@ -540,4 +542,84 @@ public class DHCP extends BasePacket {
}
return result;
}
/**
* Deserializer function for DHCP packets.
*
* @return deserializer function
*/
public static Deserializer<DHCP> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, MIN_HEADER_LENGTH);
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
DHCP dhcp = new DHCP();
dhcp.opCode = bb.get();
dhcp.hardwareType = bb.get();
dhcp.hardwareAddressLength = bb.get();
dhcp.hops = bb.get();
dhcp.transactionId = bb.getInt();
dhcp.seconds = bb.getShort();
dhcp.flags = bb.getShort();
dhcp.clientIPAddress = bb.getInt();
dhcp.yourIPAddress = bb.getInt();
dhcp.serverIPAddress = bb.getInt();
dhcp.gatewayIPAddress = bb.getInt();
final int hardwareAddressLength = 0xff & dhcp.hardwareAddressLength;
dhcp.clientHardwareAddress = new byte[hardwareAddressLength];
bb.get(dhcp.clientHardwareAddress);
for (int i = hardwareAddressLength; i < 16; ++i) {
bb.get();
}
dhcp.serverName = readString(bb, 64);
dhcp.bootFileName = readString(bb, 128);
// read the magic cookie
// magic cookie
bb.get();
bb.get();
bb.get();
bb.get();
// read options
boolean foundEndOptionsMarker = false;
while (bb.hasRemaining()) {
final DHCPOption option = new DHCPOption();
int code = 0xff & bb.get(); // convert signed byte to int in range
// [0,255]
option.setCode((byte) code);
if (code == 0) {
// skip these
continue;
} else if (code != 255) {
if (bb.hasRemaining()) {
final int l = 0xff & bb.get(); // convert signed byte to
// int in range [0,255]
option.setLength((byte) l);
if (bb.remaining() >= l) {
final byte[] optionData = new byte[l];
bb.get(optionData);
option.setData(optionData);
dhcp.options.add(option);
} else {
throw new DeserializationException(
"Buffer underflow while reading DHCP option");
}
}
} else if (code == 255) {
// remaining bytes are supposed to be 0, but ignore them just in
// case
foundEndOptionsMarker = true;
break;
}
}
if (!foundEndOptionsMarker) {
throw new DeserializationException("DHCP End options marker was missing");
}
return dhcp;
};
}
}
......
......@@ -20,6 +20,8 @@ package org.onlab.packet;
import java.util.Arrays;
import static org.onlab.packet.PacketUtils.*;
/**
*
*/
......@@ -30,6 +32,7 @@ public class Data extends BasePacket {
*
*/
public Data() {
data = new byte[0];
}
/**
......@@ -63,7 +66,7 @@ public class Data extends BasePacket {
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final int length) {
this.data = Arrays.copyOfRange(data, offset, data.length);
return this;
}
......@@ -103,4 +106,27 @@ public class Data extends BasePacket {
}
return true;
}
/**
* Deserializer function for generic payload data.
*
* @return deserializer function
*/
public static Deserializer<Data> deserializer() {
return (data, offset, length) -> {
// Allow zero-length data for now
if (length == 0) {
return new Data();
}
checkInput(data, offset, length, 1);
Data dataObject = new Data();
dataObject.data = Arrays.copyOfRange(data, offset, data.length);
return dataObject;
};
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
/**
* Signals that an error occurred during deserialization of a packet.
*/
public class DeserializationException extends Exception {
/**
* Creates a new deserialization exception with the given message.
*
* @param message exception message
*/
public DeserializationException(String message) {
super(message);
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
/**
* Function to deserialize a packet from a byte-based input stream.
*/
@FunctionalInterface
public interface Deserializer<U extends IPacket> {
/**
* Deserialize a packet object from a byte array.
*
* @param data input array to take packet bytes from
* @param offset index where this packet header begins in the byte array
* @param length length of the packet header
* @return a deserialized packet object
* @throws DeserializationException if the packet cannot be deserialized
* from the input
*/
U deserialize(byte[] data, int offset, int length) throws DeserializationException;
}
......@@ -93,25 +93,27 @@ public class EthType {
public static enum EtherType {
ARP(0x806, "arp", ARP.class),
RARP(0x8035, "rarp", null),
IPV4(0x800, "ipv4", IPv4.class),
IPV6(0x86dd, "ipv6", IPv6.class),
LLDP(0x88cc, "lldp", LLDP.class),
VLAN(0x8100, "vlan", null),
BDDP(0x8942, "bddp", LLDP.class),
MPLS_UNICAST(0x8847, "mpls_unicast", null),
MPLS_MULTICAST(0x8848, "mpls_unicast", null);
ARP(0x806, "arp", ARP.class, org.onlab.packet.ARP.deserializer()),
RARP(0x8035, "rarp", null, org.onlab.packet.ARP.deserializer()),
IPV4(0x800, "ipv4", IPv4.class, org.onlab.packet.IPv4.deserializer()),
IPV6(0x86dd, "ipv6", IPv6.class, org.onlab.packet.IPv6.deserializer()),
LLDP(0x88cc, "lldp", LLDP.class, org.onlab.packet.LLDP.deserializer()),
VLAN(0x8100, "vlan", null, null),
BDDP(0x8942, "bddp", LLDP.class, org.onlab.packet.LLDP.deserializer()),
MPLS_UNICAST(0x8847, "mpls_unicast", null, org.onlab.packet.MPLS.deserializer()),
MPLS_MULTICAST(0x8848, "mpls_unicast", null, org.onlab.packet.MPLS.deserializer());
private final Class clazz;
private EthType ethType;
private String type;
private Deserializer<?> deserializer;
EtherType(int ethType, String type, Class clazz) {
EtherType(int ethType, String type, Class clazz, Deserializer deserializer) {
this.ethType = new EthType(ethType);
this.type = type;
this.clazz = clazz;
this.deserializer = deserializer;
}
public EthType ethType() {
......@@ -127,6 +129,8 @@ public class EthType {
return clazz;
}
public Deserializer<?> deserializer() {
return deserializer;
}
}
}
......
......@@ -18,13 +18,14 @@
package org.onlab.packet;
import static com.google.common.base.Preconditions.checkNotNull;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.packet.PacketUtils.checkHeaderLength;
import static org.onlab.packet.PacketUtils.checkInput;
/**
*
......@@ -42,15 +43,21 @@ public class Ethernet extends BasePacket {
public static final short MPLS_UNICAST = EthType.MPLS_UNICAST;
public static final short MPLS_MULTICAST = EthType.MPLS_MULTICAST;
public static final short VLAN_UNTAGGED = (short) 0xffff;
public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
public static final short VLAN_HEADER_LENGTH = 4; // bytes
public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
public static final Map<Short, Class<? extends IPacket>> ETHER_TYPE_CLASS_MAP =
new HashMap<>();
private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP =
new HashMap<>();
static {
for (EthType.EtherType ethType : EthType.EtherType.values()) {
if (ethType.clazz() != null) {
ETHER_TYPE_CLASS_MAP.put(ethType.ethType().toShort(), ethType.clazz());
ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer());
}
}
}
......@@ -300,7 +307,7 @@ public class Ethernet extends BasePacket {
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final int length) {
if (length <= 0) {
return null;
}
......@@ -331,21 +338,19 @@ public class Ethernet extends BasePacket {
this.etherType = ethType;
IPacket payload;
if (Ethernet.ETHER_TYPE_CLASS_MAP.containsKey(this.etherType)) {
final Class<? extends IPacket> clazz = Ethernet.ETHER_TYPE_CLASS_MAP
.get(this.etherType);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for Ethernet packet", e);
}
Deserializer<? extends IPacket> deserializer;
if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
} else {
payload = new Data();
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
......@@ -567,4 +572,53 @@ public class Ethernet extends BasePacket {
return builder.toString();
}
/**
* Deserializer function for Ethernet packets.
*
* @return deserializer function
*/
public static Deserializer<Ethernet> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
Ethernet eth = new Ethernet();
// Read destination MAC address into buffer
bb.get(addressBuffer);
eth.setDestinationMACAddress(addressBuffer);
// Read source MAC address into buffer
bb.get(addressBuffer);
eth.setSourceMACAddress(addressBuffer);
short ethType = bb.getShort();
if (ethType == TYPE_VLAN) {
checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
final short tci = bb.getShort();
eth.setPriorityCode((byte) (tci >> 13 & 0x07));
eth.setVlanID((short) (tci & 0x0fff));
ethType = bb.getShort();
} else {
eth.setVlanID(Ethernet.VLAN_UNTAGGED);
}
eth.setEtherType(ethType);
IPacket payload;
Deserializer<? extends IPacket> deserializer;
if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
} else {
deserializer = Data.deserializer();
}
payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
payload.setParent(eth);
eth.setPayload(payload);
return eth;
};
}
}
......
......@@ -20,6 +20,8 @@ package org.onlab.packet;
import java.nio.ByteBuffer;
import static org.onlab.packet.PacketUtils.*;
/**
* Implements ICMP packet format.
*
......@@ -33,6 +35,8 @@ public class ICMP extends BasePacket {
public static final byte TYPE_ECHO_REPLY = 0x00;
public static final byte SUBTYPE_ECHO_REPLY = 0x00;
public static final short ICMP_HEADER_LENGTH = 4;
/**
* @return the icmpType
*/
......@@ -134,6 +138,21 @@ public class ICMP extends BasePacket {
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.icmpType = bb.get();
this.icmpCode = bb.get();
this.checksum = bb.getShort();
this.payload = new Data();
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
}
/*
* (non-Javadoc)
*
......@@ -178,18 +197,27 @@ public class ICMP extends BasePacket {
return true;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.icmpType = bb.get();
this.icmpCode = bb.get();
this.checksum = bb.getShort();
this.payload = new Data();
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
/**
* Deserializer function for ICMP packets.
*
* @return deserializer function
*/
public static Deserializer<ICMP> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, ICMP_HEADER_LENGTH);
ICMP icmp = new ICMP();
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
icmp.icmpType = bb.get();
icmp.icmpCode = bb.get();
icmp.checksum = bb.getShort();
icmp.payload = Data.deserializer()
.deserialize(data, bb.position(), bb.limit()
- bb.position());
icmp.payload.setParent(icmp);
return icmp;
};
}
}
......
......@@ -24,10 +24,13 @@ import org.onlab.packet.ndp.NeighborSolicitation;
import org.onlab.packet.ndp.Redirect;
import org.onlab.packet.ndp.RouterAdvertisement;
import org.onlab.packet.ndp.RouterSolicitation;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements ICMPv6 packet format. (RFC 4443)
*/
......@@ -96,15 +99,15 @@ public class ICMP6 extends BasePacket {
/** Unrecognized IPv6 option encountered. */
public static final byte IPV6_OPT_ERR = (byte) 0x01;
public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP =
public static final Map<Byte, Deserializer<? extends IPacket>> TYPE_DESERIALIZER_MAP =
new HashMap<>();
static {
ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.ROUTER_SOLICITATION, RouterSolicitation.class);
ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.ROUTER_ADVERTISEMENT, RouterAdvertisement.class);
ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.NEIGHBOR_SOLICITATION, NeighborSolicitation.class);
ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.NEIGHBOR_ADVERTISEMENT, NeighborAdvertisement.class);
ICMP6.PROTOCOL_CLASS_MAP.put(ICMP6.REDIRECT, Redirect.class);
ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.ROUTER_SOLICITATION, RouterSolicitation.deserializer());
ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.ROUTER_ADVERTISEMENT, RouterAdvertisement.deserializer());
ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.NEIGHBOR_SOLICITATION, NeighborSolicitation.deserializer());
ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.NEIGHBOR_ADVERTISEMENT, NeighborAdvertisement.deserializer());
ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.REDIRECT, Redirect.deserializer());
}
protected byte icmpType;
......@@ -261,6 +264,31 @@ public class ICMP6 extends BasePacket {
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.icmpType = bb.get();
this.icmpCode = bb.get();
this.checksum = bb.getShort();
Deserializer<? extends IPacket> deserializer;
if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmpType)) {
deserializer = TYPE_DESERIALIZER_MAP.get(icmpType);
} else {
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
return this;
}
/*
* (non-Javadoc)
*
......@@ -305,31 +333,34 @@ public class ICMP6 extends BasePacket {
return true;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.icmpType = bb.get();
this.icmpCode = bb.get();
this.checksum = bb.getShort();
/**
* Deserializer function for ICMPv6 packets.
*
* @return deserializer function
*/
public static Deserializer<ICMP6> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
ICMP6 icmp6 = new ICMP6();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
IPacket payload;
if (ICMP6.PROTOCOL_CLASS_MAP.containsKey(this.icmpType)) {
final Class<? extends IPacket> clazz = ICMP6.PROTOCOL_CLASS_MAP
.get(this.icmpType);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for ICMP6 packet", e);
icmp6.icmpType = bb.get();
icmp6.icmpCode = bb.get();
icmp6.checksum = bb.getShort();
Deserializer<? extends IPacket> deserializer;
if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmp6.icmpType)) {
deserializer = TYPE_DESERIALIZER_MAP.get(icmp6.icmpType);
} else {
deserializer = Data.deserializer();
}
} else {
payload = new Data();
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
icmp6.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
icmp6.payload.setParent(icmp6);
return this;
return icmp6;
};
}
}
......
......@@ -64,6 +64,11 @@ public interface IPacket {
/**
* Deserializes this packet layer and all possible payloads.
*
* NOTE: This method has been deprecated and will be removed in a future
* release. It is now recommended to use the Deserializer function provided
* by the deserialize() method on each packet to deserialize them. The
* Deserializer functions are robust to malformed input.
*
* @param data bytes to deserialize
* @param offset
* offset to start deserializing from
......@@ -71,6 +76,7 @@ public interface IPacket {
* length of the data to deserialize
* @return the deserialized data
*/
@Deprecated
IPacket deserialize(byte[] data, int offset, int length);
/**
......
......@@ -25,6 +25,8 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import static org.onlab.packet.PacketUtils.*;
/**
*
*/
......@@ -32,19 +34,21 @@ public class IPv4 extends BasePacket {
public static final byte PROTOCOL_ICMP = 0x1;
public static final byte PROTOCOL_TCP = 0x6;
public static final byte PROTOCOL_UDP = 0x11;
public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP =
public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
new HashMap<>();
static {
IPv4.PROTOCOL_CLASS_MAP.put(IPv4.PROTOCOL_ICMP, ICMP.class);
IPv4.PROTOCOL_CLASS_MAP.put(IPv4.PROTOCOL_TCP, TCP.class);
IPv4.PROTOCOL_CLASS_MAP.put(IPv4.PROTOCOL_UDP, UDP.class);
IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_ICMP, ICMP.deserializer());
IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_TCP, TCP.deserializer());
IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_UDP, UDP.deserializer());
}
private static final byte DSCP_MASK = 0x3f;
private static final byte DSCP_OFFSET = 2;
private static final byte ECN_MASK = 0x3;
private static final short HEADER_LENGTH = 20;
protected byte version;
protected byte headerLength;
protected byte diffServ;
......@@ -414,7 +418,7 @@ s */
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
short sscratch;
......@@ -439,29 +443,26 @@ s */
bb.get(this.options);
}
IPacket payload;
if (IPv4.PROTOCOL_CLASS_MAP.containsKey(this.protocol)) {
final Class<? extends IPacket> clazz = IPv4.PROTOCOL_CLASS_MAP
.get(this.protocol);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for IPv4 packet", e);
}
} else {
payload = new Data();
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
if (this.totalLength != length) {
this.isTruncated = true;
} else {
this.isTruncated = false;
}
Deserializer<? extends IPacket> deserializer;
if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(this.protocol)) {
deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(this.protocol);
} else {
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
return this;
}
......@@ -669,4 +670,60 @@ s */
}
return true;
}
/**
* Deserializer function for IPv4 packets.
*
* @return deserializer function
*/
public static Deserializer<IPv4> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
IPv4 ipv4 = new IPv4();
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
byte versionByte = bb.get();
ipv4.headerLength = (byte) (versionByte & 0xf);
ipv4.setVersion((byte) (versionByte >> 4 & 0xf));
ipv4.setDiffServ(bb.get());
ipv4.totalLength = bb.getShort();
ipv4.identification = bb.getShort();
short flagsFragment = bb.getShort();
ipv4.flags = (byte) (flagsFragment >> 13 & 0x7);
ipv4.fragmentOffset = (short) (flagsFragment & 0x1fff);
ipv4.ttl = bb.get();
ipv4.protocol = bb.get();
ipv4.checksum = bb.getShort();
ipv4.sourceAddress = bb.getInt();
ipv4.destinationAddress = bb.getInt();
if (ipv4.headerLength > 5) {
checkHeaderLength(length, ipv4.headerLength * 4);
int optionsLength = (ipv4.headerLength - 5) * 4;
ipv4.options = new byte[optionsLength];
bb.get(ipv4.options);
}
Deserializer<? extends IPacket> deserializer;
if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv4.protocol)) {
deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(ipv4.protocol);
} else {
deserializer = Data.deserializer();
}
ipv4.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
ipv4.payload.setParent(ipv4);
if (ipv4.totalLength != length) {
ipv4.isTruncated = true;
} else {
ipv4.isTruncated = false;
}
return ipv4;
};
}
}
......
......@@ -22,14 +22,17 @@ import org.onlab.packet.ipv6.Authentication;
import org.onlab.packet.ipv6.DestinationOptions;
import org.onlab.packet.ipv6.EncapSecurityPayload;
import org.onlab.packet.ipv6.Fragment;
import org.onlab.packet.ipv6.IExtensionHeader;
import org.onlab.packet.ipv6.HopByHopOptions;
import org.onlab.packet.ipv6.IExtensionHeader;
import org.onlab.packet.ipv6.Routing;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements IPv6 packet format. (RFC 2460)
*/
......@@ -47,19 +50,19 @@ public class IPv6 extends BasePacket implements IExtensionHeader {
public static final byte PROTOCOL_DSTOPT = 0x3C;
public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP =
public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
new HashMap<>();
static {
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_TCP, TCP.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_UDP, UDP.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_AH, Authentication.class);
IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.class);
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_TCP, TCP.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_UDP, UDP.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_AH, Authentication.deserializer());
IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.deserializer());
}
protected byte version;
......@@ -256,22 +259,19 @@ public class IPv6 extends BasePacket implements IExtensionHeader {
bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
IPacket payload;
if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
.get(this.nextHeader);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for IPv6 packet", e);
}
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
} else {
payload = new Data();
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
......@@ -343,4 +343,42 @@ public class IPv6 extends BasePacket implements IExtensionHeader {
}
return true;
}
/**
* Deserializer function for IPv6 packets.
*
* @return deserializer function
*/
public static Deserializer<IPv6> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, FIXED_HEADER_LENGTH);
IPv6 ipv6 = new IPv6();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
int iscratch = bb.getInt();
ipv6.version = (byte) (iscratch >> 28 & 0xf);
ipv6.trafficClass = (byte) (iscratch >> 20 & 0xff);
ipv6.flowLabel = iscratch & 0xfffff;
ipv6.payloadLength = bb.getShort();
ipv6.nextHeader = bb.get();
ipv6.hopLimit = bb.get();
bb.get(ipv6.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
bb.get(ipv6.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv6.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(ipv6.nextHeader);
} else {
deserializer = Data.deserializer();
}
ipv6.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
ipv6.payload.setParent(ipv6);
return ipv6;
};
}
}
......
......@@ -20,6 +20,8 @@ package org.onlab.packet;
import java.nio.ByteBuffer;
import static org.onlab.packet.PacketUtils.*;
/**
* This class represents an Link Local Control header that is used in Ethernet
* 802.3.
......@@ -27,6 +29,9 @@ import java.nio.ByteBuffer;
*
*/
public class LLC extends BasePacket {
public static final byte LLC_HEADER_LENGTH = 3;
private byte dsap = 0;
private byte ssap = 0;
private byte ctrl = 0;
......@@ -67,11 +72,31 @@ public class LLC extends BasePacket {
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.dsap = bb.get();
this.ssap = bb.get();
this.ctrl = bb.get();
return this;
}
/**
* Deserializer function for LLC packets.
*
* @return deserializer function
*/
public static Deserializer<LLC> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, LLC_HEADER_LENGTH);
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
LLC llc = new LLC();
llc.dsap = bb.get();
llc.ssap = bb.get();
llc.ctrl = bb.get();
return llc;
};
}
}
......
......@@ -20,13 +20,26 @@
package org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import static org.onlab.packet.PacketUtils.*;
/**
*
*/
public class LLDP extends BasePacket {
public static final byte CHASSIS_TLV_TYPE = 1;
public static final short CHASSIS_TLV_SIZE = 7;
public static final byte CHASSIS_TLV_SUBTYPE = 4;
public static final byte PORT_TLV_TYPE = 2;
public static final short PORT_TLV_SIZE = 5;
public static final byte PORT_TLV_SUBTYPE = 2;
public static final byte TTL_TLV_TYPE = 3;
public static final short TTL_TLV_SIZE = 2;
protected LLDPTLV chassisId;
protected LLDPTLV portId;
protected LLDPTLV ttl;
......@@ -34,7 +47,7 @@ public class LLDP extends BasePacket {
protected short ethType;
public LLDP() {
this.optionalTLVList = new ArrayList<LLDPTLV>();
this.optionalTLVList = new LinkedList<>();
this.ethType = Ethernet.TYPE_LLDP;
}
......@@ -134,11 +147,15 @@ public class LLDP extends BasePacket {
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
LLDPTLV tlv;
do {
tlv = new LLDPOrganizationalTLV().deserialize(bb);
try {
tlv = new LLDPOrganizationalTLV().deserialize(bb);
} catch (DeserializationException e) {
break;
}
// if there was a failure to deserialize stop processing TLVs
if (tlv == null) {
......@@ -227,4 +244,57 @@ public class LLDP extends BasePacket {
}
return true;
}
/**
* Deserializer function for LLDP packets.
*
* @return deserializer function
*/
public static Deserializer<LLDP> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, 0);
LLDP lldp = new LLDP();
int currentIndex = 0;
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
LLDPTLV tlv;
do {
// Each new TLV must be a minimum of 2 bytes
// (containing the type and length fields).
currentIndex += 2;
checkHeaderLength(length, currentIndex);
tlv = new LLDPOrganizationalTLV().deserialize(bb);
// if there was a failure to deserialize stop processing TLVs
if (tlv == null) {
break;
}
switch (tlv.getType()) {
case 0x0:
// can throw this one away, it's just an end delimiter
break;
case 0x1:
lldp.chassisId = tlv;
break;
case 0x2:
lldp.portId = tlv;
break;
case 0x3:
lldp.ttl = tlv;
break;
default:
lldp.optionalTLVList.add(tlv);
break;
}
currentIndex += tlv.getLength();
} while (tlv.getType() != 0);
return lldp;
};
}
}
......
......@@ -154,10 +154,15 @@ public class LLDPOrganizationalTLV extends LLDPTLV {
}
@Override
public LLDPTLV deserialize(final ByteBuffer bb) {
LLDPTLV tlv = super.deserialize(bb);
if (tlv.getType() != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
return tlv;
public LLDPTLV deserialize(final ByteBuffer bb) throws DeserializationException {
super.deserialize(bb);
if (this.getType() != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
return this;
}
if (this.getLength() <= OUI_LENGTH + SUBTYPE_LENGTH) {
throw new DeserializationException(
"TLV length is less than required for organizational TLV");
}
final ByteBuffer optionalField = ByteBuffer.wrap(this.value);
......
......@@ -95,18 +95,23 @@ public class LLDPTLV {
return data;
}
public LLDPTLV deserialize(final ByteBuffer bb) {
short sscratch;
sscratch = bb.getShort();
this.type = (byte) (sscratch >> 9 & 0x7f);
this.length = (short) (sscratch & 0x1ff);
public LLDPTLV deserialize(final ByteBuffer bb) throws DeserializationException {
if (bb.remaining() < 2) {
throw new DeserializationException(
"Not enough bytes to deserialize TLV type and length");
}
short typeLength;
typeLength = bb.getShort();
this.type = (byte) (typeLength >> 9 & 0x7f);
this.length = (short) (typeLength & 0x1ff);
if (this.length > 0) {
this.value = new byte[this.length];
// if there is an underrun just toss the TLV
if (bb.remaining() < this.length) {
return null;
throw new DeserializationException(
"Remaining bytes are less then the length of the TLV");
}
bb.get(this.value);
}
......
......@@ -4,16 +4,19 @@ import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.onlab.packet.PacketUtils.checkInput;
public class MPLS extends BasePacket {
public static final int ADDRESS_LENGTH = 4;
public static final int HEADER_LENGTH = 4;
public static final byte PROTOCOL_IPV4 = 0x1;
public static final byte PROTOCOL_MPLS = 0x6;
public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP;
static Map<Byte, Deserializer<? extends IPacket>> protocolDeserializerMap
= new HashMap<>();
static {
PROTOCOL_CLASS_MAP = new HashMap<Byte, Class<? extends IPacket>>();
PROTOCOL_CLASS_MAP.put(PROTOCOL_IPV4, IPv4.class);
PROTOCOL_CLASS_MAP.put(PROTOCOL_MPLS, MPLS.class);
protocolDeserializerMap.put(PROTOCOL_IPV4, IPv4.deserializer());
protocolDeserializerMap.put(PROTOCOL_MPLS, MPLS.deserializer());
}
protected int label; //20bits
......@@ -59,19 +62,18 @@ public class MPLS extends BasePacket {
this.bos = (byte) (mplsheader & 0x000000ff);
this.protocol = (this.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;
IPacket payload;
if (IPv4.PROTOCOL_CLASS_MAP.containsKey(this.protocol)) {
Class<? extends IPacket> clazz = IPv4.PROTOCOL_CLASS_MAP.get(this.protocol);
try {
payload = clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("Error parsing payload for MPLS packet", e);
}
Deserializer<? extends IPacket> deserializer;
if (protocolDeserializerMap.containsKey(this.protocol)) {
deserializer = protocolDeserializerMap.get(this.protocol);
} else {
payload = new Data();
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
......@@ -112,4 +114,34 @@ public class MPLS extends BasePacket {
this.ttl = ttl;
}
/**
* Deserializer function for MPLS packets.
*
* @return deserializer function
*/
public static Deserializer<MPLS> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
MPLS mpls = new MPLS();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
int mplsheader = bb.getInt();
mpls.label = ((mplsheader & 0xfffff000) >>> 12);
mpls.bos = (byte) ((mplsheader & 0x00000100) >> 8);
mpls.ttl = (byte) (mplsheader & 0x000000ff);
mpls.protocol = (mpls.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;
Deserializer<? extends IPacket> deserializer;
if (protocolDeserializerMap.containsKey(mpls.protocol)) {
deserializer = protocolDeserializerMap.get(mpls.protocol);
} else {
deserializer = Data.deserializer();
}
mpls.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
mpls.payload.setParent(mpls);
return mpls;
};
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Utilities for working with packet headers.
*/
public final class PacketUtils {
private PacketUtils() {
}
/**
* Check the length of the input buffer is appropriate given the offset and
* length parameters.
*
* @param byteLength length of the input buffer array
* @param offset offset given to begin reading bytes from
* @param length length given to read up until
* @throws DeserializationException if the input parameters don't match up (i.e
* we can't read that many bytes from the buffer at the given offest)
*/
public static void checkBufferLength(int byteLength, int offset, int length)
throws DeserializationException {
boolean ok = (offset >= 0 && offset < byteLength);
ok = ok & (length >= 0 && offset + length <= byteLength);
if (!ok) {
throw new DeserializationException("Unable to read " + length + " bytes from a "
+ byteLength + " byte array starting at offset " + offset);
}
}
/**
* Check that there are enough bytes in the buffer to read some number of
* bytes that we need to read a full header.
*
* @param givenLength given size of the buffer
* @param requiredLength number of bytes we need to read some header fully
* @throws DeserializationException if there aren't enough bytes
*/
public static void checkHeaderLength(int givenLength, int requiredLength)
throws DeserializationException {
if (requiredLength > givenLength) {
throw new DeserializationException(requiredLength
+ " bytes are needed to continue deserialization, however only "
+ givenLength + " remain in buffer");
}
}
/**
* Check the input parameters are sane and there's enough bytes to read
* the required length.
*
* @param data input byte buffer
* @param offset offset of the start of the header
* @param length length given to deserialize the header
* @param requiredLength length needed to deserialize header
* @throws DeserializationException if we're unable to deserialize the
* packet based on the input parameters
*/
public static void checkInput(byte[] data, int offset, int length, int requiredLength)
throws DeserializationException {
checkNotNull(data);
checkBufferLength(data.length, offset, length);
checkHeaderLength(length, requiredLength);
}
}
......@@ -20,11 +20,16 @@ package org.onlab.packet;
import java.nio.ByteBuffer;
import static org.onlab.packet.PacketUtils.*;
/**
* Implements TCP packet format.
*/
public class TCP extends BasePacket {
private static final short TCP_HEADER_LENGTH = 20;
protected short sourcePort;
protected short destinationPort;
protected int sequence;
......@@ -339,6 +344,40 @@ public class TCP extends BasePacket {
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.sourcePort = bb.getShort();
this.destinationPort = bb.getShort();
this.sequence = bb.getInt();
this.acknowledge = bb.getInt();
this.flags = bb.getShort();
this.dataOffset = (byte) (this.flags >> 12 & 0xf);
this.flags = (short) (this.flags & 0x1ff);
this.windowSize = bb.getShort();
this.checksum = bb.getShort();
this.urgentPointer = bb.getShort();
if (this.dataOffset > 5) {
int optLength = (this.dataOffset << 2) - 20;
if (bb.limit() < bb.position() + optLength) {
optLength = bb.limit() - bb.position();
}
try {
this.options = new byte[optLength];
bb.get(this.options, 0, optLength);
} catch (final IndexOutOfBoundsException e) {
this.options = null;
}
}
this.payload = new Data();
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
}
/*
* (non-Javadoc)
*
......@@ -384,37 +423,39 @@ public class TCP extends BasePacket {
&& (this.dataOffset == 5 || this.options.equals(other.options));
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.sourcePort = bb.getShort();
this.destinationPort = bb.getShort();
this.sequence = bb.getInt();
this.acknowledge = bb.getInt();
this.flags = bb.getShort();
this.dataOffset = (byte) (this.flags >> 12 & 0xf);
this.flags = (short) (this.flags & 0x1ff);
this.windowSize = bb.getShort();
this.checksum = bb.getShort();
this.urgentPointer = bb.getShort();
if (this.dataOffset > 5) {
int optLength = (this.dataOffset << 2) - 20;
if (bb.limit() < bb.position() + optLength) {
optLength = bb.limit() - bb.position();
}
try {
this.options = new byte[optLength];
bb.get(this.options, 0, optLength);
} catch (final IndexOutOfBoundsException e) {
this.options = null;
/**
* Deserializer function for TCP packets.
*
* @return deserializer function
*/
public static Deserializer<TCP> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, TCP_HEADER_LENGTH);
TCP tcp = new TCP();
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
tcp.sourcePort = bb.getShort();
tcp.destinationPort = bb.getShort();
tcp.sequence = bb.getInt();
tcp.acknowledge = bb.getInt();
tcp.flags = bb.getShort();
tcp.dataOffset = (byte) (tcp.flags >> 12 & 0xf);
tcp.flags = (short) (tcp.flags & 0x1ff);
tcp.windowSize = bb.getShort();
tcp.checksum = bb.getShort();
tcp.urgentPointer = bb.getShort();
if (tcp.dataOffset > 5) {
int optLength = (tcp.dataOffset << 2) - 20;
checkHeaderLength(length, TCP_HEADER_LENGTH + tcp.dataOffset);
tcp.options = new byte[optLength];
bb.get(tcp.options, 0, optLength);
}
}
this.payload = new Data();
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
tcp.payload = Data.deserializer()
.deserialize(data, bb.position(), bb.limit() - bb.position());
tcp.payload.setParent(tcp);
return tcp;
};
}
}
......
......@@ -22,23 +22,27 @@ import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.onlab.packet.PacketUtils.*;
/**
*
*/
public class UDP extends BasePacket {
public static final Map<Short, Class<? extends IPacket>> DECODE_MAP =
public static final Map<Short, Deserializer<? extends IPacket>> PORT_DESERIALIZER_MAP =
new HashMap<>();
public static final short DHCP_SERVER_PORT = (short) 67;
public static final short DHCP_CLIENT_PORT = (short) 68;
private static final short UDP_HEADER_LENGTH = 8;
static {
/*
* Disable DHCP until the deserialize code is hardened to deal with
* garbage input
*/
UDP.DECODE_MAP.put(UDP.DHCP_SERVER_PORT, DHCP.class);
UDP.DECODE_MAP.put(UDP.DHCP_CLIENT_PORT, DHCP.class);
UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_SERVER_PORT, DHCP.deserializer());
UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_CLIENT_PORT, DHCP.deserializer());
}
......@@ -192,6 +196,34 @@ public class UDP extends BasePacket {
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.sourcePort = bb.getShort();
this.destinationPort = bb.getShort();
this.length = bb.getShort();
this.checksum = bb.getShort();
Deserializer<? extends IPacket> deserializer;
if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.destinationPort)) {
deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.destinationPort);
} else if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.sourcePort)) {
deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.sourcePort);
} else {
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
return this;
}
/*
* (non-Javadoc)
*
......@@ -240,35 +272,36 @@ public class UDP extends BasePacket {
return true;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.sourcePort = bb.getShort();
this.destinationPort = bb.getShort();
this.length = bb.getShort();
this.checksum = bb.getShort();
/**
* Deserializer function for UDP packets.
*
* @return deserializer function
*/
public static Deserializer<UDP> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, UDP_HEADER_LENGTH);
if (UDP.DECODE_MAP.containsKey(this.destinationPort)) {
try {
this.payload = UDP.DECODE_MAP.get(this.destinationPort)
.getConstructor().newInstance();
} catch (final Exception e) {
throw new RuntimeException("Failure instantiating class", e);
}
} else if (UDP.DECODE_MAP.containsKey(this.sourcePort)) {
try {
this.payload = UDP.DECODE_MAP.get(this.sourcePort)
.getConstructor().newInstance();
} catch (final Exception e) {
throw new RuntimeException("Failure instantiating class", e);
UDP udp = new UDP();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
udp.sourcePort = bb.getShort();
udp.destinationPort = bb.getShort();
udp.length = bb.getShort();
udp.checksum = bb.getShort();
Deserializer<? extends IPacket> deserializer;
if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.destinationPort)) {
deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.destinationPort);
} else if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.sourcePort)) {
deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.sourcePort);
} else {
deserializer = Data.deserializer();
}
} else {
this.payload = new Data();
}
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
udp.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
udp.payload.setParent(udp);
return udp;
};
}
}
......
......@@ -18,11 +18,16 @@ package org.onlab.packet.ipv6;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.IPv6;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements IPv6 authentication extension header format. (RFC 4302)
*/
......@@ -186,22 +191,20 @@ public class Authentication extends BasePacket implements IExtensionHeader {
this.integrityCheck = new byte[icvLength];
bb.get(this.integrityCheck, 0, icvLength);
IPacket payload;
if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
.get(this.nextHeader);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for Authentication packet", e);
}
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
} else {
payload = new Data();
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
......@@ -259,4 +262,39 @@ public class Authentication extends BasePacket implements IExtensionHeader {
}
return true;
}
/**
* Deserializer function for authentication headers.
*
* @return deserializer function
*/
public static Deserializer<Authentication> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, FIXED_HEADER_LENGTH);
Authentication authentication = new Authentication();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
authentication.nextHeader = bb.get();
authentication.payloadLength = bb.get();
bb.getShort();
authentication.securityParamIndex = bb.getInt();
authentication.sequence = bb.getInt();
int icvLength = (authentication.payloadLength + MINUS) * LENGTH_UNIT - FIXED_HEADER_LENGTH;
authentication.integrityCheck = new byte[icvLength];
bb.get(authentication.integrityCheck, 0, icvLength);
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(authentication.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(authentication.nextHeader);
} else {
deserializer = Data.deserializer();
}
authentication.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
authentication.payload.setParent(authentication);
return authentication;
};
}
}
......
......@@ -18,12 +18,17 @@ package org.onlab.packet.ipv6;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.IPv6;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.onlab.packet.PacketUtils.checkHeaderLength;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Base class for hop-by-hop options and destination options.
*/
......@@ -151,22 +156,19 @@ public class BaseOptions extends BasePacket implements IExtensionHeader {
this.options = new byte[optionLength];
bb.get(this.options, 0, optionLength);
IPacket payload;
if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
.get(this.nextHeader);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for BaseOptions packet", e);
}
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
} else {
payload = new Data();
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
......@@ -219,4 +221,40 @@ public class BaseOptions extends BasePacket implements IExtensionHeader {
}
return true;
}
/**
* Deserializer function for IPv6 base options.
*
* @return deserializer function
*/
public static Deserializer<BaseOptions> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, FIXED_HEADER_LENGTH);
BaseOptions baseOptions = new BaseOptions();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
baseOptions.nextHeader = bb.get();
baseOptions.headerExtLength = bb.get();
int optionLength =
FIXED_OPTIONS_LENGTH + LENGTH_UNIT * baseOptions.headerExtLength;
checkHeaderLength(bb.remaining(), optionLength);
baseOptions.options = new byte[optionLength];
bb.get(baseOptions.options, 0, optionLength);
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(baseOptions.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(baseOptions.nextHeader);
} else {
deserializer = Data.deserializer();
}
baseOptions.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
baseOptions.payload.setParent(baseOptions);
return baseOptions;
};
}
}
......
......@@ -18,10 +18,14 @@ package org.onlab.packet.ipv6;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Data;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.IPv6;
import java.nio.ByteBuffer;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements IPv6 Encapsulating Security Payload (ESP) extension header format.
* (RFC 4303)
......@@ -113,7 +117,7 @@ public class EncapSecurityPayload extends BasePacket {
this.payload = new Data();
this.payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
......@@ -158,4 +162,27 @@ public class EncapSecurityPayload extends BasePacket {
}
return true;
}
/**
* Deserializer function for encapsulated security payload headers.
*
* @return deserializer function
*/
public static Deserializer<EncapSecurityPayload> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
EncapSecurityPayload encapSecurityPayload = new EncapSecurityPayload();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
encapSecurityPayload.securityParamIndex = bb.getInt();
encapSecurityPayload.sequence = bb.getInt();
encapSecurityPayload.payload = Data.deserializer().deserialize(
data, bb.position(), bb.limit() - bb.position());
encapSecurityPayload.payload.setParent(encapSecurityPayload);
return encapSecurityPayload;
};
}
}
......
......@@ -18,11 +18,15 @@ package org.onlab.packet.ipv6;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.IPv6;
import java.nio.ByteBuffer;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements IPv6 fragment extension header format. (RFC 2460)
*/
......@@ -149,22 +153,19 @@ public class Fragment extends BasePacket implements IExtensionHeader {
this.moreFragment = (byte) (sscratch & 0x1);
this.identification = bb.getInt();
IPacket payload;
if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
.get(this.nextHeader);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for Fragment packet", e);
}
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
} else {
payload = new Data();
deserializer = Data.deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
......@@ -216,4 +217,37 @@ public class Fragment extends BasePacket implements IExtensionHeader {
}
return true;
}
/**
* Deserializer function for fragment headers.
*
* @return deserializer function
*/
public static Deserializer<Fragment> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
Fragment fragment = new Fragment();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
fragment.nextHeader = bb.get();
bb.get();
short sscratch = bb.getShort();
fragment.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
fragment.moreFragment = (byte) (sscratch & 0x1);
fragment.identification = bb.getInt();
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(fragment.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(fragment.nextHeader);
} else {
deserializer = Data.deserializer();
}
fragment.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
fragment.payload.setParent(fragment);
return fragment;
};
}
}
......
......@@ -18,12 +18,17 @@ package org.onlab.packet.ipv6;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.IPv6;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.onlab.packet.PacketUtils.checkHeaderLength;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements IPv6 routing extension header format. (RFC 2460)
*/
......@@ -175,22 +180,19 @@ public class Routing extends BasePacket implements IExtensionHeader {
this.routingData = new byte[dataLength];
bb.get(this.routingData, 0, dataLength);
IPacket payload;
if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
.get(this.nextHeader);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for Routing packet", e);
}
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
} else {
payload = new Data();
deserializer = new Data().deserializer();
}
try {
this.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
} catch (DeserializationException e) {
return this;
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
......@@ -248,4 +250,42 @@ public class Routing extends BasePacket implements IExtensionHeader {
}
return true;
}
}
\ No newline at end of file
/**
* Deserializer function for routing headers.
*
* @return deserializer function
*/
public static Deserializer<Routing> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, FIXED_HEADER_LENGTH);
Routing routing = new Routing();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
routing.nextHeader = bb.get();
routing.headerExtLength = bb.get();
routing.routingType = bb.get();
routing.segmentsLeft = bb.get();
int dataLength =
FIXED_ROUTING_DATA_LENGTH + LENGTH_UNIT * routing.headerExtLength;
checkHeaderLength(bb.remaining(), dataLength);
routing.routingData = new byte[dataLength];
bb.get(routing.routingData, 0, dataLength);
Deserializer<? extends IPacket> deserializer;
if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(routing.nextHeader)) {
deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(routing.nextHeader);
} else {
deserializer = new Data().deserializer();
}
routing.payload = deserializer.deserialize(data, bb.position(),
bb.limit() - bb.position());
routing.payload.setParent(routing);
return routing;
};
}
}
......
......@@ -16,6 +16,7 @@
package org.onlab.packet.ndp;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.Ip6Address;
......@@ -23,6 +24,8 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements ICMPv6 Neighbor Advertisement packet format (RFC 4861).
*/
......@@ -238,4 +241,36 @@ public class NeighborAdvertisement extends BasePacket {
}
return true;
}
/**
* Deserializer function for neighbor advertisement packets.
*
* @return deserializer function
*/
public static Deserializer<NeighborAdvertisement> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
NeighborAdvertisement neighborAdvertisement = new NeighborAdvertisement();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
int iscratch;
iscratch = bb.getInt();
neighborAdvertisement.routerFlag = (byte) (iscratch >> 31 & 0x1);
neighborAdvertisement.solicitedFlag = (byte) (iscratch >> 30 & 0x1);
neighborAdvertisement.overrideFlag = (byte) (iscratch >> 29 & 0x1);
bb.get(neighborAdvertisement.targetAddress, 0, Ip6Address.BYTE_LENGTH);
NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
.deserialize(data, bb.position(), bb.limit() - bb.position());
for (NeighborDiscoveryOptions.Option option : options.options()) {
neighborAdvertisement.addOption(option.type(), option.data());
}
return neighborAdvertisement;
};
}
}
......
......@@ -15,13 +15,17 @@
*/
package org.onlab.packet.ndp;
import org.onlab.packet.BasePacket;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.onlab.packet.BasePacket;
import org.onlab.packet.IPacket;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Neighbor Discovery Protocol packet options.
......@@ -33,6 +37,11 @@ public class NeighborDiscoveryOptions extends BasePacket {
public static final byte TYPE_REDIRECTED_HEADER = 4;
public static final byte TYPE_MTU = 5;
public static final byte INITIAL_HEADER_REQUIRED = 2;
private static final String BUFFER_UNDERFLOW_ERROR =
"Not enough bytes in buffer to read option";
private final List<Option> options = new ArrayList<>();
/**
......@@ -187,7 +196,7 @@ public class NeighborDiscoveryOptions extends BasePacket {
}
byte lengthField = bb.get();
int dataLength = lengthField * 8; // The data length field is in
// unit of 8 octets
// unit of 8 octets
// Exclude the type and length fields
if (dataLength < 2) {
......@@ -229,4 +238,44 @@ public class NeighborDiscoveryOptions extends BasePacket {
}
return false;
}
public static Deserializer<NeighborDiscoveryOptions> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, INITIAL_HEADER_REQUIRED);
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
NeighborDiscoveryOptions ndo = new NeighborDiscoveryOptions();
ndo.options.clear();
//
// Deserialize all options
//
while (bb.hasRemaining()) {
byte type = bb.get();
if (!bb.hasRemaining()) {
throw new DeserializationException(BUFFER_UNDERFLOW_ERROR);
}
byte lengthField = bb.get();
int dataLength = lengthField * 8; // The data length field is in
// unit of 8 octets
// Exclude the type and length fields
if (dataLength < 2) {
break;
}
dataLength -= 2;
if (bb.remaining() < dataLength) {
throw new DeserializationException(BUFFER_UNDERFLOW_ERROR);
}
byte[] optionData = new byte[dataLength];
bb.get(optionData, 0, optionData.length);
ndo.addOption(type, optionData);
}
return ndo;
};
}
}
......
......@@ -16,6 +16,7 @@
package org.onlab.packet.ndp;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.Ip6Address;
......@@ -23,6 +24,8 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements ICMPv6 Neighbor Solicitation packet format. (RFC 4861)
*/
......@@ -157,4 +160,31 @@ public class NeighborSolicitation extends BasePacket {
}
return true;
}
/**
* Deserializer function for neighbor solicitation packets.
*
* @return deserializer function
*/
public static Deserializer<NeighborSolicitation> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
NeighborSolicitation neighborSolicitation = new NeighborSolicitation();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
bb.getInt();
bb.get(neighborSolicitation.targetAddress, 0, Ip6Address.BYTE_LENGTH);
NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
.deserialize(data, bb.position(), bb.limit() - bb.position());
for (NeighborDiscoveryOptions.Option option : options.options()) {
neighborSolicitation.addOption(option.type(), option.data());
}
return neighborSolicitation;
};
}
}
......
......@@ -16,6 +16,7 @@
package org.onlab.packet.ndp;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.Ip6Address;
......@@ -23,6 +24,8 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements ICMPv6 Redirect packet format. (RFC 4861)
*/
......@@ -188,4 +191,33 @@ public class Redirect extends BasePacket {
}
return true;
}
/**
* Deserializer function for redirect packets.
*
* @return deserializer function
*/
public static Deserializer<Redirect> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
Redirect redirect = new Redirect();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
bb.getInt();
bb.get(redirect.targetAddress, 0, Ip6Address.BYTE_LENGTH);
bb.get(redirect.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
.deserialize(data, bb.position(), bb.limit() - bb.position());
for (NeighborDiscoveryOptions.Option option : options.options()) {
redirect.addOption(option.type(), option.data());
}
return redirect;
};
}
}
......
......@@ -16,11 +16,14 @@
package org.onlab.packet.ndp;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import java.nio.ByteBuffer;
import java.util.List;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements ICMPv6 Router Advertisement packet format. (RFC 4861)
*/
......@@ -284,4 +287,37 @@ public class RouterAdvertisement extends BasePacket {
}
return true;
}
/**
* Deserializer function for router advertisement packets.
*
* @return deserializer function
*/
public static Deserializer<RouterAdvertisement> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
RouterAdvertisement routerAdvertisement = new RouterAdvertisement();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
int bscratch;
routerAdvertisement.currentHopLimit = bb.get();
bscratch = bb.get();
routerAdvertisement.mFlag = (byte) ((bscratch >> 7) & 0x1);
routerAdvertisement.oFlag = (byte) ((bscratch >> 6) & 0x1);
routerAdvertisement.routerLifetime = bb.getShort();
routerAdvertisement.reachableTime = bb.getInt();
routerAdvertisement.retransmitTimer = bb.getInt();
NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
.deserialize(data, bb.position(), bb.limit() - bb.position());
for (NeighborDiscoveryOptions.Option option : options.options()) {
routerAdvertisement.addOption(option.type(), option.data());
}
return routerAdvertisement;
};
}
}
......
......@@ -16,19 +16,21 @@
package org.onlab.packet.ndp;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import java.nio.ByteBuffer;
import java.util.List;
import static org.onlab.packet.PacketUtils.checkInput;
/**
* Implements ICMPv6 Router Solicitation packet format. (RFC 4861)
*/
public class RouterSolicitation extends BasePacket {
public static final byte HEADER_LENGTH = 4; // bytes
private final NeighborDiscoveryOptions options =
new NeighborDiscoveryOptions();
private final NeighborDiscoveryOptions options = new NeighborDiscoveryOptions();
/**
* Gets the Neighbor Discovery Protocol packet options.
......@@ -122,4 +124,30 @@ public class RouterSolicitation extends BasePacket {
}
return true;
}
/**
* Deserializer function for router solicitation packets.
*
* @return deserializer function
*/
public static Deserializer<RouterSolicitation> deserializer() {
return (data, offset, length) -> {
checkInput(data, offset, length, HEADER_LENGTH);
RouterSolicitation routerSolicitation = new RouterSolicitation();
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
bb.getInt();
NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer()
.deserialize(data, bb.position(), bb.limit() - bb.position());
for (NeighborDiscoveryOptions.Option option : options.options()) {
routerSolicitation.addOption(option.type(), option.data());
}
return routerSolicitation;
};
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Unit tests for the ARP class.
*/
public class ArpTest {
private Deserializer<ARP> deserializer = ARP.deserializer();
private final byte hwAddressLength = 6;
private final byte protoAddressLength = 4;
private MacAddress srcMac = MacAddress.valueOf(1);
private MacAddress targetMac = MacAddress.valueOf(2);
private Ip4Address srcIp = Ip4Address.valueOf(1);
private Ip4Address targetIp = Ip4Address.valueOf(2);
private byte[] byteHeader;
@Before
public void setUp() {
ByteBuffer bb = ByteBuffer.allocate(ARP.INITIAL_HEADER_LENGTH +
2 * hwAddressLength + 2 * protoAddressLength);
bb.putShort(ARP.HW_TYPE_ETHERNET);
bb.putShort(ARP.PROTO_TYPE_IP);
bb.put(hwAddressLength);
bb.put(protoAddressLength);
bb.putShort(ARP.OP_REPLY);
bb.put(srcMac.toBytes());
bb.put(srcIp.toOctets());
bb.put(targetMac.toBytes());
bb.put(targetIp.toOctets());
byteHeader = bb.array();
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, byteHeader);
}
@Test
public void testDeserialize() throws Exception {
ARP arp = deserializer.deserialize(byteHeader, 0, byteHeader.length);
assertEquals(ARP.HW_TYPE_ETHERNET, arp.getHardwareType());
assertEquals(ARP.PROTO_TYPE_IP, arp.getProtocolType());
assertEquals(hwAddressLength, arp.getHardwareAddressLength());
assertEquals(protoAddressLength, arp.getProtocolAddressLength());
assertEquals(ARP.OP_REPLY, arp.getOpCode());
assertTrue(Arrays.equals(srcMac.toBytes(), arp.getSenderHardwareAddress()));
assertTrue(Arrays.equals(srcIp.toOctets(), arp.getSenderProtocolAddress()));
assertTrue(Arrays.equals(targetMac.toBytes(), arp.getTargetHardwareAddress()));
assertTrue(Arrays.equals(targetIp.toOctets(), arp.getTargetProtocolAddress()));
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import com.google.common.base.Charsets;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Unit tests for DHCP class.
*/
public class DhcpTest {
private Deserializer<DHCP> deserializer = DHCP.deserializer();
private byte opCode = 1;
private byte hardwareType = 1;
private byte hardwareAddressLength = Ethernet.DATALAYER_ADDRESS_LENGTH;
private byte hops = 0;
private int transactionId = 0x2ed4eb50;
private short seconds = 0;
private short flags = 0;
private int clientIpAddress = 1;
private int yourIpAddress = 2;
private int serverIpAddress = 3;
private int gatewayIpAddress = 4;
private byte[] clientHardwareAddress = MacAddress.valueOf(500).toBytes();
private String serverName = "test-server";
private String bootFileName = "test-file";
private String hostName = "test-host";
private DHCPOption hostNameOption = new DHCPOption();
private byte[] byteHeader;
@Before
public void setUp() {
hostNameOption.setCode((byte) 55);
hostNameOption.setLength((byte) hostName.length());
hostNameOption.setData(hostName.getBytes(Charsets.US_ASCII));
// Packet length is the fixed DHCP header plus option length plus an
// extra byte to indicate 'end of options'.
ByteBuffer bb = ByteBuffer.allocate(DHCP.MIN_HEADER_LENGTH +
2 + hostNameOption.getLength() + 1);
bb.put(opCode);
bb.put(hardwareType);
bb.put(hardwareAddressLength);
bb.put(hops);
bb.putInt(transactionId);
bb.putShort(seconds);
bb.putShort(flags);
bb.putInt(clientIpAddress);
bb.putInt(yourIpAddress);
bb.putInt(serverIpAddress);
bb.putInt(gatewayIpAddress);
bb.put(clientHardwareAddress);
// need 16 bytes of zeros to pad out the client hardware address field
bb.put(new byte[16 - hardwareAddressLength]);
// Put server name and pad out to 64 bytes
bb.put(serverName.getBytes(Charsets.US_ASCII));
bb.put(new byte[64 - serverName.length()]);
// Put boot file name and pad out to 128 bytes
bb.put(bootFileName.getBytes(Charsets.US_ASCII));
bb.put(new byte[128 - bootFileName.length()]);
// Magic cookie
bb.put("DHCP".getBytes(Charsets.US_ASCII));
bb.put(hostNameOption.getCode());
bb.put(hostNameOption.getLength());
bb.put(hostNameOption.getData());
// End of options marker
bb.put((byte) (0xff & 255));
byteHeader = bb.array();
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, byteHeader);
}
@Test
public void testDeserialize() throws Exception {
DHCP dhcp = deserializer.deserialize(byteHeader, 0, byteHeader.length);
assertEquals(opCode, dhcp.opCode);
assertEquals(hardwareType, dhcp.hardwareType);
assertEquals(hardwareAddressLength, dhcp.hardwareAddressLength);
assertEquals(hops, dhcp.hops);
assertEquals(transactionId, dhcp.transactionId);
assertEquals(seconds, dhcp.seconds);
assertEquals(flags, dhcp.flags);
assertEquals(clientIpAddress, dhcp.clientIPAddress);
assertEquals(yourIpAddress, dhcp.yourIPAddress);
assertEquals(serverIpAddress, dhcp.serverIPAddress);
assertEquals(gatewayIpAddress, dhcp.gatewayIPAddress);
assertTrue(Arrays.equals(clientHardwareAddress, dhcp.clientHardwareAddress));
assertEquals(serverName, dhcp.serverName);
assertEquals(bootFileName, dhcp.bootFileName);
assertEquals(1, dhcp.options.size());
assertEquals(hostNameOption, dhcp.options.get(0));
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for the Ethernet class.
*/
public class EthernetTest {
private MacAddress dstMac;
private MacAddress srcMac;
private short ethertype = 6;
private short vlan = 5;
private Deserializer<Ethernet> deserializer;
private byte[] byteHeader;
private byte[] vlanByteHeader;
@Before
public void setUp() {
deserializer = Ethernet.deserializer();
byte[] dstMacBytes = {
(byte) 0x88, (byte) 0x88, (byte) 0x88, (byte) 0x88, (byte) 0x88,
(byte) 0x88 };
dstMac = MacAddress.valueOf(dstMacBytes);
byte[] srcMacBytes = {
(byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa,
(byte) 0xaa };
srcMac = MacAddress.valueOf(srcMacBytes);
// Create Ethernet byte array with no VLAN header
ByteBuffer bb = ByteBuffer.allocate(Ethernet.ETHERNET_HEADER_LENGTH);
bb.put(dstMacBytes);
bb.put(srcMacBytes);
bb.putShort(ethertype);
byteHeader = bb.array();
// Create Ethernet byte array with a VLAN header
bb = ByteBuffer.allocate(Ethernet.ETHERNET_HEADER_LENGTH + Ethernet.VLAN_HEADER_LENGTH);
bb.put(dstMacBytes);
bb.put(srcMacBytes);
bb.putShort(Ethernet.TYPE_VLAN);
bb.putShort(vlan);
bb.putShort(ethertype);
vlanByteHeader = bb.array();
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws DeserializationException {
PacketTestUtils.testDeserializeTruncated(deserializer, vlanByteHeader);
}
@Test
public void testDeserializeNoVlan() throws Exception {
Ethernet eth = deserializer.deserialize(byteHeader, 0, byteHeader.length);
assertEquals(dstMac, eth.getDestinationMAC());
assertEquals(srcMac, eth.getSourceMAC());
assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
assertEquals(ethertype, eth.getEtherType());
}
@Test
public void testDeserializeWithVlan() throws Exception {
Ethernet eth = deserializer.deserialize(vlanByteHeader, 0, vlanByteHeader.length);
assertEquals(dstMac, eth.getDestinationMAC());
assertEquals(srcMac, eth.getSourceMAC());
assertEquals(vlan, eth.getVlanID());
assertEquals(ethertype, eth.getEtherType());
}
}
......@@ -67,13 +67,22 @@ public class ICMP6Test {
assertArrayEquals(bytePacket, icmp6.serialize());
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(ICMP6.deserializer());
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(ICMP6.deserializer(), bytePacket);
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
ICMP6 icmp6 = new ICMP6();
icmp6.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws Exception {
ICMP6 icmp6 = ICMP6.deserializer().deserialize(bytePacket, 0, bytePacket.length);
assertThat(icmp6.getIcmpType(), is(ICMP6.ECHO_REQUEST));
assertThat(icmp6.getIcmpCode(), is((byte) 0x00));
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for the ICMP class.
*/
public class ICMPTest {
private Deserializer<ICMP> deserializer;
private byte icmpType = ICMP.TYPE_ECHO_REQUEST;
private byte icmpCode = 4;
private short checksum = 870;
private byte[] headerBytes;
@Before
public void setUp() throws Exception {
deserializer = ICMP.deserializer();
ByteBuffer bb = ByteBuffer.allocate(ICMP.ICMP_HEADER_LENGTH);
bb.put(icmpType);
bb.put(icmpCode);
bb.putShort(checksum);
headerBytes = bb.array();
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, headerBytes);
}
@Test
public void testDeserialize() throws Exception {
ICMP icmp = deserializer.deserialize(headerBytes, 0, headerBytes.length);
assertEquals(icmpType, icmp.getIcmpType());
assertEquals(icmpCode, icmp.getIcmpCode());
assertEquals(checksum, icmp.getChecksum());
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Unit tests for IPv4 class.
*/
public class IPv4Test {
private Deserializer<IPv4> deserializer;
private byte version = 4;
private byte headerLength = 6;
private byte diffServ = 2;
private short totalLength = 20;
private short identification = 1;
private byte flags = 1;
private short fragmentOffset = 1;
private byte ttl = 60;
private byte protocol = 4;
private short checksum = 4;
private int sourceAddress = 1;
private int destinationAddress = 2;
private byte[] options = new byte[] {0x1, 0x2, 0x3, 0x4};
private byte[] headerBytes;
@Before
public void setUp() throws Exception {
deserializer = IPv4.deserializer();
ByteBuffer bb = ByteBuffer.allocate(headerLength * 4);
bb.put((byte) ((version & 0xf) << 4 | headerLength & 0xf));
bb.put(diffServ);
bb.putShort(totalLength);
bb.putShort(identification);
bb.putShort((short) ((flags & 0x7) << 13 | fragmentOffset & 0x1fff));
bb.put(ttl);
bb.put(protocol);
bb.putShort(checksum);
bb.putInt(sourceAddress);
bb.putInt(destinationAddress);
bb.put(options);
headerBytes = bb.array();
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, headerBytes);
}
@Test
public void testDeserialize() throws Exception {
IPv4 ipv4 = deserializer.deserialize(headerBytes, 0, headerBytes.length);
assertEquals(version, ipv4.getVersion());
assertEquals(headerLength, ipv4.getHeaderLength());
assertEquals(diffServ, ipv4.getDiffServ());
assertEquals(totalLength, ipv4.getTotalLength());
assertEquals(identification, ipv4.getIdentification());
assertEquals(flags, ipv4.getFlags());
assertEquals(fragmentOffset, ipv4.getFragmentOffset());
assertEquals(ttl, ipv4.getTtl());
assertEquals(protocol, ipv4.getProtocol());
assertEquals(checksum, ipv4.getChecksum());
assertEquals(sourceAddress, ipv4.getSourceAddress());
assertEquals(destinationAddress, ipv4.getDestinationAddress());
assertTrue(ipv4.isTruncated());
}
}
......@@ -18,14 +18,17 @@
package org.onlab.packet;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.nio.ByteBuffer;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Tests for class {@link IPv6}.
......@@ -43,6 +46,8 @@ public class IPv6Test {
private static UDP udp;
private static byte[] bytePacket;
private Deserializer<IPv6> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
data = new Data();
......@@ -65,6 +70,11 @@ public class IPv6Test {
System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
}
@Before
public void setUp() {
deserializer = IPv6.deserializer();
}
/**
* Tests serialize and setters.
*/
......@@ -83,13 +93,26 @@ public class IPv6Test {
assertArrayEquals(ipv6.serialize(), bytePacket);
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
// Run the truncation test only on the IPv6 header
byte[] ipv6Header = new byte[IPv6.FIXED_HEADER_LENGTH];
ByteBuffer.wrap(bytePacket).get(ipv6Header);
PacketTestUtils.testDeserializeTruncated(deserializer, ipv6Header);
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
IPv6 ipv6 = new IPv6();
ipv6.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
IPv6 ipv6 = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(ipv6.getVersion(), is((byte) 6));
assertThat(ipv6.getTrafficClass(), is((byte) 0x93));
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for LLC class.
*/
public class LLCTest {
private Deserializer<LLC> deserializer;
private byte dsap = 10;
private byte ssap = 20;
private byte ctrl = 30;
private byte[] bytes;
@Before
public void setUp() throws Exception {
deserializer = LLC.deserializer();
ByteBuffer bb = ByteBuffer.allocate(LLC.LLC_HEADER_LENGTH);
bb.put(dsap);
bb.put(ssap);
bb.put(ctrl);
bytes = bb.array();
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, bytes);
}
@Test
public void testDeserialize() throws Exception {
LLC llc = deserializer.deserialize(bytes, 0, bytes.length);
assertEquals(dsap, llc.getDsap());
assertEquals(ssap, llc.getSsap());
assertEquals(ctrl, llc.getCtrl());
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Unit tests for the LLDP class.
*/
public class LLDPTest {
private Deserializer<LLDP> deserializer;
private byte[] chassisValue = new byte[] {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
private byte[] portValue = new byte[] {0x1, 0x2, 0x3, 0x4, 0x5};
private byte[] ttlValue = new byte[] {0x0, 0x20};
private short optionalTlvSize = 6;
private byte[] optionalTlvValue = new byte[] {0x6, 0x5, 0x4, 0x3, 0x2, 0x1};
private byte[] bytes;
@Before
public void setUp() throws Exception {
deserializer = LLDP.deserializer();
// Each TLV is 2 bytes for the type+length, plus the size of the value
// There are 2 zero-bytes at the end
ByteBuffer bb = ByteBuffer.allocate(2 + LLDP.CHASSIS_TLV_SIZE +
2 + LLDP.PORT_TLV_SIZE +
2 + LLDP.TTL_TLV_SIZE +
2 + optionalTlvSize +
2);
// Chassis TLV
bb.putShort(getTypeLength(LLDP.CHASSIS_TLV_TYPE, LLDP.CHASSIS_TLV_SIZE));
bb.put(chassisValue);
// Port TLV
bb.putShort(getTypeLength(LLDP.PORT_TLV_TYPE, LLDP.PORT_TLV_SIZE));
bb.put(portValue);
// TTL TLV
bb.putShort(getTypeLength(LLDP.TTL_TLV_TYPE, LLDP.TTL_TLV_SIZE));
bb.put(ttlValue);
// Optional TLV
bb.putShort(getTypeLength(LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE, optionalTlvSize));
bb.put(optionalTlvValue);
bb.putShort((short) 0);
bytes = bb.array();
}
private short getTypeLength(byte type, short length) {
return (short) ((0x7f & type) << 9 | 0x1ff & length);
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, bytes);
}
@Test
public void testDeserialize() throws Exception {
LLDP lldp = deserializer.deserialize(bytes, 0, bytes.length);
assertEquals(LLDP.CHASSIS_TLV_TYPE, lldp.getChassisId().getType());
assertEquals(LLDP.CHASSIS_TLV_SIZE, lldp.getChassisId().getLength());
assertTrue(Arrays.equals(chassisValue, lldp.getChassisId().getValue()));
assertEquals(LLDP.PORT_TLV_TYPE, lldp.getPortId().getType());
assertEquals(LLDP.PORT_TLV_SIZE, lldp.getPortId().getLength());
assertTrue(Arrays.equals(portValue, lldp.getPortId().getValue()));
assertEquals(LLDP.TTL_TLV_TYPE, lldp.getTtl().getType());
assertEquals(LLDP.TTL_TLV_SIZE, lldp.getTtl().getLength());
assertTrue(Arrays.equals(ttlValue, lldp.getTtl().getValue()));
assertEquals(1, lldp.getOptionalTLVList().size());
LLDPTLV optionalTlv = lldp.getOptionalTLVList().get(0);
assertEquals(LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE, optionalTlv.getType());
assertEquals(optionalTlvSize, optionalTlv.getLength());
assertTrue(Arrays.equals(optionalTlvValue, optionalTlv.getValue()));
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.HashMap;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for MPLS class.
*/
public class MplsTest {
private Deserializer<MPLS> deserializer;
private int label = 1048575;
private byte bos = 1;
private byte ttl = 20;
private byte protocol = MPLS.PROTOCOL_IPV4;
private byte[] bytes;
@Before
public void setUp() throws Exception {
// Replace normal deserializer map with an empty map. This will cause
// the DataDeserializer to be used which will silently handle 0-byte input.
MPLS.protocolDeserializerMap = new HashMap<>();
deserializer = MPLS.deserializer();
ByteBuffer bb = ByteBuffer.allocate(MPLS.HEADER_LENGTH);
bb.putInt(((label & 0x000fffff) << 12) | ((bos & 0x1) << 8 | (ttl & 0xff)));
bytes = bb.array();
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, bytes);
}
@Test
public void testDeserialize() throws Exception {
MPLS mpls = deserializer.deserialize(bytes, 0, bytes.length);
assertEquals(label, mpls.label);
assertEquals(bos, mpls.bos);
assertEquals(ttl, mpls.ttl);
assertEquals(protocol, mpls.protocol);
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.packet;
import java.nio.ByteBuffer;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertTrue;
/**
* Utilities for testing packet methods.
*/
public final class PacketTestUtils {
private PacketTestUtils() {
}
/**
* Tests that the Deserializer function is resilient to bad input parameters
* such as null input, negative offset and length, etc.
*
* @param deserializer deserializer function to test
*/
public static void testDeserializeBadInput(Deserializer deserializer) {
byte[] bytes = ByteBuffer.allocate(4).array();
try {
deserializer.deserialize(null, 0, 4);
fail("NullPointerException was not thrown");
} catch (NullPointerException e) {
assertTrue(true);
} catch (DeserializationException e) {
fail("NullPointerException was not thrown");
}
// input byte array length, offset and length don't make sense
expectDeserializationException(deserializer, bytes, -1, 0);
expectDeserializationException(deserializer, bytes, 0, -1);
expectDeserializationException(deserializer, bytes, 0, 5);
expectDeserializationException(deserializer, bytes, 2, 3);
expectDeserializationException(deserializer, bytes, 5, 0);
}
/**
* Tests that the Deserializer function is resilient to truncated input, or
* cases where the input byte array does not contain enough bytes to
* deserialize the packet.
*
* @param deserializer deserializer function to test
* @param header byte array of a full-size packet
*/
public static void testDeserializeTruncated(Deserializer deserializer,
byte[] header) {
byte[] truncated;
for (int i = 0; i < header.length; i++) {
truncated = new byte[i];
ByteBuffer.wrap(header).get(truncated);
expectDeserializationException(deserializer, truncated, 0, truncated.length);
}
}
/**
* Run the given deserializer function against the given inputs and verify
* that a DeserializationException is thrown. The the test will fail if a
* DeserializationException is not thrown by the deserializer function.
*
* @param deserializer deserializer function to test
* @param bytes input byte array
* @param offset input offset
* @param length input length
*/
public static void expectDeserializationException(Deserializer deserializer,
byte[] bytes, int offset, int length) {
try {
deserializer.deserialize(bytes, offset, length);
fail("DeserializationException was not thrown");
} catch (DeserializationException e) {
assertTrue(true);
}
}
}
......@@ -67,8 +67,12 @@ public class TCPTest {
(byte) 0x00, (byte) 0x01 // urgent
};
private static Deserializer<TCP> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
deserializer = TCP.deserializer();
ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS));
ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS));
ipv4.setProtocol(IPv4.PROTOCOL_TCP);
......@@ -100,13 +104,22 @@ public class TCPTest {
assertArrayEquals(bytePacketTCP6, tcp.serialize());
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, bytePacketTCP4);
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
TCP tcp = new TCP();
tcp.deserialize(bytePacketTCP4, 0, bytePacketTCP4.length);
public void testDeserialize() throws Exception {
TCP tcp = deserializer.deserialize(bytePacketTCP4, 0, bytePacketTCP4.length);
assertThat(tcp.getSourcePort(), is((short) 0x50));
assertThat(tcp.getDestinationPort(), is((short) 0x60));
......
......@@ -61,8 +61,12 @@ public class UDPTest {
(byte) 0x02, (byte) 0x2a, // checksum
};
private static Deserializer<UDP> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
deserializer = UDP.deserializer();
ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS));
ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS));
ipv4.setProtocol(IPv4.PROTOCOL_UDP);
......@@ -88,13 +92,22 @@ public class UDPTest {
assertArrayEquals(bytePacketUDP6, udp.serialize());
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(deserializer, bytePacketUDP4);
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
UDP udp = new UDP();
udp.deserialize(bytePacketUDP4, 0, bytePacketUDP4.length);
public void testDeserialize() throws Exception {
UDP udp = deserializer.deserialize(bytePacketUDP4, 0, bytePacketUDP4.length);
assertThat(udp.getSourcePort(), is((short) 0x50));
assertThat(udp.getDestinationPort(), is((short) 0x60));
......
......@@ -16,9 +16,11 @@
package org.onlab.packet.ipv6;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.Data;
import org.onlab.packet.Deserializer;
import org.onlab.packet.UDP;
import static org.hamcrest.Matchers.is;
......@@ -38,6 +40,8 @@ public class AuthenticationTest {
};
private static byte[] bytePacket;
private Deserializer<Authentication> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
data = new Data();
......@@ -57,6 +61,11 @@ public class AuthenticationTest {
System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
}
@Before
public void setUp() {
deserializer = Authentication.deserializer();
}
/**
* Tests serialize and setters.
*/
......@@ -77,9 +86,8 @@ public class AuthenticationTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
Authentication auth = new Authentication();
auth.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws Exception {
Authentication auth = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(auth.getNextHeader(), is((byte) 0x11));
assertThat(auth.getPayloadLength(), is((byte) 0x02));
......
......@@ -16,9 +16,11 @@
package org.onlab.packet.ipv6;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.Data;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPv6;
import org.onlab.packet.UDP;
......@@ -40,6 +42,8 @@ public class BaseOptionsTest {
};
private static byte[] bytePacket;
private Deserializer<BaseOptions> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
data = new Data();
......@@ -57,6 +61,11 @@ public class BaseOptionsTest {
System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
}
@Before
public void setUp() {
deserializer = BaseOptions.deserializer();
}
/**
* Tests serialize and setters.
*/
......@@ -75,9 +84,8 @@ public class BaseOptionsTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
BaseOptions baseopt = new BaseOptions();
baseopt.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws Exception {
BaseOptions baseopt = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(baseopt.getNextHeader(), is((byte) 0x11));
assertThat(baseopt.getHeaderExtLength(), is((byte) 0x00));
......
......@@ -16,9 +16,13 @@
package org.onlab.packet.ipv6;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import java.util.Arrays;
import static org.hamcrest.Matchers.is;
......@@ -35,6 +39,8 @@ public class EncapSecurityPayloadTest {
private static byte[] dataByte = new byte[32];
private static byte[] bytePacket;
private Deserializer<EncapSecurityPayload> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
Arrays.fill(dataByte, (byte) 0xff);
......@@ -50,6 +56,11 @@ public class EncapSecurityPayloadTest {
System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
}
@Before
public void setUp() {
deserializer = EncapSecurityPayload.deserializer();
}
/**
* Tests serialize and setters.
*/
......@@ -67,9 +78,8 @@ public class EncapSecurityPayloadTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
EncapSecurityPayload esp = new EncapSecurityPayload();
esp.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
EncapSecurityPayload esp = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(esp.getSecurityParamIndex(), is(0x13572468));
assertThat(esp.getSequence(), is(0xffff00));
......
......@@ -16,9 +16,12 @@
package org.onlab.packet.ipv6;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.UDP;
import static org.hamcrest.Matchers.is;
......@@ -35,6 +38,8 @@ public class FragmentTest {
private static UDP udp;
private static byte[] bytePacket;
private Deserializer<Fragment> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
data = new Data();
......@@ -52,6 +57,11 @@ public class FragmentTest {
System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
}
@Before
public void setUp() {
deserializer = Fragment.deserializer();
}
/**
* Tests serialize and setters.
*/
......@@ -71,9 +81,8 @@ public class FragmentTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
Fragment frag = new Fragment();
frag.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
Fragment frag = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(frag.getNextHeader(), is((byte) 0x11));
assertThat(frag.getFragmentOffset(), is((short) 0x1f));
......
......@@ -16,9 +16,12 @@
package org.onlab.packet.ipv6;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.UDP;
import static org.hamcrest.Matchers.is;
......@@ -42,6 +45,8 @@ public class RoutingTest {
};
private static byte[] bytePacket;
private Deserializer<Routing> deserializer;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
data = new Data();
......@@ -63,6 +68,11 @@ public class RoutingTest {
System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length);
}
@Before
public void setUp() {
deserializer = Routing.deserializer();
}
/**
* Tests serialize and setters.
*/
......@@ -83,9 +93,8 @@ public class RoutingTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
Routing routing = new Routing();
routing.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
Routing routing = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(routing.getNextHeader(), is((byte) 0x11));
assertThat(routing.getHeaderExtLength(), is((byte) 0x02));
......
......@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.MacAddress;
import static org.hamcrest.Matchers.is;
......@@ -40,6 +42,9 @@ public class NeighborAdvertisementTest {
private static byte[] bytePacket;
private Deserializer<NeighborAdvertisement> deserializer
= NeighborAdvertisement.deserializer();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
byte[] byteHeader = {
......@@ -75,9 +80,8 @@ public class NeighborAdvertisementTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
NeighborAdvertisement na = new NeighborAdvertisement();
na.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
NeighborAdvertisement na = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(na.getRouterFlag(), is((byte) 1));
assertThat(na.getSolicitedFlag(), is((byte) 1));
......
......@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.MacAddress;
import static org.hamcrest.Matchers.is;
......@@ -46,6 +48,9 @@ public class NeighborSolicitationTest {
private static byte[] bytePacket;
private Deserializer<NeighborSolicitation> deserializer
= NeighborSolicitation.deserializer();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
byte[] byteHeader = {
......@@ -78,9 +83,8 @@ public class NeighborSolicitationTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
NeighborSolicitation ns = new NeighborSolicitation();
ns.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
NeighborSolicitation ns = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertArrayEquals(ns.getTargetAddress(), TARGET_ADDRESS);
......
......@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.MacAddress;
import static org.hamcrest.Matchers.is;
......@@ -52,6 +54,8 @@ public class RedirectTest {
private static byte[] bytePacket;
private Deserializer<Redirect> deserializer = Redirect.deserializer();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
byte[] byteHeader = {
......@@ -89,9 +93,8 @@ public class RedirectTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
Redirect rd = new Redirect();
rd.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
Redirect rd = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertArrayEquals(rd.getTargetAddress(), TARGET_ADDRESS);
assertArrayEquals(rd.getDestinationAddress(), DESTINATION_ADDRESS);
......
......@@ -17,6 +17,8 @@ package org.onlab.packet.ndp;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.MacAddress;
import static org.hamcrest.Matchers.is;
......@@ -34,6 +36,9 @@ public class RouterAdvertisementTest {
private static byte[] bytePacket;
private Deserializer<RouterAdvertisement> deserializer
= RouterAdvertisement.deserializer();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
byte[] byteHeader = {
......@@ -69,9 +74,8 @@ public class RouterAdvertisementTest {
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
RouterAdvertisement ra = new RouterAdvertisement();
ra.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws DeserializationException {
RouterAdvertisement ra = deserializer.deserialize(bytePacket, 0, bytePacket.length);
assertThat(ra.getCurrentHopLimit(), is((byte) 3));
assertThat(ra.getMFlag(), is((byte) 1));
......
......@@ -17,7 +17,9 @@ package org.onlab.packet.ndp;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.packet.Deserializer;
import org.onlab.packet.MacAddress;
import org.onlab.packet.PacketTestUtils;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertArrayEquals;
......@@ -36,6 +38,9 @@ public class RouterSolicitationTest {
private static byte[] bytePacket;
private Deserializer<RouterSolicitation> deserializer
= RouterSolicitation.deserializer();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
byte[] byteHeader = {
......@@ -59,13 +64,22 @@ public class RouterSolicitationTest {
assertArrayEquals(rs.serialize(), bytePacket);
}
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(RouterSolicitation.deserializer());
}
@Test
public void testDeserializeTruncated() throws Exception {
PacketTestUtils.testDeserializeTruncated(RouterSolicitation.deserializer(), bytePacket);
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
RouterSolicitation rs = new RouterSolicitation();
rs.deserialize(bytePacket, 0, bytePacket.length);
public void testDeserialize() throws Exception {
RouterSolicitation rs = deserializer.deserialize(bytePacket, 0, bytePacket.length);
// Check the option(s)
assertThat(rs.getOptions().size(), is(1));
......