Commit efd61207 authored by Brickner_cp's avatar Brickner_cp

Automatically calculate TCP and UDP checksum over IPv6.

Automatically calculate IPv6 extension headers Next Header field and IPv6 layer next header field.
parent 4e34fd27
......@@ -259,7 +259,7 @@ namespace PcapDotNet.Core.Test
case 5: // IPv6
case 6:
IpV6Layer ipV6Layer = random.NextIpV6Layer();
IpV6Layer ipV6Layer = random.NextIpV6Layer(random.NextBool(20));
layers.Add(ipV6Layer);
CreateRandomIpPayload(random, ipV6Layer, layers);
return;
......@@ -279,7 +279,7 @@ namespace PcapDotNet.Core.Test
return;
}
if (random.NextBool(20))
if (ipV6Layer != null ? ipV6Layer.LastNextHeader != null : random.NextBool(20))
{
// Finish with payload.
PayloadLayer payloadLayer = random.NextPayloadLayer(random.Next(100));
......@@ -306,7 +306,7 @@ namespace PcapDotNet.Core.Test
case 2: // IpV6.
case 3:
IpV6Layer innerIpV6Layer = random.NextIpV6Layer();
IpV6Layer innerIpV6Layer = random.NextIpV6Layer(random.NextBool(20));
layers.Add(innerIpV6Layer);
CreateRandomIpPayload(random, innerIpV6Layer, layers);
return;
......
......@@ -184,7 +184,8 @@ namespace PcapDotNet.Core.Test
{
Assert.IsFalse(options.IsValid, "Options IsValid");
Assert.IsTrue(
field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net
field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net.
field.Show().StartsWith("Unknown (0x19) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net.
field.Show().StartsWith("Echo reply (with option length = ") ||
field.Show().Contains("bytes says option goes past end of options") ||
field.Show().Contains(") (with too-short option length = ") ||
......
......@@ -70,7 +70,7 @@ namespace PcapDotNet.Packets.Test
for (int i = 0; i != 1000; ++i)
{
IpV6Layer ipV6Layer = random.NextIpV6Layer();
IpV6Layer ipV6Layer = random.NextIpV6Layer(false);
PayloadLayer payloadLayer = random.NextPayloadLayer(random.NextInt(0, 50 * 1024));
......@@ -253,7 +253,7 @@ namespace PcapDotNet.Packets.Test
}
[TestMethod]
[ExpectedException(typeof(ArgumentException), AllowDerivedTypes = false)]
[ExpectedException(typeof(InvalidOperationException), AllowDerivedTypes = false)]
public void AutomaticIpV6NextHeaderNoNextLayer()
{
PacketBuilder.Build(DateTime.Now, new EthernetLayer(), new IpV6Layer());
......@@ -261,7 +261,7 @@ namespace PcapDotNet.Packets.Test
}
[TestMethod]
[ExpectedException(typeof(ArgumentException), AllowDerivedTypes = false)]
[ExpectedException(typeof(InvalidOperationException), AllowDerivedTypes = false)]
public void AutomaticIpV6NextHeaderUnknownNextLayer()
{
PacketBuilder.Build(DateTime.Now, new EthernetLayer(), new IpV6Layer(), new PayloadLayer());
......
......@@ -2,6 +2,7 @@ using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.Packets.TestUtils;
using PcapDotNet.Packets.Transport;
......@@ -42,7 +43,7 @@ namespace PcapDotNet.Packets.Test
#endregion
[TestMethod]
public void RandomTcpTest()
public void RandomTcpOverIpV4Test()
{
MacAddress ethernetSource = new MacAddress("00:01:02:03:04:05");
MacAddress ethernetDestination = new MacAddress("A0:A1:A2:A3:A4:A5");
......@@ -58,7 +59,7 @@ namespace PcapDotNet.Packets.Test
IpV4Layer ipV4Layer = random.NextIpV4Layer(null);
ipV4Layer.HeaderChecksum = null;
for (int i = 0; i != 1000; ++i)
for (int i = 0; i != 500; ++i)
{
TcpLayer tcpLayer = random.NextTcpLayer();
......@@ -111,6 +112,76 @@ namespace PcapDotNet.Packets.Test
}
}
// TODO: Merge this test with the above one.
[TestMethod]
public void RandomTcpOverIpV6Test()
{
MacAddress ethernetSource = new MacAddress("00:01:02:03:04:05");
MacAddress ethernetDestination = new MacAddress("A0:A1:A2:A3:A4:A5");
EthernetLayer ethernetLayer = new EthernetLayer
{
Source = ethernetSource,
Destination = ethernetDestination
};
Random random = new Random();
int seed = random.Next();
Console.WriteLine("Seed: {0}", seed);
random = new Random(seed);
IpV6Layer ipV6Layer = random.NextIpV6Layer(IpV4Protocol.Tcp, false);
for (int i = 0; i != 500; ++i)
{
TcpLayer tcpLayer = random.NextTcpLayer();
PayloadLayer payloadLayer = random.NextPayloadLayer(random.Next(60000));
Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV6Layer, tcpLayer, payloadLayer);
Assert.IsTrue(packet.IsValid);
// Ethernet
ethernetLayer.EtherType = EthernetType.IpV6;
Assert.AreEqual(ethernetLayer, packet.Ethernet.ExtractLayer(), "Ethernet Layer");
// IpV6
Assert.AreEqual(ipV6Layer, packet.Ethernet.IpV6.ExtractLayer(), "IP Layer");
// TCP
tcpLayer.Checksum = packet.Ethernet.IpV6.Tcp.Checksum;
Assert.AreEqual(tcpLayer, packet.Ethernet.IpV6.Tcp.ExtractLayer(), "TCP Layer");
Assert.AreNotEqual(random.NextTcpLayer(), packet.Ethernet.IpV6.Tcp.ExtractLayer(), "TCP Layer");
Assert.AreEqual(tcpLayer.GetHashCode(), packet.Ethernet.IpV6.Tcp.ExtractLayer().GetHashCode(), "TCP Layer");
Assert.AreNotEqual(random.NextTcpLayer().GetHashCode(), packet.Ethernet.IpV6.Tcp.ExtractLayer().GetHashCode(), "TCP Layer");
Assert.AreEqual(packet.Ethernet.IpV6.Tcp.SequenceNumber + packet.Ethernet.IpV6.Tcp.PayloadLength, packet.Ethernet.IpV6.Tcp.NextSequenceNumber);
foreach (TcpOption option in packet.Ethernet.IpV6.Tcp.Options.OptionsCollection)
{
Assert.AreEqual(option, option);
Assert.AreEqual(option.GetHashCode(), option.GetHashCode());
Assert.IsFalse(string.IsNullOrEmpty(option.ToString()));
Assert.IsFalse(option.Equals(null));
Assert.IsFalse(option.Equals(2));
}
Assert.AreEqual(tcpLayer.Options, packet.Ethernet.IpV6.Tcp.Options, "Options");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.Acknowledgment) == TcpControlBits.Acknowledgment, packet.Ethernet.IpV6.Tcp.IsAcknowledgment, "IsAcknowledgment");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.CongestionWindowReduced) == TcpControlBits.CongestionWindowReduced, packet.Ethernet.IpV6.Tcp.IsCongestionWindowReduced, "IsCongestionWindowReduced");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.ExplicitCongestionNotificationEcho) == TcpControlBits.ExplicitCongestionNotificationEcho, packet.Ethernet.IpV6.Tcp.IsExplicitCongestionNotificationEcho, "IsExplicitCongestionNotificationEcho");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.Fin) == TcpControlBits.Fin, packet.Ethernet.IpV6.Tcp.IsFin, "IsFin");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.Push) == TcpControlBits.Push, packet.Ethernet.IpV6.Tcp.IsPush, "IsPush");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.Reset) == TcpControlBits.Reset, packet.Ethernet.IpV6.Tcp.IsReset, "IsReset");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.Synchronize) == TcpControlBits.Synchronize, packet.Ethernet.IpV6.Tcp.IsSynchronize, "IsSynchronize");
Assert.AreEqual((tcpLayer.ControlBits & TcpControlBits.Urgent) == TcpControlBits.Urgent, packet.Ethernet.IpV6.Tcp.IsUrgent, "IsUrgent");
Assert.AreEqual(0, packet.Ethernet.IpV6.Tcp.Reserved);
Assert.IsFalse(packet.Ethernet.IpV6.Tcp.IsChecksumOptional, "IsChecksumOptional");
Assert.AreEqual(TcpDatagram.HeaderMinimumLength + tcpLayer.Options.BytesLength + payloadLayer.Length, packet.Ethernet.IpV6.Tcp.Length, "Total Length");
Assert.IsTrue(packet.Ethernet.IpV6.IsTransportChecksumCorrect, "IsTransportChecksumCorrect");
Assert.AreEqual(payloadLayer.Data, packet.Ethernet.IpV6.Tcp.Payload, "Payload");
}
}
[TestMethod]
public void TcpOptionSelectiveAcknowledgmentBlockTest()
{
......
......@@ -2,6 +2,7 @@ using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.Packets.TestUtils;
using PcapDotNet.Packets.Transport;
......@@ -42,7 +43,7 @@ namespace PcapDotNet.Packets.Test
#endregion
[TestMethod]
public void RandomUdpTest()
public void RandomUdpOverIpV4Test()
{
EthernetLayer ethernetLayer = new EthernetLayer
{
......@@ -55,7 +56,8 @@ namespace PcapDotNet.Packets.Test
IpV4Layer ipV4Layer = random.NextIpV4Layer(null);
ipV4Layer.HeaderChecksum = null;
for (int i = 0; i != 1000; ++i)
// TODO: Merge this test with the above one.
for (int i = 0; i != 500; ++i)
{
UdpLayer udpLayer = random.NextUdpLayer();
udpLayer.Checksum = null;
......@@ -87,6 +89,48 @@ namespace PcapDotNet.Packets.Test
}
}
[TestMethod]
public void RandomUdpOverIpV6Test()
{
EthernetLayer ethernetLayer = new EthernetLayer
{
Source = new MacAddress("00:01:02:03:04:05"),
Destination = new MacAddress("A0:A1:A2:A3:A4:A5")
};
Random random = new Random();
IpV6Layer ipV6Layer = random.NextIpV6Layer(IpV4Protocol.Udp, false);
for (int i = 0; i != 500; ++i)
{
UdpLayer udpLayer = random.NextUdpLayer();
udpLayer.Checksum = null;
PayloadLayer payloadLayer = random.NextPayloadLayer(random.Next(60000));
Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV6Layer, udpLayer, payloadLayer);
Assert.IsTrue(packet.IsValid, "IsValid");
// Ethernet
ethernetLayer.EtherType = EthernetType.IpV6;
Assert.AreEqual(ethernetLayer, packet.Ethernet.ExtractLayer(), "Ethernet Layer");
// IpV6
Assert.AreEqual(ipV6Layer, packet.Ethernet.IpV6.ExtractLayer(), "IP Layer");
// UDP
udpLayer.Checksum = packet.Ethernet.IpV6.Udp.Checksum;
Assert.AreEqual(udpLayer, packet.Ethernet.IpV6.Udp.ExtractLayer(), "UDP Layer");
Assert.AreEqual(UdpDatagram.HeaderLength + payloadLayer.Length, packet.Ethernet.IpV6.Udp.TotalLength, "Total Length");
Assert.IsTrue(!udpLayer.CalculateChecksum && packet.Ethernet.IpV6.Udp.Checksum == 0 ||
udpLayer.CalculateChecksum && packet.Ethernet.IpV6.IsTransportChecksumCorrect, "IsTransportChecksumCorrect");
Assert.IsTrue(packet.Ethernet.IpV6.Udp.IsChecksumOptional, "IsChecksumOptional");
Assert.AreEqual(payloadLayer.Data, packet.Ethernet.IpV6.Udp.Payload, "Payload");
}
}
[TestMethod]
public void UdpChecksumTest()
{
......
......@@ -31,10 +31,16 @@ namespace PcapDotNet.Packets.TestUtils
return ((Func<IpV6Address>)(() => random.NextIpV6AddressWithLeadingZeroBytes(numLeadingZeros))).GenerateArray(count);
}
public static IpV6Layer NextIpV6Layer(this Random random)
public static IpV6Layer NextIpV6Layer(this Random random, bool withAutomaticNextLayer)
{
IpV6ExtensionHeaders extensionHeaders = random.NextIpV6ExtensionHeaders(random.NextInt(0, 10));
IpV4Protocol nextHeader = extensionHeaders.FirstHeader ?? random.NextEnum<IpV4Protocol>(IpV6ExtensionHeader.ExtensionHeaders);
IpV4Protocol? lastNextHeader = withAutomaticNextLayer ? (IpV4Protocol?)null : random.NextEnum<IpV4Protocol>(IpV6ExtensionHeader.ExtensionHeaders);
return random.NextIpV6Layer(lastNextHeader, !withAutomaticNextLayer);
}
public static IpV6Layer NextIpV6Layer(this Random random, IpV4Protocol? lastNextHeader, bool allowEncapsulatingSecurityPayload)
{
IpV6ExtensionHeaders extensionHeaders = random.NextIpV6ExtensionHeaders(random.NextInt(0, 10), lastNextHeader, allowEncapsulatingSecurityPayload);
IpV4Protocol nextHeader = extensionHeaders.FirstHeader ?? (lastNextHeader ?? random.NextEnum<IpV4Protocol>(IpV6ExtensionHeader.ExtensionHeaders));
return new IpV6Layer
{
TrafficClass = random.NextByte(),
......@@ -47,21 +53,20 @@ namespace PcapDotNet.Packets.TestUtils
};
}
public static IpV6ExtensionHeaders NextIpV6ExtensionHeaders(this Random random, int count)
public static IpV6ExtensionHeaders NextIpV6ExtensionHeaders(this Random random, int count, IpV4Protocol? nextHeader, bool allowEncapsulatingSecurityPayload)
{
if (count == 0)
return IpV6ExtensionHeaders.Empty;
IpV4Protocol nextHeader = random.NextEnum<IpV4Protocol>(IpV6ExtensionHeader.ExtensionHeaders);
IpV6ExtensionHeader[] headers = new IpV6ExtensionHeader[count];
for (int i = headers.Length - 1; i >= 0; --i)
{
headers[i] = random.NextIpV6ExtensionHeader(nextHeader, i == headers.Length - 1);
headers[i] = random.NextIpV6ExtensionHeader(nextHeader, allowEncapsulatingSecurityPayload && i == headers.Length - 1);
nextHeader = headers[i].Protocol;
}
return new IpV6ExtensionHeaders(headers);
}
public static IpV6ExtensionHeader NextIpV6ExtensionHeader(this Random random, IpV4Protocol nextHeader, bool isEncapsulatingSecurityPayloadPossible)
public static IpV6ExtensionHeader NextIpV6ExtensionHeader(this Random random, IpV4Protocol? nextHeader, bool isEncapsulatingSecurityPayloadPossible)
{
IpV4Protocol extensionHeaderType =
random.NextValue(
......@@ -118,7 +123,7 @@ namespace PcapDotNet.Packets.TestUtils
}
}
public static IpV6ExtensionHeaderMobility NextIpV6ExtensionHeaderMobility(this Random random, IpV4Protocol nextHeader)
public static IpV6ExtensionHeaderMobility NextIpV6ExtensionHeaderMobility(this Random random, IpV4Protocol? nextHeader)
{
IpV6MobilityHeaderType mobilityHeaderType = random.NextEnum<IpV6MobilityHeaderType>();
ushort checksum = random.NextUShort();
......
......@@ -96,6 +96,8 @@ namespace PcapDotNet.Packets.Ethernet
get { return PayloadDatagrams.VLanTaggedFrame; }
}
// TODO: Add Ip property.
/// <summary>
/// The Ethernet payload as an IPv4 datagram.
/// </summary>
......
......@@ -20,6 +20,8 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Identifies the type of header immediately following this extension header.
/// If the extension header is constructed with null NextHeader, it would be auto calculated according to the next extension or next layer when writing
/// the layer.
/// </summary>
public IpV4Protocol? NextHeader { get; private set; }
......@@ -98,7 +100,7 @@ namespace PcapDotNet.Packets.IpV6
}
}
internal abstract void Write(byte[] buffer, ref int offset);
internal abstract void Write(byte[] buffer, ref int offset, IpV4Protocol nextHeader);
private static readonly ReadOnlyCollection<IpV4Protocol> _extensionHeaders =
IpV6ExtensionHeaderStandard.StandardExtensionHeaders.Concat(
......
......@@ -65,7 +65,7 @@ namespace PcapDotNet.Packets.IpV6
/// All implementations must support such padding.
/// The authentication algorithm specification must specify the length of the ICV and the comparison rules and processing steps for validation.
/// </param>
public IpV6ExtensionHeaderAuthentication(IpV4Protocol nextHeader, uint securityParametersIndex, uint sequenceNumber, DataSegment authenticationData)
public IpV6ExtensionHeaderAuthentication(IpV4Protocol? nextHeader, uint securityParametersIndex, uint sequenceNumber, DataSegment authenticationData)
: base(nextHeader)
{
if (authenticationData == null)
......@@ -200,9 +200,9 @@ namespace PcapDotNet.Packets.IpV6
return new IpV6ExtensionHeaderAuthentication(nextHeader, securityParametersIndex, sequenceNumber, authenticationData);
}
internal override void Write(byte[] buffer, ref int offset)
internal override void Write(byte[] buffer, ref int offset, IpV4Protocol nextHeader)
{
buffer.Write(offset + Offset.NextHeader, (byte)NextHeader);
buffer.Write(offset + Offset.NextHeader, (byte)(nextHeader));
int length = Length;
buffer.Write(offset + Offset.PayloadLength, (byte)((length / 4) - 2));
buffer.Write(offset + Offset.SecurityParametersIndex, SecurityParametersIndex, Endianity.Big);
......
......@@ -23,7 +23,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
/// <param name="nextHeader">Identifies the type of header immediately following this extension header.</param>
/// <param name="options">Extension header options.</param>
public IpV6ExtensionHeaderDestinationOptions(IpV4Protocol nextHeader, IpV6Options options)
public IpV6ExtensionHeaderDestinationOptions(IpV4Protocol? nextHeader, IpV6Options options)
: base(nextHeader, options)
{
}
......
......@@ -224,7 +224,7 @@ namespace PcapDotNet.Packets.IpV6
return new IpV6ExtensionHeaderEncapsulatingSecurityPayload(securityParametersIndex, sequenceNumber, encryptedDataAndAuthenticationData);
}
internal override void Write(byte[] buffer, ref int offset)
internal override void Write(byte[] buffer, ref int offset, IpV4Protocol nextHeader)
{
buffer.Write(offset + Offset.SecurityParametersIndex, SecurityParametersIndex, Endianity.Big);
buffer.Write(offset + Offset.SequenceNumber, SequenceNumber, Endianity.Big);
......
......@@ -62,7 +62,7 @@ namespace PcapDotNet.Packets.IpV6
/// The Identification must be different than that of any other fragmented packet sent recently with the same Source Address and Destination Address.
/// If a Routing header is present, the Destination Address of concern is that of the final destination.
/// </param>
public IpV6ExtensionHeaderFragmentData(IpV4Protocol nextHeader, ushort fragmentOffset, bool moreFragments, uint identification)
public IpV6ExtensionHeaderFragmentData(IpV4Protocol? nextHeader, ushort fragmentOffset, bool moreFragments, uint identification)
: base(nextHeader)
{
if (fragmentOffset > MaxFragmentOffset)
......
......@@ -22,7 +22,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
/// <param name="nextHeader">Identifies the type of header immediately following this extension header.</param>
/// <param name="options">Options for the extension header.</param>
public IpV6ExtensionHeaderHopByHopOptions(IpV4Protocol nextHeader, IpV6Options options)
public IpV6ExtensionHeaderHopByHopOptions(IpV4Protocol? nextHeader, IpV6Options options)
: base(nextHeader, options)
{
}
......
......@@ -88,7 +88,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public IpV6MobilityOptions MobilityOptions { get; private set; }
internal IpV6ExtensionHeaderMobility(IpV4Protocol nextHeader, ushort checksum, IpV6MobilityOptions mobilityOptions, int? messageDataMobilityOptionsOffset)
internal IpV6ExtensionHeaderMobility(IpV4Protocol? nextHeader, ushort checksum, IpV6MobilityOptions mobilityOptions, int? messageDataMobilityOptionsOffset)
: base(nextHeader)
{
if (messageDataMobilityOptionsOffset.HasValue)
......
......@@ -83,7 +83,7 @@ namespace PcapDotNet.Packets.IpV6
/// for which this node should retain the entry for this mobile node in its Binding Cache.
/// </param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityBindingAcknowledgement(IpV4Protocol nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
public IpV6ExtensionHeaderMobilityBindingAcknowledgement(IpV4Protocol? nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
bool keyManagementMobilityCapability, bool mobileRouter, bool proxyRegistration,
bool typeLengthValueHeaderFormat, ushort sequenceNumber, ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, status, keyManagementMobilityCapability, sequenceNumber, lifetime, options)
......
......@@ -84,7 +84,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ushort Lifetime { get; private set; }
internal IpV6ExtensionHeaderMobilityBindingAcknowledgementBase(IpV4Protocol nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
internal IpV6ExtensionHeaderMobilityBindingAcknowledgementBase(IpV4Protocol? nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
bool keyManagementMobilityCapability, ushort sequenceNumber, ushort lifetime,
IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
......
......@@ -65,7 +65,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="options">
/// Zero or more TLV-encoded mobility options.
/// </param>
public IpV6ExtensionHeaderMobilityBindingError(IpV4Protocol nextHeader, ushort checksum, IpV6BindingErrorStatus status, IpV6Address homeAddress,
public IpV6ExtensionHeaderMobilityBindingError(IpV4Protocol? nextHeader, ushort checksum, IpV6BindingErrorStatus status, IpV6Address homeAddress,
IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
......
......@@ -44,7 +44,7 @@ namespace PcapDotNet.Packets.IpV6
/// The checksum is the 16-bit one's complement of the one's complement sum of this string.
/// </param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityBindingRefreshRequest(IpV4Protocol nextHeader, ushort checksum, IpV6MobilityOptions options)
public IpV6ExtensionHeaderMobilityBindingRefreshRequest(IpV4Protocol? nextHeader, ushort checksum, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
}
......
......@@ -59,7 +59,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="options">
/// Zero or more TLV-encoded mobility options.
/// </param>
public IpV6ExtensionHeaderMobilityBindingRevocationAcknowledgementMessage(IpV4Protocol nextHeader, ushort checksum,
public IpV6ExtensionHeaderMobilityBindingRevocationAcknowledgementMessage(IpV4Protocol? nextHeader, ushort checksum,
Ipv6MobilityBindingRevocationStatus status, ushort sequenceNumber,
bool proxyBinding, bool ipV4HomeAddressBindingOnly, bool global,
IpV6MobilityOptions options)
......
......@@ -63,7 +63,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="options">
/// Zero or more TLV-encoded mobility options.
/// </param>
public IpV6ExtensionHeaderMobilityBindingRevocationIndicationMessage(IpV4Protocol nextHeader, ushort checksum,
public IpV6ExtensionHeaderMobilityBindingRevocationIndicationMessage(IpV4Protocol? nextHeader, ushort checksum,
Ipv6MobilityBindingRevocationTrigger revocationTrigger, ushort sequenceNumber,
bool proxyBinding, bool ipV4HomeAddressBindingOnly, bool global,
IpV6MobilityOptions options)
......
......@@ -96,7 +96,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public bool Global { get; private set; }
internal IpV6ExtensionHeaderMobilityBindingRevocationMessage(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool proxyBinding,
internal IpV6ExtensionHeaderMobilityBindingRevocationMessage(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber, bool proxyBinding,
bool ipV4HomeAddressBindingOnly, bool global, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
......
......@@ -114,7 +114,7 @@ namespace PcapDotNet.Packets.IpV6
/// One time unit is 4 seconds for Binding Update and 1 second for Fast Binding Update.
/// </param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityBindingUpdate(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge, bool homeRegistration,
public IpV6ExtensionHeaderMobilityBindingUpdate(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge, bool homeRegistration,
bool linkLocalAddressCompatibility, bool keyManagementMobilityCapability, bool mapRegistration,
bool mobileRouter, bool proxyRegistration, bool forcingUdpEncapsulation, bool typeLengthValueHeaderFormat,
bool bulkBindingUpdate, ushort lifetime, IpV6MobilityOptions options)
......
......@@ -97,7 +97,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ushort Lifetime { get; private set; }
internal IpV6ExtensionHeaderMobilityBindingUpdateBase(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge,
internal IpV6ExtensionHeaderMobilityBindingUpdateBase(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge,
bool homeRegistration, bool linkLocalAddressCompatibility, bool keyManagementMobilityCapability,
ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
......
......@@ -61,7 +61,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="careOfInitCookie">Contains the care-of init cookie.</param>
/// <param name="careOfKeygenToken">Contains the 64-bit care-of keygen token used in the return routability procedure.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityCareOfTest(IpV4Protocol nextHeader, ushort checksum, ushort careOfNonceIndex, ulong careOfInitCookie,
public IpV6ExtensionHeaderMobilityCareOfTest(IpV4Protocol? nextHeader, ushort checksum, ushort careOfNonceIndex, ulong careOfInitCookie,
ulong careOfKeygenToken, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
......
......@@ -51,7 +51,7 @@ namespace PcapDotNet.Packets.IpV6
/// </param>
/// <param name="careOfInitCookie">Contains a random value, the care-of init cookie.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityCareOfTestInit(IpV4Protocol nextHeader, ushort checksum, ulong careOfInitCookie, IpV6MobilityOptions options)
public IpV6ExtensionHeaderMobilityCareOfTestInit(IpV4Protocol? nextHeader, ushort checksum, ulong careOfInitCookie, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
CareOfInitCookie = careOfInitCookie;
......
......@@ -37,7 +37,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="messageData">
/// Carries the data specific to the experimental protocol extension.
/// </param>
public IpV6ExtensionHeaderMobilityExperimental(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
public IpV6ExtensionHeaderMobilityExperimental(IpV4Protocol? nextHeader, ushort checksum, DataSegment messageData)
: base(nextHeader, checksum, IpV6MobilityOptions.None, null)
{
if (messageData == null)
......
......@@ -61,7 +61,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="options">
/// Zero or more TLV-encoded mobility options.
/// </param>
public IpV6ExtensionHeaderMobilityFastBindingAcknowledgement(IpV4Protocol nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
public IpV6ExtensionHeaderMobilityFastBindingAcknowledgement(IpV4Protocol? nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
bool keyManagementMobilityCapability, ushort sequenceNumber, ushort lifetime,
IpV6MobilityOptions options)
: base(nextHeader, checksum, status, keyManagementMobilityCapability, sequenceNumber, lifetime, options)
......
......@@ -70,7 +70,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="options">
/// Zero or more TLV-encoded mobility options.
/// </param>
public IpV6ExtensionHeaderMobilityFastBindingUpdate(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge,
public IpV6ExtensionHeaderMobilityFastBindingUpdate(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge,
bool homeRegistration, bool linkLocalAddressCompatibility, bool keyManagementMobilityCapability,
ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, sequenceNumber, acknowledge, homeRegistration, linkLocalAddressCompatibility, keyManagementMobilityCapability, lifetime, options)
......
......@@ -49,7 +49,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="options">
/// Zero or more TLV-encoded mobility options.
/// </param>
public IpV6ExtensionHeaderMobilityFastNeighborAdvertisement(IpV4Protocol nextHeader, ushort checksum, IpV6MobilityOptions options)
public IpV6ExtensionHeaderMobilityFastNeighborAdvertisement(IpV4Protocol? nextHeader, ushort checksum, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
}
......
......@@ -54,7 +54,7 @@ namespace PcapDotNet.Packets.IpV6
/// </param>
/// <param name="code">Describes whether the handover was accepted or not and more details.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityHandoverAcknowledgeMessage(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber,
public IpV6ExtensionHeaderMobilityHandoverAcknowledgeMessage(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber,
IpV6MobilityHandoverAcknowledgeCode code, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
......
......@@ -68,7 +68,7 @@ namespace PcapDotNet.Packets.IpV6
/// </param>
/// <param name="code">Describes whether the source ip address is a previous care of address.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityHandoverInitiateMessage(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool assignedAddressConfiguration,
public IpV6ExtensionHeaderMobilityHandoverInitiateMessage(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber, bool assignedAddressConfiguration,
bool buffer, IpV6HandoverInitiateMessageCode code, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
......
......@@ -64,7 +64,7 @@ namespace PcapDotNet.Packets.IpV6
/// </param>
/// <param name="sequenceNumber">Sequence number used for matching the request to the reply.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityHeartbeatMessage(IpV4Protocol nextHeader, ushort checksum, bool isUnsolicitedHeartbeatResponse, bool isResponse,
public IpV6ExtensionHeaderMobilityHeartbeatMessage(IpV4Protocol? nextHeader, ushort checksum, bool isUnsolicitedHeartbeatResponse, bool isResponse,
uint sequenceNumber, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.MobilityOptions)
{
......
......@@ -54,7 +54,7 @@ namespace PcapDotNet.Packets.IpV6
/// </param>
/// <param name="homeAgentAddresses">A list of alternate home agent addresses for the mobile node.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityHomeAgentSwitchMessage(IpV4Protocol nextHeader, ushort checksum, ReadOnlyCollection<IpV6Address> homeAgentAddresses,
public IpV6ExtensionHeaderMobilityHomeAgentSwitchMessage(IpV4Protocol? nextHeader, ushort checksum, ReadOnlyCollection<IpV6Address> homeAgentAddresses,
IpV6MobilityOptions options)
: base(nextHeader, checksum, options,
MessageDataOffset.HomeAgentAddresses + (homeAgentAddresses == null ? 0 : homeAgentAddresses.Count) * IpV6Address.SizeOf)
......@@ -76,7 +76,7 @@ namespace PcapDotNet.Packets.IpV6
/// </param>
/// <param name="homeAgentAddresses">A list of alternate home agent addresses for the mobile node.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityHomeAgentSwitchMessage(IpV4Protocol nextHeader, ushort checksum, IList<IpV6Address> homeAgentAddresses, IpV6MobilityOptions options)
public IpV6ExtensionHeaderMobilityHomeAgentSwitchMessage(IpV4Protocol? nextHeader, ushort checksum, IList<IpV6Address> homeAgentAddresses, IpV6MobilityOptions options)
: this(nextHeader, checksum, (ReadOnlyCollection<IpV6Address>)homeAgentAddresses.AsReadOnly(), options)
{
}
......
......@@ -61,7 +61,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="homeInitCookie">Contains the home init cookie.</param>
/// <param name="homeKeygenToken">Contains the 64-bit home keygen token used in the return routability procedure.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityHomeTest(IpV4Protocol nextHeader, ushort checksum, ushort homeNonceIndex, ulong homeInitCookie, ulong homeKeygenToken,
public IpV6ExtensionHeaderMobilityHomeTest(IpV4Protocol? nextHeader, ushort checksum, ushort homeNonceIndex, ulong homeInitCookie, ulong homeKeygenToken,
IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
......
......@@ -51,7 +51,7 @@ namespace PcapDotNet.Packets.IpV6
/// </param>
/// <param name="homeInitCookie">Contains a random value, the home init cookie.</param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityHomeTestInit(IpV4Protocol nextHeader, ushort checksum, ulong homeInitCookie, IpV6MobilityOptions options)
public IpV6ExtensionHeaderMobilityHomeTestInit(IpV4Protocol? nextHeader, ushort checksum, ulong homeInitCookie, IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
HomeInitCookie = homeInitCookie;
......
......@@ -60,7 +60,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ushort Lifetime { get; private set; }
internal IpV6ExtensionHeaderMobilityLocalizedRouting(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, ushort lifetime,
internal IpV6ExtensionHeaderMobilityLocalizedRouting(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber, ushort lifetime,
IpV6MobilityOptions options)
: base(nextHeader, checksum, options, MessageDataOffset.Options)
{
......
......@@ -61,7 +61,7 @@ namespace PcapDotNet.Packets.IpV6
/// Typically copied from the corresponding field in the LRI message.
/// </param>
/// <param name="options">Zero or more TLV-encoded mobility options.</param>
public IpV6ExtensionHeaderMobilityLocalizedRoutingAcknowledgement(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool unsolicited,
public IpV6ExtensionHeaderMobilityLocalizedRoutingAcknowledgement(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber, bool unsolicited,
IpV6MobilityLocalizedRoutingAcknowledgementStatus status, ushort lifetime,
IpV6MobilityOptions options)
: base(nextHeader, checksum, sequenceNumber, lifetime, options)
......
......@@ -50,7 +50,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="options">
/// Zero or more TLV-encoded mobility options.
/// </param>
public IpV6ExtensionHeaderMobilityLocalizedRoutingInitiation(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber,
public IpV6ExtensionHeaderMobilityLocalizedRoutingInitiation(IpV4Protocol? nextHeader, ushort checksum, ushort sequenceNumber,
ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, sequenceNumber, lifetime, options)
{
......
......@@ -51,7 +51,7 @@ namespace PcapDotNet.Packets.IpV6
Options.Write(buffer, offset);
}
internal IpV6ExtensionHeaderOptions(IpV4Protocol nextHeader, IpV6Options options)
internal IpV6ExtensionHeaderOptions(IpV4Protocol? nextHeader, IpV6Options options)
: base(nextHeader)
{
if (options.BytesLength % 8 != 6)
......
......@@ -56,7 +56,7 @@ namespace PcapDotNet.Packets.IpV6
get { return IpV4Protocol.IpV6Route; }
}
internal IpV6ExtensionHeaderRouting(IpV4Protocol nextHeader, byte segmentsLeft)
internal IpV6ExtensionHeaderRouting(IpV4Protocol? nextHeader, byte segmentsLeft)
: base(nextHeader)
{
SegmentsLeft = segmentsLeft;
......
......@@ -43,7 +43,7 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="homeAddress">
/// The home address of the destination mobile node.
/// </param>
public IpV6ExtensionHeaderRoutingHomeAddress(IpV4Protocol nextHeader, byte segmentsLeft, IpV6Address homeAddress)
public IpV6ExtensionHeaderRoutingHomeAddress(IpV4Protocol? nextHeader, byte segmentsLeft, IpV6Address homeAddress)
: base(nextHeader, segmentsLeft)
{
HomeAddress = homeAddress;
......
......@@ -90,7 +90,7 @@ namespace PcapDotNet.Packets.IpV6
/// For example, a header carrying a full IPv6 address in Addresses[n] sets this to 0.
/// </param>
/// <param name="addresses">Routing addresses.</param>
public IpV6ExtensionHeaderRoutingProtocolLowPowerAndLossyNetworks(IpV4Protocol nextHeader, byte segmentsLeft, byte commonPrefixLengthForNonLastAddresses,
public IpV6ExtensionHeaderRoutingProtocolLowPowerAndLossyNetworks(IpV4Protocol? nextHeader, byte segmentsLeft, byte commonPrefixLengthForNonLastAddresses,
byte commonPrefixLengthForLastAddress, params IpV6Address[] addresses)
: base(nextHeader, segmentsLeft)
{
......
......@@ -57,7 +57,7 @@ namespace PcapDotNet.Packets.IpV6
/// Number of route segments remaining, i.e., number of explicitly listed intermediate nodes still to be visited before reaching the final destination.
/// </param>
/// <param name="addresses">Routing addresses.</param>
public IpV6ExtensionHeaderRoutingSourceRoute(IpV4Protocol nextHeader, byte segmentsLeft, params IpV6Address[] addresses)
public IpV6ExtensionHeaderRoutingSourceRoute(IpV4Protocol? nextHeader, byte segmentsLeft, params IpV6Address[] addresses)
: base(nextHeader, segmentsLeft)
{
Addresses = addresses.AsReadOnly();
......
......@@ -58,14 +58,14 @@ namespace PcapDotNet.Packets.IpV6
internal abstract int GetDataHashCode();
internal IpV6ExtensionHeaderStandard(IpV4Protocol nextHeader)
internal IpV6ExtensionHeaderStandard(IpV4Protocol? nextHeader)
: base(nextHeader)
{
}
internal sealed override void Write(byte[] buffer, ref int offset)
internal sealed override void Write(byte[] buffer, ref int offset, IpV4Protocol nextHeader)
{
buffer.Write(offset + Offset.NextHeader, (byte)NextHeader);
buffer.Write(offset + Offset.NextHeader, (byte)nextHeader);
int length = Length;
buffer.Write(offset + Offset.HeaderExtensionLength, (byte)((length / 8) - 1));
WriteData(buffer, offset + Offset.Data);
......
......@@ -26,13 +26,18 @@ namespace PcapDotNet.Packets.IpV6
throw new ArgumentNullException("extensionHeaders");
for (int i = 0; i < extensionHeaders.Count; ++i)
{
if (extensionHeaders[i].Protocol == IpV4Protocol.EncapsulatingSecurityPayload && i != extensionHeaders.Count - 1)
IpV6ExtensionHeader extensionHeader = extensionHeaders[i];
if (i != extensionHeaders.Count - 1)
{
throw new ArgumentException(
string.Format(CultureInfo.InvariantCulture,
"EncapsulatingSecurityPayload can only be the last extension header. However it is the {0} out of {1}.", (i + 1),
extensionHeaders.Count), "extensionHeaders");
if (extensionHeader.Protocol == IpV4Protocol.EncapsulatingSecurityPayload)
{
throw new ArgumentException(
string.Format(CultureInfo.InvariantCulture,
"EncapsulatingSecurityPayload can only be the last extension header. However it is the {0} out of {1}.", (i + 1),
extensionHeaders.Count), "extensionHeaders");
}
}
BytesLength += extensionHeader.Length;
}
Headers = extensionHeaders;
IsValid = true;
......@@ -208,10 +213,25 @@ namespace PcapDotNet.Packets.IpV6
IsValid = (!nextHeader.HasValue || !IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value)) && headers.All(header => header.IsValid);
}
internal void Write(byte[] buffer, int offset)
internal void Write(byte[] buffer, int offset, IpV4Protocol? nextLayerProtocol)
{
foreach (IpV6ExtensionHeader extensionHeader in this)
extensionHeader.Write(buffer, ref offset);
for (int i = 0; i != Headers.Count; ++i)
{
IpV6ExtensionHeader extensionHeader = Headers[i];
IpV4Protocol nextHeader;
if (extensionHeader.NextHeader != null)
nextHeader = extensionHeader.NextHeader.Value;
else if (i < Headers.Count - 1)
nextHeader = Headers[i + 1].Protocol;
else if (nextLayerProtocol.HasValue)
nextHeader = nextLayerProtocol.Value;
else if (extensionHeader.Protocol == IpV4Protocol.EncapsulatingSecurityPayload)
nextHeader = IpV4Protocol.NoNextHeaderForIpV6; // Arbitrary.
else
throw new InvalidOperationException("Can't determine extension header next header value. It is the last extension header with no known next layer protocol.");
extensionHeader.Write(buffer, ref offset, nextHeader);
}
}
private static readonly IpV6ExtensionHeaders _empty = new IpV6ExtensionHeaders();
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ip;
using PcapDotNet.Packets.IpV4;
......@@ -168,19 +169,22 @@ namespace PcapDotNet.Packets.IpV6
get { return HeaderLength + PayloadLength; }
}
// TODO: Sort method by visibility.
protected override ushort CalculateTransportChecksum()
{
return CalculateTransportChecksum(Buffer, StartOffset, (ushort)Transport.Length, Transport.ChecksumOffset, Transport.IsChecksumOptional, CurrentDestination);
return CalculateTransportChecksum(Buffer, StartOffset, HeaderLength + ExtensionHeaders.BytesLength, (uint)Transport.Length, Transport.ChecksumOffset,
Transport.IsChecksumOptional, CurrentDestination);
}
private static ushort CalculateTransportChecksum(byte[] buffer, int offset, ushort transportLength, int transportChecksumOffset, bool isChecksumOptional, IpV6Address destination)
private static ushort CalculateTransportChecksum(byte[] buffer, int offset, int fullHeaderLength, uint transportLength, int transportChecksumOffset, bool isChecksumOptional, IpV6Address destination)
{
int offsetAfterChecksum = offset + HeaderLength + transportChecksumOffset + 2;
int offsetAfterChecksum = offset + fullHeaderLength + transportChecksumOffset + sizeof(ushort);
uint sum = Sum16Bits(buffer, offset + Offset.SourceAddress, IpV6Address.SizeOf) +
Sum16Bits(destination) +
transportLength + buffer[offset + Offset.NextHeader] +
Sum16Bits(buffer, offset + HeaderLength, transportChecksumOffset) +
Sum16Bits(buffer, offsetAfterChecksum, transportLength - transportChecksumOffset - 2);
Sum16Bits(transportLength) + buffer[offset + Offset.NextHeader] +
Sum16Bits(buffer, offset + fullHeaderLength, transportChecksumOffset) +
Sum16Bits(buffer, offsetAfterChecksum, (int)(transportLength - transportChecksumOffset - sizeof(ushort)));
ushort checksumResult = Sum16BitsToChecksum(sum);
if (checksumResult == 0 && isChecksumOptional)
......@@ -221,6 +225,14 @@ namespace PcapDotNet.Packets.IpV6
_isValid = _isValid && _extensionHeaders.IsValid;
}
internal static void WriteTransportChecksum(byte[] buffer, int offset, int headerLength, uint transportLength, int transportChecksumOffset,
bool isChecksumOptional, ushort? checksum, IpV6Address destination)
{
ushort checksumValue =
checksum ?? CalculateTransportChecksum(buffer, offset, headerLength, transportLength, transportChecksumOffset, isChecksumOptional, destination);
buffer.Write(offset + headerLength + transportChecksumOffset, checksumValue, Endianity.Big);
}
/// <summary>
/// Creates a Layer that represents the datagram to be used with PacketBuilder.
/// </summary>
......@@ -239,7 +251,7 @@ namespace PcapDotNet.Packets.IpV6
}
/// <summary>
/// The default validity check always returns true.
/// Valid if all extension headers are valid.
/// </summary>
protected override bool CalculateIsValid()
{
......@@ -261,16 +273,25 @@ namespace PcapDotNet.Packets.IpV6
}
internal static void WriteHeader(byte[] buffer, int offset,
byte trafficClass, int flowLabel, ushort payloadLength, IpV4Protocol nextHeader, byte hopLimit,
IpV6Address source, IpV6Address currentDestination, IpV6ExtensionHeaders extensionHeaders)
byte trafficClass, int flowLabel, ushort payloadLength, IpV4Protocol? nextHeader, IpV4Protocol? nextLayerProtocol,
byte hopLimit, IpV6Address source, IpV6Address currentDestination, IpV6ExtensionHeaders extensionHeaders)
{
buffer.Write(offset + Offset.Version, (uint)((((DefaultVersion << 8) | trafficClass) << 20) | flowLabel), Endianity.Big);
buffer.Write(offset + Offset.PayloadLength, payloadLength, Endianity.Big);
buffer.Write(offset + Offset.NextHeader, (byte)nextHeader);
IpV4Protocol actualNextHeader;
if (nextHeader.HasValue)
actualNextHeader = nextHeader.Value;
else if (extensionHeaders.Any())
actualNextHeader = extensionHeaders.FirstHeader.Value;
else if (nextLayerProtocol.HasValue)
actualNextHeader = nextLayerProtocol.Value;
else
throw new InvalidOperationException("Can't determinte next header. No extension headers and no known next layer protocol.");
buffer.Write(offset + Offset.NextHeader, (byte)actualNextHeader);
buffer.Write(offset + Offset.HopLimit, hopLimit);
buffer.Write(offset + Offset.SourceAddress, source, Endianity.Big);
buffer.Write(offset + Offset.DestinationAddress, currentDestination, Endianity.Big);
extensionHeaders.Write(buffer, offset + HeaderLength);
extensionHeaders.Write(buffer, offset + HeaderLength, nextLayerProtocol);
}
private IpV6ExtensionHeaders _extensionHeaders;
......
......@@ -94,7 +94,12 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public override int Length
{
get { return IpV6Datagram.HeaderLength + ExtensionHeaders.Sum(header => header.Length); }
get { return IpV6Datagram.HeaderLength + ExtensionHeaders.BytesLength; }
}
public IpV4Protocol? LastNextHeader
{
get { return ExtensionHeaders.Any() ? ExtensionHeaders.NextHeader : NextHeader; }
}
/// <summary>
......@@ -107,33 +112,29 @@ namespace PcapDotNet.Packets.IpV6
/// <param name="nextLayer">The layer that comes after this layer. null if this is the last layer.</param>
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
IpV4Protocol nextHeader;
if (NextHeader == null)
{
if (ExtensionHeaders.FirstHeader != null)
{
nextHeader = ExtensionHeaders.FirstHeader.Value;
}
else
{
if (nextLayer == null)
throw new ArgumentException("Can't determine protocol automatically from next layer because there is no next layer");
IIpNextLayer ipNextLayer = nextLayer as IIpNextLayer;
if (ipNextLayer == null)
throw new ArgumentException("Can't determine protocol automatically from next layer (" + nextLayer.GetType() + ")");
nextHeader = ipNextLayer.PreviousLayerProtocol;
}
}
else
IpV4Protocol? nextLayerProtocol = null;
if (nextLayer != null)
{
nextHeader = NextHeader.Value;
IIpNextLayer ipNextLayer = nextLayer as IIpNextLayer;
if (ipNextLayer != null)
nextLayerProtocol = ipNextLayer.PreviousLayerProtocol;
}
if (nextLayer != null && ExtensionHeaders.LastHeader == IpV4Protocol.EncapsulatingSecurityPayload)
throw new ArgumentException("Cannot have a layer after IpV6Layer with EncapsulatingSecurityPayload extension header.", "nextLayer");
IpV6Datagram.WriteHeader(buffer, offset,
TrafficClass, FlowLabel, (ushort)(payloadLength + ExtensionHeaders.Sum(header => header.Length)), nextHeader, HopLimit, Source, CurrentDestination, ExtensionHeaders);
TrafficClass, FlowLabel, (ushort)(payloadLength + ExtensionHeaders.BytesLength), NextHeader, nextLayerProtocol, HopLimit, Source, CurrentDestination, ExtensionHeaders);
}
public override void Finalize(byte[] buffer, int offset, int payloadLength, ILayer nextLayer)
{
IIpNextTransportLayer nextTransportLayer = nextLayer as IIpNextTransportLayer;
if (nextTransportLayer == null || !nextTransportLayer.CalculateChecksum)
return;
IpV6Datagram.WriteTransportChecksum(buffer, offset, Length, (uint)payloadLength,
nextTransportLayer.ChecksumOffset, nextTransportLayer.IsChecksumOptional,
nextTransportLayer.Checksum, CurrentDestination);
}
/// <summary>
......@@ -172,7 +173,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public override string ToString()
{
return Source + " -> " + CurrentDestination + " (" + NextHeader + ")";
return string.Format("{0} -> {1} ({2})", Source, CurrentDestination, NextHeader);
}
}
}
\ No newline at end of file
......@@ -43,7 +43,6 @@ namespace PcapDotNet.Packets.Transport
{
}
private static readonly TcpOptions _none = new TcpOptions();
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment