Ipv6Extension-Option link

This commit is contained in:
Fabian Mauchle
2009-11-02 09:48:21 +01:00
parent 7b8fec936e
commit c4749e0afb
7 changed files with 330 additions and 150 deletions

View File

@@ -120,6 +120,83 @@ uint32_t Ipv6ExtensionHeader::Deserialize (Buffer::Iterator start)
return GetSerializedSize ();
}
OptionField::OptionField(uint32_t optionsOffset)
: m_optionData(0),
m_optionsOffset(optionsOffset)
{
}
OptionField::~OptionField()
{
}
uint32_t OptionField::GetSerializedSize () const
{
return m_optionData.GetSize() + CalculatePad((Ipv6OptionHeader::Alignment) {8,0});
}
void OptionField::Serialize (Buffer::Iterator start) const
{
start.Write(m_optionData.Begin(), m_optionData.End());
uint32_t fill = CalculatePad((Ipv6OptionHeader::Alignment) {8,0});
NS_LOG_LOGIC("fill with " << fill << " bytes padding");
switch(fill)
{
case 0: return;
case 1: Ipv6OptionPad1Header().Serialize(start);
return;
default: Ipv6OptionPadnHeader(fill).Serialize(start);
return;
}
}
uint32_t OptionField::Deserialize (Buffer::Iterator start, uint32_t length)
{
uint8_t buf[length];
start.Read(buf,length);
m_optionData = Buffer();
m_optionData.AddAtEnd(length);
m_optionData.Begin().Write(buf,length);
return length;
}
void OptionField::AddOption(Ipv6OptionHeader const& option)
{
NS_LOG_FUNCTION_NOARGS();
uint32_t pad = CalculatePad(option.GetAlignment());
NS_LOG_LOGIC("need " << pad << " bytes padding");
switch(pad)
{
case 0: break; //no padding needed
case 1: AddOption(Ipv6OptionPad1Header());
break;
default: AddOption(Ipv6OptionPadnHeader(pad));
break;
}
m_optionData.AddAtEnd(option.GetSerializedSize());
Buffer::Iterator it = m_optionData.End();
it.Prev(option.GetSerializedSize());
option.Serialize(it);
}
uint32_t OptionField::CalculatePad(Ipv6OptionHeader::Alignment alignment) const
{
return (alignment.offset - (m_optionData.GetSize() + m_optionsOffset)) % alignment.factor;
}
uint32_t OptionField::GetOptionsOffset()
{
return m_optionsOffset;
}
Buffer OptionField::GetOptionBuffer()
{
return m_optionData;
}
NS_OBJECT_ENSURE_REGISTERED (Ipv6ExtensionHopByHopHeader);
TypeId Ipv6ExtensionHopByHopHeader::GetTypeId ()
@@ -137,6 +214,7 @@ TypeId Ipv6ExtensionHopByHopHeader::GetInstanceTypeId () const
}
Ipv6ExtensionHopByHopHeader::Ipv6ExtensionHopByHopHeader ()
: OptionField(2)
{
}
@@ -151,7 +229,7 @@ void Ipv6ExtensionHopByHopHeader::Print (std::ostream &os) const
uint32_t Ipv6ExtensionHopByHopHeader::GetSerializedSize () const
{
return 2;
return 2 + OptionField::GetSerializedSize();
}
void Ipv6ExtensionHopByHopHeader::Serialize (Buffer::Iterator start) const
@@ -160,6 +238,7 @@ void Ipv6ExtensionHopByHopHeader::Serialize (Buffer::Iterator start) const
i.WriteU8 (GetNextHeader ());
i.WriteU8 ((GetLength () >> 3) - 1);
OptionField::Serialize(i);
}
uint32_t Ipv6ExtensionHopByHopHeader::Deserialize (Buffer::Iterator start)
@@ -168,6 +247,7 @@ uint32_t Ipv6ExtensionHopByHopHeader::Deserialize (Buffer::Iterator start)
SetNextHeader (i.ReadU8 ());
SetLength ((i.ReadU8 () + 1) << 3);
OptionField::Deserialize(i, GetLength() - 2);
return GetSerializedSize ();
}
@@ -189,6 +269,7 @@ TypeId Ipv6ExtensionDestinationHeader::GetInstanceTypeId () const
}
Ipv6ExtensionDestinationHeader::Ipv6ExtensionDestinationHeader ()
: OptionField(2)
{
}
@@ -203,7 +284,7 @@ void Ipv6ExtensionDestinationHeader::Print (std::ostream &os) const
uint32_t Ipv6ExtensionDestinationHeader::GetSerializedSize () const
{
return 2;
return 2 + OptionField::GetSerializedSize();
}
void Ipv6ExtensionDestinationHeader::Serialize (Buffer::Iterator start) const
@@ -212,6 +293,8 @@ void Ipv6ExtensionDestinationHeader::Serialize (Buffer::Iterator start) const
i.WriteU8 (GetNextHeader ());
i.WriteU8 ((GetLength () >> 3) - 1);
OptionField::Serialize(i);
}
uint32_t Ipv6ExtensionDestinationHeader::Deserialize (Buffer::Iterator start)
@@ -220,6 +303,7 @@ uint32_t Ipv6ExtensionDestinationHeader::Deserialize (Buffer::Iterator start)
SetNextHeader (i.ReadU8 ());
SetLength ((i.ReadU8 () + 1) << 3);
OptionField::Deserialize(i, GetLength() - 2);
return GetSerializedSize ();
}

