Charles M.C. Chan
Committed by Ray Milkey

Refactor org.onlab.packet.{TCP,UDP,ICMP6}

- ONOS-1012: Fix TCP checksum when using IPv6
- ONOS-1013: Fix UDP checksum when using IPv6
- ONOS-1593: Remove get/setTcpChecksum
- Remove unnecessary parameter of getUrgentPointer() in TCP
- Complete javadoc for TCP
- Add unit test for {TCP,UDP,ICMP6}

Change-Id: Iad5eeb35812ede6764a9a9a4a57b9837e5ea5dd6
/*
* Copyright 2014 Open Networking Laboratory
* Copyright 2014-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.
......@@ -34,6 +34,8 @@ import java.util.Map;
public class ICMP6 extends BasePacket {
public static final byte HEADER_LENGTH = 4; // bytes
public static final byte ECHO_REQUEST = (byte) 0x80;
public static final byte ECHO_REPLY = (byte) 0x81;
public static final byte ROUTER_SOLICITATION = (byte) 0x85;
public static final byte ROUTER_ADVERTISEMENT = (byte) 0x86;
public static final byte NEIGHBOR_SOLICITATION = (byte) 0x87;
......@@ -149,8 +151,8 @@ public class ICMP6 extends BasePacket {
}
}
if (ipv6Parent != null) {
bbChecksum.put(((IPv6) ipv6Parent).getSourceAddress());
bbChecksum.put(((IPv6) ipv6Parent).getDestinationAddress());
bbChecksum.put(ipv6Parent.getSourceAddress());
bbChecksum.put(ipv6Parent.getDestinationAddress());
} else {
// NOTE: IPv6 source and destination addresses unknown. Use zeroes.
bbChecksum.put(ZERO_ADDRESS);
......
/*
* Copyright 2014 Open Networking Laboratory
* Copyright 2014-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.
......@@ -21,7 +21,7 @@ package org.onlab.packet;
import java.nio.ByteBuffer;
/**
*
* Implements TCP packet format.
*/
public class TCP extends BasePacket {
......@@ -37,15 +37,18 @@ public class TCP extends BasePacket {
protected byte[] options;
/**
* @return the sourcePort
* Gets TCP source port.
*
* @return TCP source port
*/
public short getSourcePort() {
return this.sourcePort;
}
/**
* @param sourcePort
* the sourcePort to set
* Sets TCP source port.
*
* @param sourcePort the sourcePort to set
* @return this
*/
public TCP setSourcePort(final short sourcePort) {
......@@ -54,6 +57,8 @@ public class TCP extends BasePacket {
}
/**
* Gets TCP destination port.
*
* @return the destinationPort
*/
public short getDestinationPort() {
......@@ -61,8 +66,9 @@ public class TCP extends BasePacket {
}
/**
* @param destinationPort
* the destinationPort to set
* Sets TCP destination port.
*
* @param destinationPort the destinationPort to set
* @return this
*/
public TCP setDestinationPort(final short destinationPort) {
......@@ -71,98 +77,169 @@ public class TCP extends BasePacket {
}
/**
* Gets checksum.
*
* @return the checksum
*/
public short getChecksum() {
return this.checksum;
}
/**
* Sets checksum.
*
* @param checksum the checksum to set
* @return this
*/
public TCP setChecksum(final short checksum) {
this.checksum = checksum;
return this;
}
/**
* Gets sequence number.
*
* @return the sequence number
*/
public int getSequence() {
return this.sequence;
}
/**
* Sets sequence number.
*
* @param seq the sequence number to set
* @return this
*/
public TCP setSequence(final int seq) {
this.sequence = seq;
return this;
}
/**
* Gets acknowledge number.
*
* @return the acknowledge number
*/
public int getAcknowledge() {
return this.acknowledge;
}
/**
* Sets acknowledge number.
*
* @param ack the acknowledge number to set
* @return this
*/
public TCP setAcknowledge(final int ack) {
this.acknowledge = ack;
return this;
}
/**
* Gets offset.
*
* @return the offset
*/
public byte getDataOffset() {
return this.dataOffset;
}
/**
* Sets offset.
*
* @param offset the offset to set
* @return this
*/
public TCP setDataOffset(final byte offset) {
this.dataOffset = offset;
return this;
}
/**
* Gets TCP flags.
*
* @return the TCP flags
*/
public short getFlags() {
return this.flags;
}
/**
* Sets TCP flags.
*
* @param flags the TCP flags to set
* @return this
*/
public TCP setFlags(final short flags) {
this.flags = flags;
return this;
}
/**
* Gets TCP window size.
*
* @return the TCP window size
*/
public short getWindowSize() {
return this.windowSize;
}
/**
* Sets TCP window size.
*
* @param windowSize the TCP window size to set
* @return this
*/
public TCP setWindowSize(final short windowSize) {
this.windowSize = windowSize;
return this;
}
public short getTcpChecksum() {
return this.checksum;
}
public TCP setTcpChecksum(final short checksum) {
this.checksum = checksum;
return this;
}
@Override
public void resetChecksum() {
this.checksum = 0;
super.resetChecksum();
}
public short getUrgentPointer(final short urgentPointer) {
/**
* Gets urgent pointer.
*
* @return the urgent pointer
*/
public short getUrgentPointer() {
return this.urgentPointer;
}
/**
* Sets urgent pointer.
*
* @param urgentPointer the urgent pointer to set
* @return this
*/
public TCP setUrgentPointer(final short urgentPointer) {
this.urgentPointer = urgentPointer;
return this;
}
/**
* Gets TCP options.
*
* @return the TCP options
*/
public byte[] getOptions() {
return this.options;
}
public TCP setOptions(final byte[] options) {
this.options = options;
this.dataOffset = (byte) (20 + options.length + 3 >> 2);
return this;
}
/**
* @param checksum
* the checksum to set
* Sets TCP options.
*
* @param options the options to set
* @return this
*/
public TCP setChecksum(final short checksum) {
this.checksum = checksum;
public TCP setOptions(final byte[] options) {
this.options = options;
this.dataOffset = (byte) (20 + options.length + 3 >> 2);
return this;
}
......@@ -218,7 +295,8 @@ public class TCP extends BasePacket {
int accumulation = 0;
// compute pseudo header mac
if (this.parent != null && this.parent instanceof IPv4) {
if (this.parent != null) {
if (this.parent instanceof IPv4) {
final IPv4 ipv4 = (IPv4) this.parent;
accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
+ (ipv4.getSourceAddress() & 0xffff);
......@@ -226,6 +304,23 @@ public class TCP extends BasePacket {
+ (ipv4.getDestinationAddress() & 0xffff);
accumulation += ipv4.getProtocol() & 0xff;
accumulation += length & 0xffff;
} else if (this.parent instanceof IPv6) {
final IPv6 ipv6 = (IPv6) this.parent;
final int bbLength =
Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
+ 2 // nextHeader (with padding)
+ 4; // length
final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
bbChecksum.put(ipv6.getSourceAddress());
bbChecksum.put(ipv6.getDestinationAddress());
bbChecksum.put((byte) 0); // padding
bbChecksum.put(ipv6.getNextHeader());
bbChecksum.putInt(length);
bbChecksum.rewind();
for (int i = 0; i < bbLength / 2; ++i) {
accumulation += 0xffff & bbChecksum.getShort();
}
}
}
for (int i = 0; i < length / 2; ++i) {
......
/*
* Copyright 2014 Open Networking Laboratory
* Copyright 2014-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.
......@@ -148,14 +148,32 @@ public class UDP extends BasePacket {
int accumulation = 0;
// compute pseudo header mac
if (this.parent != null && this.parent instanceof IPv4) {
if (this.parent != null) {
if (this.parent instanceof IPv4) {
final IPv4 ipv4 = (IPv4) this.parent;
accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
+ (ipv4.getSourceAddress() & 0xffff);
accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
+ (ipv4.getDestinationAddress() & 0xffff);
accumulation += ipv4.getProtocol() & 0xff;
accumulation += this.length & 0xffff;
accumulation += length & 0xffff;
} else if (this.parent instanceof IPv6) {
final IPv6 ipv6 = (IPv6) this.parent;
final int bbLength =
Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst
+ 2 // nextHeader (with padding)
+ 4; // length
final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength);
bbChecksum.put(ipv6.getSourceAddress());
bbChecksum.put(ipv6.getDestinationAddress());
bbChecksum.put((byte) 0); // padding
bbChecksum.put(ipv6.getNextHeader());
bbChecksum.putInt(length);
bbChecksum.rewind();
for (int i = 0; i < bbLength / 2; ++i) {
accumulation += 0xffff & bbChecksum.getShort();
}
}
}
for (int i = 0; i < this.length / 2; ++i) {
......
/*
* Copyright 2014-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.BeforeClass;
import org.junit.Test;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Tests for class {@link ICMP6}.
*/
public class ICMP6Test {
private static final byte[] IPV6_SOURCE_ADDRESS = {
(byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
};
private static final byte[] IPV6_DESTINATION_ADDRESS = {
(byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02
};
private static IPv6 ipv6 = new IPv6();
private static byte[] bytePacket = {
ICMP6.ECHO_REQUEST, // type
(byte) 0x00, // code
(byte) 0x82, (byte) 0xbc, // checksum
};
@BeforeClass
public static void setUpBeforeClass() throws Exception {
ipv6.setSourceAddress(IPV6_SOURCE_ADDRESS);
ipv6.setDestinationAddress(IPV6_DESTINATION_ADDRESS);
ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6);
}
/**
* Tests serialize and setters.
*/
@Test
public void testSerialize() {
ICMP6 icmp6 = new ICMP6();
icmp6.setIcmpType(ICMP6.ECHO_REQUEST);
icmp6.setIcmpCode((byte) 0);
icmp6.setParent(ipv6);
assertArrayEquals(bytePacket, icmp6.serialize());
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
ICMP6 icmp6 = new ICMP6();
icmp6.deserialize(bytePacket, 0, bytePacket.length);
assertThat(icmp6.getIcmpType(), is(ICMP6.ECHO_REQUEST));
assertThat(icmp6.getIcmpCode(), is((byte) 0x00));
assertThat(icmp6.getChecksum(), is((short) 0x82bc));
}
/**
* Tests comparator.
*/
@Test
public void testEqual() {
ICMP6 icmp61 = new ICMP6();
icmp61.setIcmpType(ICMP6.ECHO_REQUEST);
icmp61.setIcmpCode((byte) 0);
icmp61.setChecksum((short) 0);
ICMP6 icmp62 = new ICMP6();
icmp62.setIcmpType(ICMP6.ECHO_REPLY);
icmp62.setIcmpCode((byte) 0);
icmp62.setChecksum((short) 0);
assertTrue(icmp61.equals(icmp61));
assertFalse(icmp61.equals(icmp62));
}
}
/*
* Copyright 2014-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.BeforeClass;
import org.junit.Test;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Tests for class {@link TCP}.
*/
public class TCPTest {
private static final byte[] IPV4_SOURCE_ADDRESS = {
(byte) 192, (byte) 168, (byte) 1, (byte) 1
};
private static final byte[] IPV4_DESTINATION_ADDRESS = {
(byte) 192, (byte) 168, (byte) 1, (byte) 2
};
private static final byte[] IPV6_SOURCE_ADDRESS = {
(byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
};
private static final byte[] IPV6_DESTINATION_ADDRESS = {
(byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02
};
private static IPv4 ipv4 = new IPv4();
private static IPv6 ipv6 = new IPv6();
private static byte[] bytePacketTCP4 = {
(byte) 0x00, (byte) 0x50, (byte) 0x00, (byte) 0x60, // src,dst port
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10, // seq
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, // ack
(byte) 0x50, (byte) 0x02, // offset,flag
(byte) 0x10, (byte) 0x00, // window
(byte) 0x1b, (byte) 0xae, // checksum
(byte) 0x00, (byte) 0x01 // urgent
};
private static byte[] bytePacketTCP6 = {
(byte) 0x00, (byte) 0x50, (byte) 0x00, (byte) 0x60, // src,dst port
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10, // seq
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, // ack
(byte) 0x50, (byte) 0x02, // offset,flag
(byte) 0x10, (byte) 0x00, // window
(byte) 0xa1, (byte) 0xfd, // checksum
(byte) 0x00, (byte) 0x01 // urgent
};
@BeforeClass
public static void setUpBeforeClass() throws Exception {
ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS));
ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS));
ipv4.setProtocol(IPv4.PROTOCOL_TCP);
ipv6.setSourceAddress(IPV6_SOURCE_ADDRESS);
ipv6.setDestinationAddress(IPV6_DESTINATION_ADDRESS);
ipv6.setNextHeader(IPv6.PROTOCOL_TCP);
}
/**
* Tests serialize and setters.
*/
@Test
public void testSerialize() {
TCP tcp = new TCP();
tcp.setSourcePort((short) 0x50);
tcp.setDestinationPort((short) 0x60);
tcp.setSequence(0x10);
tcp.setAcknowledge(0x20);
tcp.setDataOffset((byte) 0x5);
tcp.setFlags((short) 0x2);
tcp.setWindowSize((short) 0x1000);
tcp.setUrgentPointer((short) 0x1);
tcp.setParent(ipv4);
assertArrayEquals(bytePacketTCP4, tcp.serialize());
tcp.resetChecksum();
tcp.setParent(ipv6);
assertArrayEquals(bytePacketTCP6, tcp.serialize());
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
TCP tcp = new TCP();
tcp.deserialize(bytePacketTCP4, 0, bytePacketTCP4.length);
assertThat(tcp.getSourcePort(), is((short) 0x50));
assertThat(tcp.getDestinationPort(), is((short) 0x60));
assertThat(tcp.getSequence(), is(0x10));
assertThat(tcp.getAcknowledge(), is(0x20));
assertThat(tcp.getDataOffset(), is((byte) 0x5));
assertThat(tcp.getFlags(), is((short) 0x2));
assertThat(tcp.getWindowSize(), is((short) 0x1000));
assertThat(tcp.getUrgentPointer(), is((short) 0x1));
assertThat(tcp.getChecksum(), is((short) 0x1bae));
}
/**
* Tests comparator.
*/
@Test
public void testEqual() {
TCP tcp1 = new TCP();
tcp1.setSourcePort((short) 0x50);
tcp1.setDestinationPort((short) 0x60);
tcp1.setSequence(0x10);
tcp1.setAcknowledge(0x20);
tcp1.setDataOffset((byte) 0x5);
tcp1.setFlags((short) 0x2);
tcp1.setWindowSize((short) 0x1000);
tcp1.setUrgentPointer((short) 0x1);
TCP tcp2 = new TCP();
tcp2.setSourcePort((short) 0x70);
tcp2.setDestinationPort((short) 0x60);
tcp2.setSequence(0x10);
tcp2.setAcknowledge(0x20);
tcp2.setDataOffset((byte) 0x5);
tcp2.setFlags((short) 0x2);
tcp2.setWindowSize((short) 0x1000);
tcp2.setUrgentPointer((short) 0x1);
assertTrue(tcp1.equals(tcp1));
assertFalse(tcp1.equals(tcp2));
}
}
/*
* Copyright 2014-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.BeforeClass;
import org.junit.Test;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Tests for class {@link UDP}.
*/
public class UDPTest {
private static final byte[] IPV4_SOURCE_ADDRESS = {
(byte) 192, (byte) 168, (byte) 1, (byte) 1
};
private static final byte[] IPV4_DESTINATION_ADDRESS = {
(byte) 192, (byte) 168, (byte) 1, (byte) 2
};
private static final byte[] IPV6_SOURCE_ADDRESS = {
(byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
};
private static final byte[] IPV6_DESTINATION_ADDRESS = {
(byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02
};
private static IPv4 ipv4 = new IPv4();
private static IPv6 ipv6 = new IPv6();
private static byte[] bytePacketUDP4 = {
(byte) 0x00, (byte) 0x50, // src port
(byte) 0x00, (byte) 0x60, // dst port
(byte) 0x00, (byte) 0x08, // length
(byte) 0x7b, (byte) 0xda, // checksum
};
private static byte[] bytePacketUDP6 = {
(byte) 0x00, (byte) 0x50, // src port
(byte) 0x00, (byte) 0x60, // dst port
(byte) 0x00, (byte) 0x08, // length
(byte) 0x02, (byte) 0x2a, // checksum
};
@BeforeClass
public static void setUpBeforeClass() throws Exception {
ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS));
ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS));
ipv4.setProtocol(IPv4.PROTOCOL_UDP);
ipv6.setSourceAddress(IPV6_SOURCE_ADDRESS);
ipv6.setDestinationAddress(IPV6_DESTINATION_ADDRESS);
ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
}
/**
* Tests serialize and setters.
*/
@Test
public void testSerialize() {
UDP udp = new UDP();
udp.setSourcePort((short) 0x50);
udp.setDestinationPort((short) 0x60);
udp.setParent(ipv4);
assertArrayEquals(bytePacketUDP4, udp.serialize());
udp.resetChecksum();
udp.setParent(ipv6);
assertArrayEquals(bytePacketUDP6, udp.serialize());
}
/**
* Tests deserialize and getters.
*/
@Test
public void testDeserialize() {
UDP udp = new UDP();
udp.deserialize(bytePacketUDP4, 0, bytePacketUDP4.length);
assertThat(udp.getSourcePort(), is((short) 0x50));
assertThat(udp.getDestinationPort(), is((short) 0x60));
assertThat(udp.getLength(), is((short) 8));
assertThat(udp.getChecksum(), is((short) 0x7bda));
}
/**
* Tests comparator.
*/
@Test
public void testEqual() {
UDP udp1 = new UDP();
udp1.setSourcePort((short) 0x50);
udp1.setDestinationPort((short) 0x60);
UDP udp2 = new UDP();
udp2.setSourcePort((short) 0x70);
udp2.setDestinationPort((short) 0x60);
assertTrue(udp1.equals(udp1));
assertFalse(udp1.equals(udp2));
}
}