View File

@@ -22,10 +22,12 @@
#define IPV6_EXTENSION_HEADER_H
#include <vector>
#include <list>
#include <ostream>
#include "ns3/header.h"
#include "ns3/ipv6-address.h"
#include "ipv6-option-header.h"
namespace ns3
{
@@ -126,11 +128,69 @@ class Ipv6ExtensionHeader : public Header
Buffer m_data;
};
/**
* \brief Option field for an IPv6ExtensionHeader
* Enables adding options to an IPv6ExtensionHeader
*
* Implementor's note: Make sure to add the result of
* OptionField::GetSerializedSize() to your IPv6ExtensionHeader::GetSerializedSize()
* return value. Call OptionField::Serialize and OptionField::Deserialize at the
* end of your corresponding IPv6ExtensionHeader methods.
*/
class OptionField
{
public:
OptionField(uint32_t opitonsOffset);
~OptionField();
/**
* \brief Get the serialized size of the packet.
* \return size
*/
uint32_t GetSerializedSize () const;
/**
* \brief Serialize all added options.
* \param start Buffer iterator
*/
void Serialize (Buffer::Iterator start) const;
/**
* \brief Deserialize the packet.
* \param start Buffer iterator
* \return size of the packet
*/
uint32_t Deserialize (Buffer::Iterator start, uint32_t length);
/**
* \brief Serialize the option, prepending pad1 or padn option as necessary
* \param option the option header to serialize
*/
void AddOption(Ipv6OptionHeader const& option);
/**
* \brief Get the offset where the options begin, measured from the start of
* the extension header.
* \return the offset from the start of the extension header
*/
uint32_t GetOptionsOffset();
Buffer GetOptionBuffer();
private:
uint32_t CalculatePad (Ipv6OptionHeader::Alignment alignment) const;
Buffer m_optionData;
uint32_t m_optionsOffset;
};
/**
* \class Ipv6ExtensionHopByHopHeader
* \brief Header of IPv6 Extension "Hop by Hop"
*/
class Ipv6ExtensionHopByHopHeader : public Ipv6ExtensionHeader
class Ipv6ExtensionHopByHopHeader : public Ipv6ExtensionHeader, public OptionField
{
public:
/**
@@ -186,7 +246,7 @@ class Ipv6ExtensionHopByHopHeader : public Ipv6ExtensionHeader
* \class Ipv6ExtensionDestinationHeader
* \brief Header of IPv6 Extension Destination
*/
class Ipv6ExtensionDestinationHeader : public Ipv6ExtensionHeader
class Ipv6ExtensionDestinationHeader : public Ipv6ExtensionHeader, public OptionField
{
public:
/**

View File

@@ -81,6 +81,87 @@ Ptr<Node> Ipv6Extension::GetNode () const
return m_node;
}
uint8_t
Ipv6Extension::ProcessOptions (Ptr<Packet>& packet, uint8_t offset, uint8_t length, Ipv6Header const& ipv6Header, Ipv6Address dst, uint8_t *nextHeader, bool& isDropped)
{
NS_LOG_FUNCTION (this << packet << offset << length << ipv6Header << dst << nextHeader << isDropped);
// For ICMPv6 Error packets
Ptr<Packet> malformedPacket = packet->Copy ();
malformedPacket->AddHeader (ipv6Header);
Ptr<Icmpv6L4Protocol> icmpv6 = GetNode ()->GetObject<Ipv6L3Protocol> ()->GetIcmpv6 ();
Ptr<Packet> p = packet->Copy ();
p->RemoveAtStart (offset);
Ptr<Ipv6OptionDemux> ipv6OptionDemux = GetNode ()->GetObject<Ipv6OptionDemux> ();
Ptr<Ipv6Option> ipv6Option;
uint8_t processedSize = 0;
const uint8_t *data = p->PeekData ();
uint8_t optionType = 0;
uint8_t optionLength = 0;
while (length > processedSize && !isDropped)
{
optionType = *(data + processedSize);
ipv6Option = ipv6OptionDemux->GetOption (optionType);
if (ipv6Option == 0)
{
optionType >>= 6;
switch (optionType)
{
case 0:
optionLength = *(data + processedSize + 1);
break;
case 1:
NS_LOG_LOGIC ("Unknown Option. Drop!");
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
case 2:
NS_LOG_LOGIC ("Unknown Option. Drop!");
/* TODO */
/* icmpv6->SendErrorParameterError (malformedPacket, dst, ipv6Header.GetSourceAddress (), Icmpv6Header::ICMPV6_UNKNOWN_OPTION, offset + processedSize); */
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
case 3:
NS_LOG_LOGIC ("Unknown Option. Drop!");
if (!ipv6Header.GetDestinationAddress ().IsMulticast ())
{
/* TODO */
/* icmpv6->SendErrorParameterError (malformedPacket, dst, ipv6Header.GetSourceAddress (), Icmpv6Header::ICMPV6_UNKNOWN_OPTION, offset + processedSize); */
}
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
default:
break;
}
}
else
{
optionLength = ipv6Option->Process (packet, offset + processedSize, ipv6Header, isDropped);
}
processedSize += optionLength;
p->RemoveAtStart (optionLength);
}
return processedSize;
}
NS_OBJECT_ENSURE_REGISTERED (Ipv6ExtensionHopByHop);
@@ -116,10 +197,6 @@ uint8_t Ipv6ExtensionHopByHop::Process (Ptr<Packet>& packet, uint8_t offset, Ipv
{
NS_LOG_FUNCTION (this << packet << offset << ipv6Header << dst << nextHeader << isDropped);
// For ICMPv6 Error packets
Ptr<Packet> malformedPacket = packet->Copy ();
malformedPacket->AddHeader (ipv6Header);
Ptr<Packet> p = packet->Copy ();
p->RemoveAtStart (offset);
@@ -130,74 +207,11 @@ uint8_t Ipv6ExtensionHopByHop::Process (Ptr<Packet>& packet, uint8_t offset, Ipv
*nextHeader = hopbyhopHeader.GetNextHeader ();
}
Ptr<Icmpv6L4Protocol> icmpv6 = GetNode ()->GetObject<Ipv6L3Protocol> ()->GetIcmpv6 ();
uint8_t processedSize = hopbyhopHeader.GetOptionsOffset();
offset += processedSize;
uint8_t length = hopbyhopHeader.GetLength() - hopbyhopHeader.GetOptionsOffset();
Ptr<Ipv6OptionDemux> ipv6OptionDemux = GetNode ()->GetObject<Ipv6OptionDemux> ();
Ptr<Ipv6Option> ipv6Option;
uint8_t totalSize = hopbyhopHeader.GetLength ();
uint8_t processedSize = hopbyhopHeader.GetSerializedSize ();
const uint8_t *data = p->PeekData ();
uint8_t optionType = 0;
uint8_t optionLength = 0;
isDropped = false;
while (totalSize > processedSize && !isDropped)
{
optionType = *(data + processedSize);
ipv6Option = ipv6OptionDemux->GetOption (optionType);
if (ipv6Option == 0)
{
optionType >>= 6;
switch (optionType)
{
case 0:
optionLength = *(data + processedSize + 1);
break;
case 1:
NS_LOG_LOGIC ("Unknown Option. Drop!");
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
case 2:
NS_LOG_LOGIC ("Unknown Option. Drop!");
/* TODO */
/* icmpv6->SendErrorParameterError (malformedPacket, dst, ipv6Header.GetSourceAddress (), Icmpv6Header::ICMPV6_UNKNOWN_OPTION, offset + processedSize); */
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
case 3:
NS_LOG_LOGIC ("Unknown Option. Drop!");
if (!ipv6Header.GetDestinationAddress ().IsMulticast ())
{
/* TODO */
/* icmpv6->SendErrorParameterError (malformedPacket, dst, ipv6Header.GetSourceAddress (), Icmpv6Header::ICMPV6_UNKNOWN_OPTION, offset + processedSize); */
}
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
default:
break;
}
}
else
{
optionLength = ipv6Option->Process (packet, offset + processedSize, ipv6Header, isDropped);
}
processedSize += optionLength;
p->RemoveAtStart (optionLength);
}
processedSize += ProcessOptions(packet, offset, length, ipv6Header, dst, nextHeader, isDropped);
return processedSize;
}
@@ -237,10 +251,6 @@ uint8_t Ipv6ExtensionDestination::Process (Ptr<Packet>& packet, uint8_t offset,
{
NS_LOG_FUNCTION (this << packet << offset << ipv6Header << dst << nextHeader << isDropped);
// For ICMPv6 Error packets
Ptr<Packet> malformedPacket = packet->Copy ();
malformedPacket->AddHeader (ipv6Header);
Ptr<Packet> p = packet->Copy ();
p->RemoveAtStart (offset);
@@ -251,74 +261,11 @@ uint8_t Ipv6ExtensionDestination::Process (Ptr<Packet>& packet, uint8_t offset,
*nextHeader = destinationHeader.GetNextHeader ();
}
Ptr<Icmpv6L4Protocol> icmpv6 = GetNode ()->GetObject<Ipv6L3Protocol> ()->GetIcmpv6 ();
uint8_t processedSize = destinationHeader.GetOptionsOffset();
offset += processedSize;
uint8_t length = destinationHeader.GetLength() - destinationHeader.GetOptionsOffset();
Ptr<Ipv6OptionDemux> ipv6OptionDemux = GetNode ()->GetObject<Ipv6OptionDemux> ();
Ptr<Ipv6Option> ipv6Option;
uint8_t totalSize = destinationHeader.GetLength ();
uint8_t processedSize = destinationHeader.GetSerializedSize ();
const uint8_t *data = p->PeekData ();
uint8_t optionType = 0;
uint8_t optionLength = 0;
isDropped = false;
while (totalSize > processedSize && !isDropped)
{
optionType = *(data + processedSize);
ipv6Option = ipv6OptionDemux->GetOption (optionType);
if (ipv6Option == 0)
{
optionType >>= 6;
switch (optionType)
{
case 0:
optionLength = *(data + processedSize + 1);
break;
case 1:
NS_LOG_LOGIC ("Unknown Option. Drop!");
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
case 2:
NS_LOG_LOGIC ("Unknown Option. Drop!");
/* TODO */
/* icmpv6->SendErrorParameterError (malformedPacket, dst, ipv6Header.GetSourceAddress (), Icmpv6Header::ICMPV6_UNKNOWN_OPTION, offset + processedSize); */
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
case 3:
NS_LOG_LOGIC ("Unknown Option. Drop!");
if (!ipv6Header.GetDestinationAddress ().IsMulticast ())
{
/* TODO */
/* icmpv6->SendErrorParameterError (malformedPacket, dst, ipv6Header.GetSourceAddress (), Icmpv6Header::ICMPV6_UNKNOWN_OPTION, offset + processedSize); */
}
m_dropTrace (packet);
optionLength = 0;
isDropped = true;
break;
default:
break;
}
}
else
{
optionLength = ipv6Option->Process (packet, offset + processedSize, ipv6Header, isDropped);
}
processedSize += optionLength;
p->RemoveAtStart (optionLength);
}
processedSize += ProcessOptions(packet, offset, length, ipv6Header, dst, nextHeader, isDropped);
return processedSize;
}

View File

@@ -90,6 +90,21 @@ class Ipv6Extension : public Object
*/
virtual uint8_t Process (Ptr<Packet>& packet, uint8_t offset, Ipv6Header const& ipv6Header, Ipv6Address dst, uint8_t *nextHeader, bool& isDropped) = 0;
/**
* \brief Process options
* Called by implementing classes to process the options
*
* \param packet the packet
* \param offset the offset of the first option to process
* \param length the total length of all options (as specified in the extension header)
* \param ipv6Header the IPv6 header of packet received
* \param dst destination address of the packet received (i.e. us)
* \param nextHeader the next header
* \param isDropped if the packet must be dropped
* \return the size processed
*/
virtual uint8_t ProcessOptions (Ptr<Packet>& packet, uint8_t offset, uint8_t length, Ipv6Header const& ipv6Header, Ipv6Address dst, uint8_t *nextHeader, bool& isDropped);
protected:
TracedCallback<Ptr<const Packet> > m_dropTrace;

View File

@@ -81,7 +81,7 @@ void Ipv6OptionHeader::Print (std::ostream &os) const
uint32_t Ipv6OptionHeader::GetSerializedSize () const
{
return 1;
return m_length + 2;
}
void Ipv6OptionHeader::Serialize (Buffer::Iterator start) const
@@ -89,6 +89,9 @@ void Ipv6OptionHeader::Serialize (Buffer::Iterator start) const
Buffer::Iterator i = start;
i.WriteU8 (m_type);
i.WriteU8 (m_length);
i.Write(m_data.Begin(), m_data.End());
}
uint32_t Ipv6OptionHeader::Deserialize (Buffer::Iterator start)
@@ -96,10 +99,23 @@ uint32_t Ipv6OptionHeader::Deserialize (Buffer::Iterator start)
Buffer::Iterator i = start;
m_type = i.ReadU8 ();
m_length = i.ReadU8();
m_data = Buffer();
m_data.AddAtEnd(m_length);
Buffer::Iterator dataStart = i;
i.Next(m_length);
Buffer::Iterator dataEnd = i;
m_data.Begin().Write(dataStart, dataEnd);
return GetSerializedSize ();
}
Ipv6OptionHeader::Alignment Ipv6OptionHeader::GetAlignment() const
{
return (Alignment){1,0};
}
NS_OBJECT_ENSURE_REGISTERED (Ipv6OptionPad1Header);
TypeId Ipv6OptionPad1Header::GetTypeId ()
@@ -118,6 +134,7 @@ TypeId Ipv6OptionPad1Header::GetInstanceTypeId () const
Ipv6OptionPad1Header::Ipv6OptionPad1Header ()
{
SetType(0);
}
Ipv6OptionPad1Header::~Ipv6OptionPad1Header ()
@@ -166,8 +183,11 @@ TypeId Ipv6OptionPadnHeader::GetInstanceTypeId () const
return GetTypeId ();
}
Ipv6OptionPadnHeader::Ipv6OptionPadnHeader ()
Ipv6OptionPadnHeader::Ipv6OptionPadnHeader (uint32_t pad)
{
SetType(1);
NS_ASSERT_MSG (pad >= 2, "PadN must be at least 2 bytes long");
SetLength (pad - 2);
}
Ipv6OptionPadnHeader::~Ipv6OptionPadnHeader ()
@@ -225,6 +245,7 @@ TypeId Ipv6OptionJumbogramHeader::GetInstanceTypeId () const
Ipv6OptionJumbogramHeader::Ipv6OptionJumbogramHeader ()
{
SetType (0xC2);
SetLength (4);
}
@@ -258,7 +279,7 @@ void Ipv6OptionJumbogramHeader::Serialize (Buffer::Iterator start) const
i.WriteU8 (GetType ());
i.WriteU8 (GetLength ());
i.WriteHtonU16 (m_dataLength);
i.WriteHtonU32 (m_dataLength);
}
uint32_t Ipv6OptionJumbogramHeader::Deserialize (Buffer::Iterator start)
@@ -272,6 +293,11 @@ uint32_t Ipv6OptionJumbogramHeader::Deserialize (Buffer::Iterator start)
return GetSerializedSize ();
}
Ipv6OptionHeader::Alignment Ipv6OptionJumbogramHeader::GetAlignment() const
{
return (Alignment){4,2}; //4n+2
}
NS_OBJECT_ENSURE_REGISTERED (Ipv6OptionRouterAlertHeader);
TypeId Ipv6OptionRouterAlertHeader::GetTypeId ()
@@ -338,5 +364,10 @@ uint32_t Ipv6OptionRouterAlertHeader::Deserialize (Buffer::Iterator start)
return GetSerializedSize ();
}
Ipv6OptionHeader::Alignment Ipv6OptionRouterAlertHeader::GetAlignment() const
{
return (Alignment){2,0}; //2n+0
}
} /* namespace ns3 */

View File

@@ -35,6 +35,20 @@ namespace ns3
class Ipv6OptionHeader : public Header
{
public:
/**
* \brief represents the alignment requirements of an option header
*
* Represented as factor*n+offset (eg. 8n+2) See RFC 2460.
* No alignemt is represented as 1n+0.
*
*/
struct Alignment
{
uint8_t factor;
uint8_t offset;
};
/**
* \brief Get the type identificator.
* \return type identificator
@@ -107,6 +121,15 @@ class Ipv6OptionHeader : public Header
*/
virtual uint32_t Deserialize (Buffer::Iterator start);
/**
* \brief Get the Alignment requirement of this option header
* \return The required alignment
*
* Subclasses should only implement this method, if special alignemt is
* required. Default is no alignment (1n+0).
*/
virtual Alignment GetAlignment() const;
private:
/**
* \brief The type of the option.
@@ -118,6 +141,12 @@ class Ipv6OptionHeader : public Header
*/
uint8_t m_length;
/**
* \brief The anonymous data of this option
*/
Buffer m_data;
};
/**
@@ -197,8 +226,9 @@ class Ipv6OptionPadnHeader : public Ipv6OptionHeader
/**
* \brief Constructor.
* \param pad Number of bytes to pad (>=2)
*/
Ipv6OptionPadnHeader ();
Ipv6OptionPadnHeader (uint32_t pad = 2);
/**
* \brief Destructor.
@@ -299,6 +329,12 @@ class Ipv6OptionJumbogramHeader : public Ipv6OptionHeader
*/
virtual uint32_t Deserialize (Buffer::Iterator start);
/**
* \brief Get the Alignment requirement of this option header
* \return The required alignment
*/
virtual Alignment GetAlignment() const;
private:
/**
* \brief The data length.
@@ -372,6 +408,12 @@ class Ipv6OptionRouterAlertHeader : public Ipv6OptionHeader
*/
virtual uint32_t Deserialize (Buffer::Iterator start);
/**
* \brief Get the Alignment requirement of this option header
* \return The required alignment
*/
virtual Alignment GetAlignment() const;
private:
/**
* \brief The value.

View File

@@ -130,6 +130,7 @@ def build(bld):
'ipv4-l3-protocol.h',
'ipv6-l3-protocol.h',
'ipv6-extension-header.h',
'ipv6-option-header.h',
'arp-l3-protocol.h',
'udp-l4-protocol.h',
'tcp-l4-protocol.h',