sixlowpan: add context-based (stateful) IPHC compression

This commit is contained in:
Tommaso Pecorella
2021-01-17 16:54:52 +00:00
parent 673004edae
commit 217b28e6aa
12 changed files with 1836 additions and 346 deletions

View File

@@ -26,6 +26,7 @@ requirements (Note: not all ns-3 features are available on all systems):
New user-visible features
-------------------------
- (sixlowpan) Added support for stateful (i.e., context-based) RFC6282 compression.
Bugs fixed
----------

View File

@@ -23,17 +23,15 @@ standpoint, as it does extend it beyond the original scope by supporting also
other kinds of networks.
Other than that, the module strictly follows :rfc:`4944` and :rfc:`6282`, with the
following exceptions:
* HC2 encoding is not supported
* IPHC's SAC and DAC are not supported
The HC2 encoding is not supported, as it has been superseded by IPHC and NHC
exception that HC2 encoding is not supported, as it has been superseded by IPHC and NHC
compression type (\ :rfc:`6282`).
IPHC SAC and DAC are not yet supported, as they do require :rfc:`6775`
IPHC sateful (context-based) compression is supported but, since :rfc:`6775`
("Neighbor Discovery Optimization for IPv6 over Low-Power Wireless Personal Area Networks (6LoWPANs)")
for full compliance. It is planned to support them in the future.
is not yet implemented, it is necessary to add the context to the nodes manually.
This is possible though the ``SixLowPanHelper::AddContext`` function.
Mind that installing different contexts in different nodes will lead to decompression failures.
NetDevice
#########
@@ -117,8 +115,9 @@ Scope and Limitations
Contex-based compression
########################
The present implementation does not support context-based (stateful) compression.
This limitation will be removed in the future.
IPHC sateful (context-based) compression is supported but, since :rfc:`6775`
("Neighbor Discovery Optimization for IPv6 over Low-Power Wireless Personal Area Networks (6LoWPANs)")
is not yet implemented, it is necessary to add the context to the nodes manually.
6LoWPAM-ND
##########

View File

@@ -66,6 +66,66 @@ NetDeviceContainer SixLowPanHelper::Install (const NetDeviceContainer c)
return devs;
}
void SixLowPanHelper::AddContext (NetDeviceContainer c, uint8_t contextId, Ipv6Prefix context, Time validity)
{
NS_LOG_FUNCTION (this << +contextId << context << validity);
for (uint32_t i = 0; i < c.GetN (); ++i)
{
Ptr<NetDevice> device = c.Get (i);
Ptr<SixLowPanNetDevice> sixDevice = DynamicCast<SixLowPanNetDevice> (device);
if (sixDevice)
{
sixDevice->AddContext (contextId, context, true, validity);
}
}
}
void SixLowPanHelper::RenewContext (NetDeviceContainer c, uint8_t contextId, Time validity)
{
NS_LOG_FUNCTION (this << +contextId << validity);
for (uint32_t i = 0; i < c.GetN (); ++i)
{
Ptr<NetDevice> device = c.Get (i);
Ptr<SixLowPanNetDevice> sixDevice = DynamicCast<SixLowPanNetDevice> (device);
if (sixDevice)
{
sixDevice->RenewContext (contextId, validity);
}
}
}
void SixLowPanHelper::InvalidateContext (NetDeviceContainer c, uint8_t contextId)
{
NS_LOG_FUNCTION (this << +contextId);
for (uint32_t i = 0; i < c.GetN (); ++i)
{
Ptr<NetDevice> device = c.Get (i);
Ptr<SixLowPanNetDevice> sixDevice = DynamicCast<SixLowPanNetDevice> (device);
if (sixDevice)
{
sixDevice->InvalidateContext (contextId);
}
}
}
void SixLowPanHelper::RemoveContext (NetDeviceContainer c, uint8_t contextId)
{
NS_LOG_FUNCTION (this << +contextId);
for (uint32_t i = 0; i < c.GetN (); ++i)
{
Ptr<NetDevice> device = c.Get (i);
Ptr<SixLowPanNetDevice> sixDevice = DynamicCast<SixLowPanNetDevice> (device);
if (sixDevice)
{
sixDevice->RemoveContext (contextId);
}
}
}
int64_t SixLowPanHelper::AssignStreams (NetDeviceContainer c, int64_t stream)
{
int64_t currentStream = stream;

View File

@@ -80,16 +80,64 @@ public:
NetDeviceContainer Install (NetDeviceContainer c);
/**
* Assign a fixed random variable stream number to the random variables
* used by this model. Return the number of streams (possibly zero) that
* have been assigned. The Install() method should have previously been
* called by the user.
*
* \param [in] c NetDeviceContainer of the set of net devices for which the
* SixLowPanNetDevice should be modified to use a fixed stream.
* \param [in] stream First stream index to use.
* \return The number of stream indices assigned by this helper.
*/
* \brief Adds a compression Context to a set of NetDevices.
*
* This function installs one Compression Context on a set of NetDevices.
* The context is used only in IPHC compression and decompression.
*
* \param [in] c The NetDevice container.
* \param [in] id The context id (must be less than 16).
* \param [in] prefix The context prefix.
* \param [in] validity the context validity time (relative to the actual time).
*/
void AddContext (NetDeviceContainer c, uint8_t contextId, Ipv6Prefix context, Time validity);
/**
* \brief Renew a compression Context in a set of NetDevices.
*
* The context will have its lifetime extended and its validity for compression re-enabled.
*
* \param [in] c The NetDevice container.
* \param [in] id The context id (must be less than 16).
* \param [in] validity the context validity time (relative to the actual time).
*/
void RenewContext (NetDeviceContainer c, uint8_t contextId, Time validity);
/**
* \brief Invalidates a compression Context in a set of NetDevices.
*
* An invalid context is used only in IPHC decompression and not
* in IPHC compression.
*
* This is necessary to avoid that a context reaching its validity lifetime
* can not be used for decompression whie packets are traveling the network.
*
* \param [in] c The NetDevice container.
* \param [in] id The context id (must be less than 16).
*/
void InvalidateContext (NetDeviceContainer c, uint8_t contextId);
/**
* \brief Remove a compression Context in a set of NetDevices.
*
* The context is removed immediately from the contexts in the devices.
*
* \param [in] c The NetDevice container.
* \param [in] id The context id (must be less than 16).
*/
void RemoveContext (NetDeviceContainer c, uint8_t contextId);
/**
* Assign a fixed random variable stream number to the random variables
* used by this model. Return the number of streams (possibly zero) that
* have been assigned. The Install() method should have previously been
* called by the user.
*
* \param [in] c NetDeviceContainer of the set of net devices for which the
* SixLowPanNetDevice should be modified to use a fixed stream.
* \param [in] stream First stream index to use.
* \return The number of stream indices assigned by this helper.
*/
int64_t AssignStreams (NetDeviceContainer c, int64_t stream);
private:

View File

@@ -793,6 +793,7 @@ SixLowPanIphc::SixLowPanIphc ()
{
// 011x xxxx xxxx xxxx
m_baseFormat = 0x6000;
m_srcdstContextId = 0;
}
SixLowPanIphc::SixLowPanIphc (uint8_t dispatch)
@@ -800,6 +801,7 @@ SixLowPanIphc::SixLowPanIphc (uint8_t dispatch)
// 011x xxxx xxxx xxxx
m_baseFormat = dispatch;
m_baseFormat <<= 8;
m_srcdstContextId = 0;
}
TypeId SixLowPanIphc::GetTypeId (void)
@@ -818,7 +820,48 @@ TypeId SixLowPanIphc::GetInstanceTypeId (void) const
void SixLowPanIphc::Print (std::ostream & os) const
{
os << "Compression kind: " << +m_baseFormat;
switch ( GetTf () )
{
case TF_FULL:
os << "TF_FULL(" << +m_ecn << ", " << +m_dscp << ", " << m_flowLabel << ")";
break;
case TF_DSCP_ELIDED:
os << "TF_DSCP_ELIDED(" << +m_ecn << ", " << m_flowLabel << ")";
break;
case TF_FL_ELIDED:
os << "TF_FL_ELIDED(" << +m_ecn << ", " << +m_dscp << ")";
break;
default:
os << "TF_ELIDED";
break;
}
GetNh () ? os << " NH(1)" : os << " NH(0)";
switch ( GetHlim () )
{
case HLIM_INLINE:
os << " HLIM_INLINE(" << +m_hopLimit << ")";
break;
case HLIM_COMPR_1:
os << " HLIM_COMPR_1(1)";
break;
case HLIM_COMPR_64:
os << " HLIM_COMPR_64(64)";
break;
default:
os << " HLIM_COMPR_255(255)";
break;
}
GetCid () ? os << " CID(" << +m_srcdstContextId << ")" : os << " CID(0)";
GetSac () ? os << " SAC(1)" : os << " SAC(0)";
os << " SAM (" << GetSam () << ")";
GetM () ? os << " M(1)" : os << " M(0)";
GetDac () ? os << " DAC(1)" : os << " DAC(0)";
os << " DAM (" << GetDam () << ")";
}
uint32_t SixLowPanIphc::GetSerializedSize () const
@@ -983,22 +1026,17 @@ void SixLowPanIphc::Serialize (Buffer::Iterator start) const
// Source Address
switch (GetSam () )
{
uint8_t temp[16];
case HC_INLINE:
if ( GetSac () == false )
{
uint8_t temp[16];
m_srcAddress.Serialize (temp);
i.Write (temp, 16);
i.Write (m_srcInlinePart, 16);
}
break;
case HC_COMPR_64:
m_srcAddress.Serialize (temp);
i.Write (temp + 8, 8);
i.Write (m_srcInlinePart, 8);
break;
case HC_COMPR_16:
m_srcAddress.Serialize (temp);
i.Write (temp + 14, 2);
i.Write (m_srcInlinePart, 2);
break;
case HC_COMPR_0:
default:
@@ -1007,23 +1045,17 @@ void SixLowPanIphc::Serialize (Buffer::Iterator start) const
// Destination Address
if ( GetM () == false)
{
uint8_t temp[16];
// unicast
switch (GetDam () )
{
case HC_INLINE:
if ( GetDac () == false )
{
m_dstAddress.Serialize (temp);
i.Write (temp, 16);
}
i.Write (m_dstInlinePart, 16);
break;
case HC_COMPR_64:
m_dstAddress.Serialize (temp);
i.Write (temp + 8, 8);
i.Write (m_dstInlinePart, 8);
break;
case HC_COMPR_16:
m_dstAddress.Serialize (temp);
i.Write (temp + 14, 2);
i.Write (m_dstInlinePart, 2);
break;
case HC_COMPR_0:
default:
@@ -1032,45 +1064,22 @@ void SixLowPanIphc::Serialize (Buffer::Iterator start) const
}
else
{
// multicast
switch (GetDam () )
{
uint8_t temp[16];
case HC_INLINE:
if ( GetDac () == false )
{
m_dstAddress.Serialize (temp);
i.Write (temp, 16);
}
else
{
m_dstAddress.Serialize (temp);
i.Write (temp + 1, 2);
i.Write (temp + 12, 4);
}
i.Write (m_dstInlinePart, 16);
break;
case HC_COMPR_64:
if ( GetDac () == false )
{
m_dstAddress.Serialize (temp);
i.Write (temp + 1, 1);
i.Write (temp + 11, 5);
}
i.Write (m_dstInlinePart, 6);
break;
case HC_COMPR_16:
if ( GetDac () == false )
{
m_dstAddress.Serialize (temp);
i.Write (temp + 1, 1);
i.Write (temp + 13, 3);
}
i.Write (m_dstInlinePart, 4);
break;
case HC_COMPR_0:
default:
if ( GetDac () == false )
{
m_dstAddress.Serialize (temp);
i.WriteU8 (temp[15]);
}
i.Write (m_dstInlinePart, 1);
break;
default:
break;
}
}
@@ -1086,6 +1095,10 @@ uint32_t SixLowPanIphc::Deserialize (Buffer::Iterator start)
{
m_srcdstContextId = i.ReadU8 ();
}
else
{
m_srcdstContextId = 0;
}
// Traffic Class and Flow Label
switch ( GetTf () )
{
@@ -1142,68 +1155,41 @@ uint32_t SixLowPanIphc::Deserialize (Buffer::Iterator start)
}
// Source Address
memset (m_srcInlinePart, 0x00, sizeof (m_srcInlinePart));
switch (GetSam () )
{
uint8_t temp[16];
case HC_INLINE:
if ( GetSac () == false )
{
i.Read (temp, 16);
m_srcAddress = Ipv6Address::Deserialize (temp);
i.Read (m_srcInlinePart, 16);
}
break;
case HC_COMPR_64:
memset (temp, 0x00, sizeof (temp));
i.Read (temp + 8, 8);
temp[0] = 0xfe;
temp[1] = 0x80;
m_srcAddress = Ipv6Address::Deserialize (temp);
i.Read (m_srcInlinePart, 8);
break;
case HC_COMPR_16:
memset (temp, 0x00, sizeof (temp));
i.Read (temp + 14, 2);
temp[0] = 0xfe;
temp[1] = 0x80;
temp[11] = 0xff;
temp[12] = 0xfe;
m_srcAddress = Ipv6Address::Deserialize (temp);
i.Read (m_srcInlinePart, 2);
break;
case HC_COMPR_0:
default:
break;
}
if ( GetSac () == true )
{
PostProcessSac ();
}
// Destination Address
memset (m_dstInlinePart, 0x00, sizeof (m_dstInlinePart));
if ( GetM () == false)
{
uint8_t temp[16];
// unicast
switch (GetDam () )
{
case HC_INLINE:
if ( GetDac () == false )
{
i.Read (temp, 16);
m_dstAddress = Ipv6Address::Deserialize (temp);
}
i.Read (m_dstInlinePart, 16);
break;
case HC_COMPR_64:
memset (temp, 0x00, sizeof (temp));
i.Read (temp + 8, 8);
temp[0] = 0xfe;
temp[1] = 0x80;
m_dstAddress = Ipv6Address::Deserialize (temp);
i.Read (m_dstInlinePart, 8);
break;
case HC_COMPR_16:
memset (temp, 0x00, sizeof (temp));
i.Read (temp + 14, 2);
temp[0] = 0xfe;
temp[1] = 0x80;
temp[11] = 0xff;
temp[12] = 0xfe;
m_dstAddress = Ipv6Address::Deserialize (temp);
i.Read (m_dstInlinePart, 2);
break;
case HC_COMPR_0:
default:
@@ -1212,61 +1198,26 @@ uint32_t SixLowPanIphc::Deserialize (Buffer::Iterator start)
}
else
{
// multicast
switch (GetDam () )
{
uint8_t temp[16];
case HC_INLINE:
if ( GetDac () == false )
{
i.Read (temp, 16);
m_dstAddress = Ipv6Address::Deserialize (temp);
}
else
{
memset (temp, 0x00, sizeof (temp));
i.Read (temp + 1, 2);
i.Read (temp + 12, 4);
temp[0] = 0xff;
m_dstAddress = Ipv6Address::Deserialize (temp);
}
i.Read (m_dstInlinePart, 16);
break;
case HC_COMPR_64:
if ( GetDac () == false )
{
memset (temp, 0x00, sizeof (temp));
i.Read (temp + 1, 1);
i.Read (temp + 11, 5);
temp[0] = 0xff;
m_dstAddress = Ipv6Address::Deserialize (temp);
}
i.Read (m_dstInlinePart, 6);
break;
case HC_COMPR_16:
if ( GetDac () == false )
{
memset (temp, 0x00, sizeof (temp));
i.Read (temp + 1, 1);
i.Read (temp + 13, 3);
temp[0] = 0xff;
m_dstAddress = Ipv6Address::Deserialize (temp);
}
i.Read (m_dstInlinePart, 4);
break;
case HC_COMPR_0:
i.Read (m_dstInlinePart, 1);
break;
default:
if ( GetDac () == false )
{
memset (temp, 0x00, sizeof (temp));
temp[15] = i.ReadU8 ();
temp[0] = 0xff;
temp[1] = 0x02;
m_dstAddress = Ipv6Address::Deserialize (temp);
}
break;
}
}
if ( GetDac () == true )
{
PostProcessDac ();
}
return GetSerializedSize ();
}
@@ -1336,6 +1287,19 @@ SixLowPanIphc::HeaderCompression_e SixLowPanIphc::GetSam (void) const
return HeaderCompression_e ((m_baseFormat >> 4) & 0x3);
}
const uint8_t* SixLowPanIphc::GetSrcInlinePart (void) const
{
return m_srcInlinePart;
}
void SixLowPanIphc::SetSrcInlinePart (uint8_t srcInlinePart[16], uint8_t size)
{
NS_ASSERT_MSG (size <= 16, "Src inline part too large");
memcpy (m_srcInlinePart, srcInlinePart, size);
return;
}
void SixLowPanIphc::SetM (bool mField)
{
uint16_t field = mField;
@@ -1369,6 +1333,19 @@ SixLowPanIphc::HeaderCompression_e SixLowPanIphc::GetDam (void) const
return HeaderCompression_e (m_baseFormat & 0x3);
}
const uint8_t* SixLowPanIphc::GetDstInlinePart (void) const
{
return m_dstInlinePart;
}
void SixLowPanIphc::SetDstInlinePart (uint8_t dstInlinePart[16], uint8_t size)
{
NS_ASSERT_MSG (size <= 16, "Dst inline part too large");
memcpy (m_dstInlinePart, dstInlinePart, size);
return;
}
void SixLowPanIphc::SetSrcContextId (uint8_t srcContextId)
{
NS_ASSERT_MSG (srcContextId < 16, "Src Context ID too large");
@@ -1444,38 +1421,6 @@ uint8_t SixLowPanIphc::GetHopLimit (void) const
return m_hopLimit;
}
void SixLowPanIphc::SetSrcAddress (Ipv6Address srcAddress)
{
m_srcAddress = srcAddress;
}
Ipv6Address SixLowPanIphc::GetSrcAddress () const
{
return m_srcAddress;
}
void SixLowPanIphc::SetDstAddress (Ipv6Address dstAddress)
{
m_dstAddress = dstAddress;
}
Ipv6Address SixLowPanIphc::GetDstAddress () const
{
return m_dstAddress;
}
void SixLowPanIphc::PostProcessSac ()
{
NS_ABORT_MSG ("Unsupported; Context destination is not implemented");
return;
}
void SixLowPanIphc::PostProcessDac ()
{
NS_ABORT_MSG ("Unsupported; Context destination is not implemented");
return;
}
std::ostream & operator << (std::ostream & os, const SixLowPanIphc & h)
{
h.Print (os);

View File

@@ -768,6 +768,19 @@ public:
*/
HeaderCompression_e GetSam (void) const;
/**
* brief Set the source address inline part
* \param srcInlinePart The inline portion of the compressed source address (16 bytes)
* \param size The number of inline bytes
*/
void SetSrcInlinePart (uint8_t srcInlinePart[16], uint8_t size);
/**
* brief Get the source address inline part
* \return The inline portion of the compressed source address (16 bytes)
*/
const uint8_t* GetSrcInlinePart (void) const;
/**
* \brief Set the M (Multicast) compression.
* \param [in] mField True if destination is multicast.
@@ -805,6 +818,19 @@ public:
HeaderCompression_e GetDam (void) const;
/**
* brief Set the destination address inline part
* \param dstInlinePart The inline portion of the compressed destination address (16 bytes)
* \param size The number of inline bytes
*/
void SetDstInlinePart (uint8_t dstInlinePart[16], uint8_t size);
/**
* brief Get the destination address inline part
* \return The inline portion of the compressed destination address (16 bytes)
*/
const uint8_t* GetDstInlinePart (void) const;
/**
* \brief Set the SrcContextId.
* \param [in] srcContextId Valid values are [0:15].
*/
@@ -888,51 +914,16 @@ public:
*/
uint8_t GetHopLimit (void) const;
/**
* \brief Set the Source Address.
* \param [in] srcAddress The Source Address.
*/
void SetSrcAddress (Ipv6Address srcAddress);
/**
* \brief Get the Source Address.
* \return The Source Address.
*/
Ipv6Address GetSrcAddress () const;
/**
* \brief Set the Destination Address.
* \param [in] dstAddress The Destination Address.
*/
void SetDstAddress (Ipv6Address dstAddress);
/**
* \brief Get the Destination Address.
* \return The Destination Address.
*/
Ipv6Address GetDstAddress () const;
private:
uint16_t m_baseFormat; //!< Dispatch + encoding fields.
uint8_t m_srcdstContextId; //!< Src and Dst Context ID.
uint8_t m_ecn : 2; //!< ECN bits.
uint8_t m_dscp : 6; //!< DSCP bits.
uint32_t m_flowLabel : 20; //!< Flow Label bits.
uint8_t m_nextHeader; //!< Next header.
uint8_t m_hopLimit; //!< Hop Limit.
Ipv6Address m_srcAddress; //!< Src address.
Ipv6Address m_dstAddress; //!< Dst address.
/**
* \brief Post-process the Source address stateful compression
* \note Currently unsupported.
*/
void PostProcessSac ();
/**
* \brief Post-process the Destination address stateful compression.
* \note Currently unsupported.
*/
void PostProcessDac ();
uint16_t m_baseFormat; //!< Dispatch + encoding fields.
uint8_t m_srcdstContextId; //!< Src and Dst Context ID.
uint8_t m_ecn : 2; //!< ECN bits.
uint8_t m_dscp : 6; //!< DSCP bits.
uint32_t m_flowLabel : 20; //!< Flow Label bits.
uint8_t m_nextHeader; //!< Next header.
uint8_t m_hopLimit; //!< Hop Limit.
uint8_t m_srcInlinePart[16]; //!< source address inline part.
uint8_t m_dstInlinePart[16]; //!< destination address inline part.
};

View File

@@ -196,7 +196,6 @@ void SixLowPanNetDevice::ReceiveFromDevice (Ptr<NetDevice> incomingPort,
PacketType packetType)
{
NS_LOG_FUNCTION (this << incomingPort << packet << protocol << src << dst);
NS_LOG_DEBUG ("UID is " << packet->GetUid ());
uint8_t dispatchRawVal = 0;
SixLowPanDispatch::Dispatch_e dispatchVal;
@@ -349,8 +348,14 @@ void SixLowPanNetDevice::ReceiveFromDevice (Ptr<NetDevice> incomingPort,
m_dropTrace (DROP_DISALLOWED_COMPRESSION, copyPkt, m_node->GetObject<SixLowPanNetDevice> (), GetIfIndex ());
return;
}
DecompressLowPanIphc (copyPkt, realSrc, realDst);
isPktDecompressed = true;
if (DecompressLowPanIphc (copyPkt, realSrc, realDst))
{
m_dropTrace (DROP_SATETFUL_DECOMPRESSION_PROBLEM, copyPkt, m_node->GetObject<SixLowPanNetDevice> (), GetIfIndex ());
}
else
{
isPktDecompressed = true;
}
break;
default:
NS_LOG_DEBUG ("Unsupported 6LoWPAN encoding: dropping.");
@@ -711,6 +716,8 @@ SixLowPanNetDevice::CompressLowPanHc1 (Ptr<Packet> packet, Address const &src, A
SixLowPanHc1 hc1Header;
uint32_t size = 0;
NS_LOG_DEBUG ( "Original packet: " << *packet << " Size " << packet->GetSize () );
if ( packet->PeekHeader (ipHeader) != 0 )
{
packet->RemoveHeader (ipHeader);
@@ -922,7 +929,7 @@ SixLowPanNetDevice::DecompressLowPanHc1 (Ptr<Packet> packet, Address const &src,
packet->AddHeader (ipHeader);
NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () );
NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () );
}
uint32_t
@@ -934,6 +941,7 @@ SixLowPanNetDevice::CompressLowPanIphc (Ptr<Packet> packet, Address const &src,
SixLowPanIphc iphcHeader;
uint32_t size = 0;
NS_LOG_DEBUG ( "Original packet: " << *packet << " Size " << packet->GetSize () << " src: " << src << " dst: " << dst);
if ( packet->PeekHeader (ipHeader) != 0 )
{
@@ -1002,7 +1010,6 @@ SixLowPanNetDevice::CompressLowPanIphc (Ptr<Packet> packet, Address const &src,
iphcHeader.SetNextHeader (nextHeader);
}
// Set the HLIM field
if (ipHeader.GetHopLimit () == 1)
{
@@ -1023,44 +1030,101 @@ SixLowPanNetDevice::CompressLowPanIphc (Ptr<Packet> packet, Address const &src,
iphcHeader.SetHopLimit (ipHeader.GetHopLimit ());
}
// \todo Add the check of CID if there is context-based compression
// Set the CID field
// Set the CID + SAC + DAC fields to their default value
iphcHeader.SetCid (false);
// \todo Add the check of SAC if there is context-based compression
// Set the SAC field
iphcHeader.SetSac (false);
iphcHeader.SetDac (false);
uint8_t addressBuf[16];
uint8_t unicastAddrCheckerBuf[16];
Ipv6Address srcAddr = ipHeader.GetSourceAddress ();
srcAddr.GetBytes (addressBuf);
Ipv6Address checker = Ipv6Address ("fe80:0000:0000:0000:0000:00ff:fe00:1");
uint8_t unicastAddrCheckerBuf[16];
checker.GetBytes (unicastAddrCheckerBuf);
uint8_t addressBuf[16];
// \todo Add the check of SAC if there is context-based compression
// Set the Source Address
iphcHeader.SetSrcAddress (srcAddr);
// This is just to limit the scope of some variables.
if (true)
{
Ipv6Address srcAddr = ipHeader.GetSourceAddress ();
uint8_t srcContextId;
Ipv6Address mySrcAddr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress (src);
NS_LOG_LOGIC ("Checking source compression: " << mySrcAddr << " - " << srcAddr );
// The "::" address is compressed as a fake stateful compression.
if (srcAddr == Ipv6Address::GetAny ())
{
// No context information is needed.
iphcHeader.SetSam (SixLowPanIphc::HC_INLINE);
iphcHeader.SetSac (true);
}
// Check if the address can be compressed with stateful compression
else if ( FindUnicastCompressionContext (srcAddr, srcContextId) )
{
// We can do stateful compression.
NS_LOG_LOGIC ("Checking stateful source compression: " << srcAddr );
if ( mySrcAddr == srcAddr )
{
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_0);
}
else if (memcmp (addressBuf, unicastAddrCheckerBuf, 14) == 0)
{
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_16);
}
else if ( srcAddr.IsLinkLocal () )
{
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_64);
}
else
{
iphcHeader.SetSam (SixLowPanIphc::HC_INLINE);
iphcHeader.SetSac (true);
if (srcContextId != 0)
{
// the default context is zero, no need to explicit it if it's zero
iphcHeader.SetSrcContextId (srcContextId);
iphcHeader.SetCid (true);
}
// Note that a context might include parts of the EUI-64 (i.e., be as long as 128 bits).
if (Ipv6Address::MakeAutoconfiguredAddress (src, m_contextTable[srcContextId].contextPrefix) == srcAddr)
{
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_0);
}
else
{
Ipv6Address cleanedAddr = CleanPrefix (srcAddr, m_contextTable[srcContextId].contextPrefix);
uint8_t serializedCleanedAddress[16];
cleanedAddr.Serialize (serializedCleanedAddress);
if ( serializedCleanedAddress[8] == 0x00 && serializedCleanedAddress[9] == 0x00 &&
serializedCleanedAddress[10] == 0x00 && serializedCleanedAddress[11] == 0xff &&
serializedCleanedAddress[12] == 0xfe && serializedCleanedAddress[13] == 0x00 )
{
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_16);
iphcHeader.SetSrcInlinePart (serializedCleanedAddress+14, 2);
}
else
{
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_64);
iphcHeader.SetSrcInlinePart (serializedCleanedAddress+8, 8);
}
}
}
else
{
// We must do stateless compression.
NS_LOG_LOGIC ("Checking stateless source compression: " << srcAddr );
srcAddr.GetBytes (addressBuf);
uint8_t serializedSrcAddress[16];
srcAddr.Serialize (serializedSrcAddress);
if ( srcAddr == Ipv6Address::MakeAutoconfiguredLinkLocalAddress (src) )
{
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_0);
}
else if (memcmp (addressBuf, unicastAddrCheckerBuf, 14) == 0)
{
iphcHeader.SetSrcInlinePart (serializedSrcAddress+14, 2);
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_16);
}
else if ( srcAddr.IsLinkLocal () )
{
iphcHeader.SetSrcInlinePart (serializedSrcAddress+8, 8);
iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_64);
}
else
{
iphcHeader.SetSrcInlinePart (serializedSrcAddress, 16);
iphcHeader.SetSam (SixLowPanIphc::HC_INLINE);
}
}
}
// Set the M field
@@ -1073,69 +1137,156 @@ SixLowPanNetDevice::CompressLowPanIphc (Ptr<Packet> packet, Address const &src,
iphcHeader.SetM (false);
}
// \todo Add the check of DAC if there is context-based compression
// Set the DAC field
iphcHeader.SetDac (false);
Ipv6Address dstAddr = ipHeader.GetDestinationAddress ();
dstAddr.GetBytes (addressBuf);
// \todo Add the check of DAC if there is context-based compression
// Set the Destination Address
iphcHeader.SetDstAddress (dstAddr);
Ipv6Address myDstAddr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress (dst);
NS_LOG_LOGIC ("Checking destination compression: " << myDstAddr << " - " << dstAddr );
if ( !iphcHeader.GetM () )
// Unicast address
// This is just to limit the scope of some variables.
if (true)
{
if ( myDstAddr == dstAddr )
Ipv6Address dstAddr = ipHeader.GetDestinationAddress ();
dstAddr.GetBytes (addressBuf);
NS_LOG_LOGIC ("Checking destination compression: " << dstAddr );
uint8_t serializedDstAddress[16];
dstAddr.Serialize (serializedDstAddress);
if ( !iphcHeader.GetM () )
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_0);
}
else if (memcmp (addressBuf, unicastAddrCheckerBuf, 14) == 0)
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_16);
}
else if ( dstAddr.IsLinkLocal () )
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_64);
// Unicast address
uint8_t dstContextId;
if ( FindUnicastCompressionContext (dstAddr, dstContextId) )
{
// We can do stateful compression.
NS_LOG_LOGIC ("Checking stateful destination compression: " << dstAddr );
iphcHeader.SetDac (true);
if (dstContextId != 0)
{
// the default context is zero, no need to explicit it if it's zero
iphcHeader.SetDstContextId (dstContextId);
iphcHeader.SetCid (true);
}
// Note that a context might include parts of the EUI-64 (i.e., be as long as 128 bits).
if (Ipv6Address::MakeAutoconfiguredAddress (dst, m_contextTable[dstContextId].contextPrefix) == dstAddr)
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_0);
}
else
{
Ipv6Address cleanedAddr = CleanPrefix (dstAddr, m_contextTable[dstContextId].contextPrefix);
uint8_t serializedCleanedAddress[16];
cleanedAddr.Serialize (serializedCleanedAddress);
if ( serializedCleanedAddress[8] == 0x00 && serializedCleanedAddress[9] == 0x00 &&
serializedCleanedAddress[10] == 0x00 && serializedCleanedAddress[11] == 0xff &&
serializedCleanedAddress[12] == 0xfe && serializedCleanedAddress[13] == 0x00 )
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_16);
iphcHeader.SetDstInlinePart (serializedCleanedAddress+14, 2);
}
else
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_64);
iphcHeader.SetDstInlinePart (serializedCleanedAddress+8, 8);
}
}
}
else
{
NS_LOG_LOGIC ("Checking stateless destination compression: " << dstAddr );
if ( dstAddr == Ipv6Address::MakeAutoconfiguredLinkLocalAddress (dst) )
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_0);
}
else if (memcmp (addressBuf, unicastAddrCheckerBuf, 14) == 0)
{
iphcHeader.SetDstInlinePart (serializedDstAddress+14, 2);
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_16);
}
else if ( dstAddr.IsLinkLocal () )
{
iphcHeader.SetDstInlinePart (serializedDstAddress+8, 8);
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_64);
}
else
{
iphcHeader.SetDstInlinePart (serializedDstAddress, 16);
iphcHeader.SetDam (SixLowPanIphc::HC_INLINE);
}
}
}
else
{
iphcHeader.SetDam (SixLowPanIphc::HC_INLINE);
}
}
else
{
// Multicast address
uint8_t multicastAddrCheckerBuf[16];
Ipv6Address multicastCheckAddress = Ipv6Address ("ff02::1");
multicastCheckAddress.GetBytes (multicastAddrCheckerBuf);
// Multicast address
// The address takes the form ff02::00XX.
if ( memcmp (addressBuf, multicastAddrCheckerBuf, 15) == 0 )
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_0);
}
// The address takes the form ffXX::00XX:XXXX.
// ffXX:0000:0000:0000:0000:0000:00XX:XXXX.
else if ( (addressBuf[0] == multicastAddrCheckerBuf[0])
&& (memcmp (addressBuf + 2, multicastAddrCheckerBuf + 2, 11) == 0) )
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_16);
}
// The address takes the form ffXX::00XX:XXXX:XXXX.
// ffXX:0000:0000:0000:0000:00XX:XXXX:XXXX.
else if ( (addressBuf[0] == multicastAddrCheckerBuf[0])
&& (memcmp (addressBuf + 2, multicastAddrCheckerBuf + 2, 9) == 0) )
{
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_64);
}
else
{
iphcHeader.SetDam (SixLowPanIphc::HC_INLINE);
uint8_t dstContextId;
if ( FindMulticastCompressionContext (dstAddr, dstContextId) )
{
// Stateful compression (only one possible case)
// ffXX:XXLL:PPPP:PPPP:PPPP:PPPP:XXXX:XXXX
uint8_t dstInlinePart[6] = {};
dstInlinePart[0] = serializedDstAddress[1];
dstInlinePart[1] = serializedDstAddress[2];
dstInlinePart[2] = serializedDstAddress[12];
dstInlinePart[3] = serializedDstAddress[13];
dstInlinePart[4] = serializedDstAddress[14];
dstInlinePart[5] = serializedDstAddress[15];
iphcHeader.SetDac (true);
if (dstContextId != 0)
{
// the default context is zero, no need to explicit it if it's zero
iphcHeader.SetDstContextId (dstContextId);
iphcHeader.SetCid (true);
}
iphcHeader.SetDstInlinePart (dstInlinePart, 6);
iphcHeader.SetDam (SixLowPanIphc::HC_INLINE);
}
else
{
// Stateless compression
uint8_t multicastAddrCheckerBuf[16];
Ipv6Address multicastCheckAddress = Ipv6Address ("ff02::1");
multicastCheckAddress.GetBytes (multicastAddrCheckerBuf);
// The address takes the form ff02::00XX.
if ( memcmp (addressBuf, multicastAddrCheckerBuf, 15) == 0 )
{
iphcHeader.SetDstInlinePart (serializedDstAddress+15, 1);
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_0);
}
// The address takes the form ffXX::00XX:XXXX.
// ffXX:0000:0000:0000:0000:0000:00XX:XXXX.
else if ( (addressBuf[0] == multicastAddrCheckerBuf[0])
&& (memcmp (addressBuf + 2, multicastAddrCheckerBuf + 2, 11) == 0) )
{
uint8_t dstInlinePart[4] = {};
memcpy (dstInlinePart, serializedDstAddress+1, 1);
memcpy (dstInlinePart+1, serializedDstAddress+13, 3);
iphcHeader.SetDstInlinePart (dstInlinePart, 4);
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_16);
}
// The address takes the form ffXX::00XX:XXXX:XXXX.
// ffXX:0000:0000:0000:0000:00XX:XXXX:XXXX.
else if ( (addressBuf[0] == multicastAddrCheckerBuf[0])
&& (memcmp (addressBuf + 2, multicastAddrCheckerBuf + 2, 9) == 0) )
{
uint8_t dstInlinePart[6] = {};
memcpy (dstInlinePart, serializedDstAddress+1, 1);
memcpy (dstInlinePart+1, serializedDstAddress+11, 5);
iphcHeader.SetDstInlinePart (dstInlinePart, 6);
iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_64);
}
else
{
iphcHeader.SetDstInlinePart (serializedDstAddress, 16);
iphcHeader.SetDam (SixLowPanIphc::HC_INLINE);
}
}
}
}
@@ -1148,7 +1299,6 @@ SixLowPanNetDevice::CompressLowPanIphc (Ptr<Packet> packet, Address const &src,
return size;
}
return 0;
}
@@ -1173,7 +1323,7 @@ SixLowPanNetDevice::CanCompressLowPanNhc (uint8_t nextHeader)
return ret;
}
void
bool
SixLowPanNetDevice::DecompressLowPanIphc (Ptr<Packet> packet, Address const &src, Address const &dst)
{
NS_LOG_FUNCTION (this << *packet << src << dst);
@@ -1191,29 +1341,99 @@ SixLowPanNetDevice::DecompressLowPanIphc (Ptr<Packet> packet, Address const &src
// Source address
if ( encoding.GetSac () )
{
// Source address compression uses stateful, context-based compression.
if ( encoding.GetSam () == SixLowPanIphc::HC_INLINE )
{
ipHeader.SetSourceAddress ( Ipv6Address::GetAny () );
}
else
{
NS_ABORT_MSG ("SAC option not yet implemented");
uint8_t contextId = encoding.GetSrcContextId ();
if (m_contextTable.find (contextId) == m_contextTable.end ())
{
NS_LOG_LOGIC ("Unknown Source compression context (" << +contextId << "), dropping packet");
return true;
}
if (m_contextTable[contextId].validLifetime < Simulator::Now ())
{
NS_LOG_LOGIC ("Expired Source compression context (" << +contextId << "), dropping packet");
return true;
}
uint8_t contexPrefix[16];
m_contextTable[contextId].contextPrefix.GetBytes(contexPrefix);
uint8_t contextLength = m_contextTable[contextId].contextPrefix.GetPrefixLength ();
uint8_t srcAddress[16] = { };
if ( encoding.GetSam () == SixLowPanIphc::HC_COMPR_64 )
{
memcpy (srcAddress +8, encoding.GetSrcInlinePart (), 8);
}
else if ( encoding.GetSam () == SixLowPanIphc::HC_COMPR_16 )
{
srcAddress[11] = 0xff;
srcAddress[12] = 0xfe;
memcpy (srcAddress +14, encoding.GetSrcInlinePart (), 2);
}
else // SixLowPanIphc::HC_COMPR_0
{
Ipv6Address::MakeAutoconfiguredLinkLocalAddress (src).GetBytes (srcAddress);
}
uint8_t bytesToCopy = contextLength / 8;
uint8_t bitsToCopy = contextLength % 8;
// Do not combine the prefix - we want to override the bytes.
for (uint8_t i=0; i<bytesToCopy; i++)
{
srcAddress[i] = contexPrefix[i];
}
if (bitsToCopy)
{
uint8_t addressBitMask = (1<<(8-bitsToCopy))-1;
uint8_t prefixBitMask = ~addressBitMask;
srcAddress[bytesToCopy] = (contexPrefix[bytesToCopy] & prefixBitMask) | (srcAddress[bytesToCopy] & addressBitMask);
}
ipHeader.SetSourceAddress ( Ipv6Address::Deserialize (srcAddress) );
}
}
else
{
if ( encoding.GetSam () == SixLowPanIphc::HC_COMPR_0 )
// Source address compression uses stateless compression.
if ( encoding.GetSam () == SixLowPanIphc::HC_INLINE )
{
uint8_t srcAddress[16] = { };
memcpy (srcAddress, encoding.GetSrcInlinePart (), 16);
ipHeader.SetSourceAddress ( Ipv6Address::Deserialize (srcAddress) );
}
else if ( encoding.GetSam () == SixLowPanIphc::HC_COMPR_64 )
{
uint8_t srcAddress[16] = { };
memcpy (srcAddress +8, encoding.GetSrcInlinePart (), 8);
srcAddress[0] = 0xfe;
srcAddress[1] = 0x80;
ipHeader.SetSourceAddress ( Ipv6Address::Deserialize (srcAddress) );
}
else if ( encoding.GetSam () == SixLowPanIphc::HC_COMPR_16 )
{
uint8_t srcAddress[16] = { };
memcpy (srcAddress +14, encoding.GetSrcInlinePart (), 2);
srcAddress[0] = 0xfe;
srcAddress[1] = 0x80;
srcAddress[11] = 0xff;
srcAddress[12] = 0xfe;
ipHeader.SetSourceAddress ( Ipv6Address::Deserialize (srcAddress) );
}
else // SixLowPanIphc::HC_COMPR_0
{
ipHeader.SetSourceAddress (Ipv6Address::MakeAutoconfiguredLinkLocalAddress (src));
}
else
{
ipHeader.SetSourceAddress ( encoding.GetSrcAddress () );
}
}
// Destination address
if ( encoding.GetDac () )
{
// Destination address compression uses stateful, context-based compression.
if ((encoding.GetDam () == SixLowPanIphc::HC_INLINE && !encoding.GetM ())
|| (encoding.GetDam () == SixLowPanIphc::HC_COMPR_64 && encoding.GetM ())
|| (encoding.GetDam () == SixLowPanIphc::HC_COMPR_16 && encoding.GetM ())
@@ -1221,20 +1441,139 @@ SixLowPanNetDevice::DecompressLowPanIphc (Ptr<Packet> packet, Address const &src
{
NS_ABORT_MSG ("Reserved code found");
}
uint8_t contextId = encoding.GetDstContextId ();
if (m_contextTable.find (contextId) == m_contextTable.end ())
{
NS_LOG_LOGIC ("Unknown Destination compression context (" << +contextId << "), dropping packet");
return true;
}
if (m_contextTable[contextId].validLifetime < Simulator::Now ())
{
NS_LOG_LOGIC ("Expired Destination compression context (" << +contextId << "), dropping packet");
return true;
}
uint8_t contexPrefix[16];
m_contextTable[contextId].contextPrefix.GetBytes(contexPrefix);
uint8_t contextLength = m_contextTable[contextId].contextPrefix.GetPrefixLength ();
if (encoding.GetM () == false)
{
// unicast
uint8_t dstAddress[16] = { };
if ( encoding.GetDam () == SixLowPanIphc::HC_COMPR_64 )
{
memcpy (dstAddress +8, encoding.GetDstInlinePart (), 8);
}
else if ( encoding.GetDam () == SixLowPanIphc::HC_COMPR_16 )
{
dstAddress[11] = 0xff;
dstAddress[12] = 0xfe;
memcpy (dstAddress +14, encoding.GetDstInlinePart (), 2);
}
else // SixLowPanIphc::HC_COMPR_0
{
Ipv6Address::MakeAutoconfiguredLinkLocalAddress (dst).GetBytes (dstAddress);
}
uint8_t bytesToCopy = m_contextTable[contextId].contextPrefix.GetPrefixLength () / 8;
uint8_t bitsToCopy = contextLength % 8;
// Do not combine the prefix - we want to override the bytes.
for (uint8_t i=0; i<bytesToCopy; i++)
{
dstAddress[i] = contexPrefix[i];
}
if (bitsToCopy)
{
uint8_t addressBitMask = (1<<(8-bitsToCopy))-1;
uint8_t prefixBitMask = ~addressBitMask;
dstAddress[bytesToCopy] = (contexPrefix[bytesToCopy] & prefixBitMask) | (dstAddress[bytesToCopy] & addressBitMask);
}
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
else
{
NS_ABORT_MSG ("DAC option not yet implemented");
// multicast
// Just one possibility: ffXX:XXLL:PPPP:PPPP:PPPP:PPPP:XXXX:XXXX
uint8_t dstAddress[16] = { };
dstAddress[0] = 0xff;
memcpy (dstAddress +1, encoding.GetDstInlinePart (), 2);
dstAddress[3] = contextLength;
memcpy (dstAddress +4, contexPrefix, 8);
memcpy (dstAddress +12, encoding.GetDstInlinePart ()+2, 4);
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
}
else
{
if ( !encoding.GetM () && encoding.GetDam () == SixLowPanIphc::HC_COMPR_0 )
// Destination address compression uses stateless compression.
if (encoding.GetM () == false)
{
ipHeader.SetDestinationAddress (Ipv6Address::MakeAutoconfiguredLinkLocalAddress (dst));
}
// unicast
if ( encoding.GetDam () == SixLowPanIphc::HC_INLINE )
{
uint8_t dstAddress[16] = { };
memcpy (dstAddress, encoding.GetDstInlinePart (), 16);
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
else if ( encoding.GetDam () == SixLowPanIphc::HC_COMPR_64 )
{
uint8_t dstAddress[16] = { };
memcpy (dstAddress +8, encoding.GetDstInlinePart (), 8);
dstAddress[0] = 0xfe;
dstAddress[1] = 0x80;
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
else if ( encoding.GetDam () == SixLowPanIphc::HC_COMPR_16 )
{
uint8_t dstAddress[16] = { };
memcpy (dstAddress +14, encoding.GetDstInlinePart (), 2);
dstAddress[0] = 0xfe;
dstAddress[1] = 0x80;
dstAddress[11] = 0xff;
dstAddress[12] = 0xfe;
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
else // SixLowPanIphc::HC_COMPR_0
{
ipHeader.SetDestinationAddress (Ipv6Address::MakeAutoconfiguredLinkLocalAddress (dst));
}
}
else
{
ipHeader.SetDestinationAddress ( encoding.GetDstAddress () );
// multicast
if ( encoding.GetDam () == SixLowPanIphc::HC_INLINE )
{
uint8_t dstAddress[16] = { };
memcpy (dstAddress, encoding.GetDstInlinePart (), 16);
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
else if ( encoding.GetDam () == SixLowPanIphc::HC_COMPR_64 )
{
uint8_t dstAddress[16] = { };
dstAddress[0] = 0xff;
memcpy (dstAddress +1, encoding.GetDstInlinePart (), 1);
memcpy (dstAddress +11, encoding.GetDstInlinePart ()+1, 5);
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
else if ( encoding.GetDam () == SixLowPanIphc::HC_COMPR_16 )
{
uint8_t dstAddress[16] = { };
dstAddress[0] = 0xff;
memcpy (dstAddress +1, encoding.GetDstInlinePart (), 1);
memcpy (dstAddress +13, encoding.GetDstInlinePart ()+1, 3);
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
else // SixLowPanIphc::HC_COMPR_0
{
uint8_t dstAddress[16] = { };
dstAddress[0] = 0xff;
dstAddress[1] = 0x02;
memcpy (dstAddress+15, encoding.GetDstInlinePart (), 1);
ipHeader.SetDestinationAddress ( Ipv6Address::Deserialize (dstAddress) );
}
}
}
@@ -1282,7 +1621,15 @@ SixLowPanNetDevice::DecompressLowPanIphc (Ptr<Packet> packet, Address const &src
}
else
{
ipHeader.SetNextHeader (DecompressLowPanNhc (packet, src, dst, ipHeader.GetSourceAddress (), ipHeader.GetDestinationAddress ()));
std::pair <uint8_t, bool> retval = DecompressLowPanNhc (packet, src, dst, ipHeader.GetSourceAddress (), ipHeader.GetDestinationAddress ());
if ( retval.second == true )
{
return true;
}
else
{
ipHeader.SetNextHeader (retval.first);
}
}
}
else
@@ -1294,8 +1641,9 @@ SixLowPanNetDevice::DecompressLowPanIphc (Ptr<Packet> packet, Address const &src
packet->AddHeader (ipHeader);
NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () );
NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () );
return false;
}
uint32_t
@@ -1557,7 +1905,7 @@ SixLowPanNetDevice::CompressLowPanNhc (Ptr<Packet> packet, uint8_t headerType, A
return size;
}
uint8_t
std::pair <uint8_t, bool>
SixLowPanNetDevice::DecompressLowPanNhc (Ptr<Packet> packet, Address const &src, Address const &dst, Ipv6Address srcAddress, Ipv6Address dstAddress)
{
NS_LOG_FUNCTION (this << *packet);
@@ -1602,7 +1950,7 @@ SixLowPanNetDevice::DecompressLowPanNhc (Ptr<Packet> packet, Address const &src,
}
else
{
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress);
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress).first;
}
}
else
@@ -1654,7 +2002,7 @@ SixLowPanNetDevice::DecompressLowPanNhc (Ptr<Packet> packet, Address const &src,
}
else
{
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress);
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress).first;
}
}
else
@@ -1686,7 +2034,7 @@ SixLowPanNetDevice::DecompressLowPanNhc (Ptr<Packet> packet, Address const &src,
}
else
{
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress);
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress).first;
}
}
else
@@ -1720,7 +2068,7 @@ SixLowPanNetDevice::DecompressLowPanNhc (Ptr<Packet> packet, Address const &src,
}
else
{
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress);
blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress).first;
}
}
else
@@ -1759,7 +2107,11 @@ SixLowPanNetDevice::DecompressLowPanNhc (Ptr<Packet> packet, Address const &src,
break;
case SixLowPanNhcExtension::EID_IPv6_H:
actualHeaderType = Ipv6Header::IPV6_IPV6;
DecompressLowPanIphc (packet, src, dst);
if (DecompressLowPanIphc (packet, src, dst))
{
m_dropTrace (DROP_SATETFUL_DECOMPRESSION_PROBLEM, packet, m_node->GetObject<SixLowPanNetDevice> (), GetIfIndex ());
return std::pair<uint8_t, bool> (0, true);
}
break;
default:
NS_ABORT_MSG ("Trying to decode unknown Extension Header");
@@ -1767,7 +2119,7 @@ SixLowPanNetDevice::DecompressLowPanNhc (Ptr<Packet> packet, Address const &src,
}
NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () );
return actualHeaderType;
return std::pair<uint8_t, bool> (actualHeaderType, false);
}
uint32_t
@@ -2013,7 +2365,11 @@ bool SixLowPanNetDevice::ProcessFragment (Ptr<Packet>& packet, Address const &sr
DecompressLowPanHc1 (p, src, dst);
break;
case SixLowPanDispatch::LOWPAN_IPHC:
DecompressLowPanIphc (p, src, dst);
if (DecompressLowPanIphc (p, src, dst))
{
m_dropTrace (DROP_SATETFUL_DECOMPRESSION_PROBLEM, p, m_node->GetObject<SixLowPanNetDevice> (), GetIfIndex ());
return false;
}
break;
default:
NS_FATAL_ERROR ("Unsupported 6LoWPAN encoding, exiting.");
@@ -2294,6 +2650,205 @@ void SixLowPanNetDevice::HandleTimeout (void)
return;
}
void SixLowPanNetDevice::AddContext (uint8_t contextId, Ipv6Prefix contextPrefix, bool compressionAllowed, Time validLifetime)
{
NS_LOG_FUNCTION (this << +contextId << Ipv6Address::GetOnes ().CombinePrefix (contextPrefix) << contextPrefix << compressionAllowed << validLifetime.As (Time::S));
if (contextId > 15)
{
NS_LOG_LOGIC ("Invalid context ID (" << +contextId << "), ignoring");
return;
}
if (validLifetime == Time(0))
{
NS_LOG_LOGIC ("Context (" << +contextId << "), removed (validity time is zero)");
m_contextTable.erase (contextId);
return;
}
m_contextTable[contextId].contextPrefix = contextPrefix;
m_contextTable[contextId].compressionAllowed = compressionAllowed;
m_contextTable[contextId].validLifetime = Simulator::Now () + validLifetime;
return;
}
bool SixLowPanNetDevice::GetContext (uint8_t contextId, Ipv6Prefix& contextPrefix, bool& compressionAllowed, Time& validLifetime)
{
NS_LOG_FUNCTION (this << +contextId);
if (contextId > 15)
{
NS_LOG_LOGIC ("Invalid context ID (" << +contextId << "), ignoring");
return false;
}
if (m_contextTable.find (contextId) == m_contextTable.end ())
{
NS_LOG_LOGIC ("Context not found (" << +contextId << "), ignoring");
return false;
}
contextPrefix = m_contextTable[contextId].contextPrefix;
compressionAllowed = m_contextTable[contextId].compressionAllowed;
validLifetime = m_contextTable[contextId].validLifetime;
return true;
}
void SixLowPanNetDevice::RenewContext (uint8_t contextId, Time validLifetime)
{
NS_LOG_FUNCTION (this << +contextId << validLifetime.As (Time::S));
if (contextId > 15)
{
NS_LOG_LOGIC ("Invalid context ID (" << +contextId << "), ignoring");
return;
}
if (m_contextTable.find (contextId) == m_contextTable.end ())
{
NS_LOG_LOGIC ("Context not found (" << +contextId << "), ignoring");
return;
}
m_contextTable[contextId].compressionAllowed = true;
m_contextTable[contextId].validLifetime = Simulator::Now () + validLifetime;
return;
}
void SixLowPanNetDevice::InvalidateContext (uint8_t contextId)
{
NS_LOG_FUNCTION (this << +contextId);
if (contextId > 15)
{
NS_LOG_LOGIC ("Invalid context ID (" << +contextId << "), ignoring");
return;
}
if (m_contextTable.find (contextId) == m_contextTable.end ())
{
NS_LOG_LOGIC ("Context not found (" << +contextId << "), ignoring");
return;
}
m_contextTable[contextId].compressionAllowed = false;
return;
}
void SixLowPanNetDevice::RemoveContext (uint8_t contextId)
{
NS_LOG_FUNCTION (this << +contextId);
if (contextId > 15)
{
NS_LOG_LOGIC ("Invalid context ID (" << +contextId << "), ignoring");
return;
}
if (m_contextTable.find (contextId) == m_contextTable.end ())
{
NS_LOG_LOGIC ("Context not found (" << +contextId << "), ignoring");
return;
}
m_contextTable.erase (contextId);
return;
}
bool SixLowPanNetDevice::FindUnicastCompressionContext (Ipv6Address address, uint8_t& contextId)
{
NS_LOG_FUNCTION (this << address);
for (const auto& iter: m_contextTable)
{
ContextEntry context = iter.second;
if ( (context.compressionAllowed == true) && (context.validLifetime > Simulator::Now ()) )
{
if (address.HasPrefix (context.contextPrefix))
{
NS_LOG_LOGIC ("Fount context " << +contextId << " " <<
Ipv6Address::GetOnes ().CombinePrefix (context.contextPrefix) << context.contextPrefix << " matching");
contextId = iter.first;
return true;
}
}
}
return false;
}
bool SixLowPanNetDevice::FindMulticastCompressionContext (Ipv6Address address, uint8_t& contextId)
{
NS_LOG_FUNCTION (this << address);
// The only allowed context-based compressed multicast address is in the form
// ffXX:XXLL:PPPP:PPPP:PPPP:PPPP:XXXX:XXXX
for (const auto& iter: m_contextTable)
{
ContextEntry context = iter.second;
if ( (context.compressionAllowed == true) && (context.validLifetime > Simulator::Now ()) )
{
uint8_t contextLength = context.contextPrefix.GetPrefixLength ();
if (contextLength <= 64) // only 64-bit prefixes or less are allowed.
{
uint8_t contextBytes[16];
uint8_t addressBytes[16];
context.contextPrefix.GetBytes (contextBytes);
address.GetBytes (addressBytes);
if (addressBytes[3] == contextLength &&
addressBytes[4] == contextBytes[0] &&
addressBytes[5] == contextBytes[1] &&
addressBytes[6] == contextBytes[2] &&
addressBytes[7] == contextBytes[3] &&
addressBytes[8] == contextBytes[4] &&
addressBytes[9] == contextBytes[5] &&
addressBytes[10] == contextBytes[6] &&
addressBytes[11] == contextBytes[7])
{
NS_LOG_LOGIC ("Fount context " << +contextId << " " <<
Ipv6Address::GetOnes ().CombinePrefix (context.contextPrefix) << context.contextPrefix << " matching");
contextId = iter.first;
return true;
}
}
}
}
return false;
}
Ipv6Address SixLowPanNetDevice::CleanPrefix (Ipv6Address address, Ipv6Prefix prefix)
{
uint8_t addressBytes[16];
address.GetBytes (addressBytes);
uint8_t prefixLength = prefix.GetPrefixLength ();
uint8_t bytesToClean = prefixLength / 8;
uint8_t bitsToClean = prefixLength % 8;
for (uint8_t i=0; i<bytesToClean; i++)
{
addressBytes[i] = 0;
}
if (bitsToClean)
{
uint8_t cleanupMask = (1<<bitsToClean)-1;
addressBytes[bytesToClean] &= cleanupMask;
}
Ipv6Address cleanedAddress = Ipv6Address::Deserialize (addressBytes);
return cleanedAddress;
}
}
// namespace ns3

View File

@@ -70,10 +70,11 @@ public:
*/
enum DropReason
{
DROP_FRAGMENT_TIMEOUT = 1, /**< Fragment timeout exceeded */
DROP_FRAGMENT_BUFFER_FULL, /**< Fragment buffer size exceeded */
DROP_UNKNOWN_EXTENSION, /**< Unsupported compression kind */
DROP_DISALLOWED_COMPRESSION /**< HC1 while in IPHC mode or viceversa */
DROP_FRAGMENT_TIMEOUT = 1, /**< Fragment timeout exceeded */
DROP_FRAGMENT_BUFFER_FULL, /**< Fragment buffer size exceeded */
DROP_UNKNOWN_EXTENSION, /**< Unsupported compression kind */
DROP_DISALLOWED_COMPRESSION, /**< HC1 while in IPHC mode or viceversa */
DROP_SATETFUL_DECOMPRESSION_PROBLEM, /**< Decompression failed due to missing or expired context */
};
/**
@@ -162,7 +163,7 @@ public:
uint32_t ifindex);
/**
* TracedCallback signature for
* TracedCallback signature fo packet drop events
*
* \param [in] reason The reason for the drop.
* \param [in] packet The packet.
@@ -177,6 +178,58 @@ public:
Ptr<SixLowPanNetDevice> sixNetDevice,
uint32_t ifindex);
/**
* Add, remove, or update a context used in IPHC stateful compression.
*
* A context with a zero validLifetime will be immediately removed.
*
* \param [in] contextId context id (most be between 0 and 15 included).
* \param [in] contextPrefix context prefix to be used in compression/decompression.
* \param [in] compressionAllowed compression and decompression allowed (true), decompression only (false).
* \param [in] validLifetime validity time (relative to the actual time).
*
*/
void AddContext (uint8_t contextId, Ipv6Prefix contextPrefix, bool compressionAllowed, Time validLifetime);
/**
* Get a context used in IPHC stateful compression.
*
* \param [in] contextId context id (most be between 0 and 15 included).
* \param [out] contextPrefix context prefix to be used in compression/decompression.
* \param [out] compressionAllowed compression and decompression allowed (true), decompression only (false).
* \param [out] validLifetime validity time (relative to the actual time).
*
* \return false if the context has not been found.
*
*/
bool GetContext (uint8_t contextId, Ipv6Prefix& contextPrefix, bool& compressionAllowed, Time& validLifetime);
/**
* Renew a context used in IPHC stateful compression.
*
* The context will have its lifetime extended and its validity for compression re-enabled.
*
* \param [in] contextId context id (most be between 0 and 15 included).
* \param [in] validLifetime validity time (relative to the actual time).
*/
void RenewContext (uint8_t contextId, Time validLifetime);
/**
* Invalidate a context used in IPHC stateful compression.
*
* An invalid context will not be used for compression but it will be used for decompression.
*
* \param [in] contextId context id (most be between 0 and 15 included).
*/
void InvalidateContext (uint8_t contextId);
/**
* Remove a context used in IPHC stateful compression.
*
* \param [in] contextId context id (most be between 0 and 15 included).
*/
void RemoveContext (uint8_t contextId);
protected:
virtual void DoDispose (void);
@@ -312,8 +365,9 @@ private:
* \param [in] packet The packet to be compressed.
* \param [in] src The MAC source address.
* \param [in] dst The MAC destination address.
* \return true if the packet can not be decompressed due to wrong context informations.
*/
void DecompressLowPanIphc (Ptr<Packet> packet, Address const &src, Address const &dst);
bool DecompressLowPanIphc (Ptr<Packet> packet, Address const &src, Address const &dst);
/**
* \brief Compress the headers according to NHC compression.
@@ -332,9 +386,9 @@ private:
* \param [in] dst The MAC destination address.
* \param [in] srcAddress The IPv6 source address.
* \param [in] dstAddress The IPv6 destination address.
* \return The decompressed header type.
* \return A std::pair containing the decompressed header type and a flag - true if the packet can not be decompressed due to wrong context informations.
*/
uint8_t DecompressLowPanNhc (Ptr<Packet> packet, Address const &src, Address const &dst, Ipv6Address srcAddress, Ipv6Address dstAddress);
std::pair<uint8_t, bool> DecompressLowPanNhc (Ptr<Packet> packet, Address const &src, Address const &dst, Ipv6Address srcAddress, Ipv6Address dstAddress);
/**
* \brief Compress the headers according to NHC compression.
@@ -549,6 +603,48 @@ private:
uint32_t m_compressionThreshold; //!< Minimum L2 payload size.
Ptr<UniformRandomVariable> m_rng; //!< Rng for the fragments tag.
/**
* Structure holding the informations for a context (used in compression and decompression)
*/
struct ContextEntry
{
Ipv6Prefix contextPrefix; //!< context prefix to be used in compression/decompression
bool compressionAllowed; //!< compression and decompression allowed (true), decompression only (false)
Time validLifetime; //!< validity period
};
std::map<uint8_t, ContextEntry> m_contextTable; //!< Table of the contexts used in compression/decompression
/**
* \brief Finds if the given unicast address matches a context for compression
*
* \param[in] address the address to check
* \param[out] the context found
* \return true if a valid context has been found
*/
bool FindUnicastCompressionContext (Ipv6Address address, uint8_t& contextId);
/**
* \brief Finds if the given multicast address matches a context for compression
*
* \param[in] address the address to check
* \param[out] the context found
* \return true if a valid context has been found
*/
bool FindMulticastCompressionContext (Ipv6Address address, uint8_t& contextId);
/**
* \brief Clean an address from its prefix.
*
* This function is used to find the relevant bits to be sent in stateful IPHC compression.
* Only the pefix length is used - the address prefix is assumed to be matching the prefix.
*
* \param address the address to be cleaned
* \param the prefix to remove
* \return An address with the prefix zeroed.
*/
Ipv6Address CleanPrefix (Ipv6Address address, Ipv6Prefix prefix);
};
} // namespace ns3

View File

@@ -0,0 +1,348 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2020 Universita' di Firenze, Italy
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
*/
#include "mock-net-device.h"
#include "ns3/node.h"
#include "ns3/packet.h"
#include "ns3/log.h"
#include "ns3/pointer.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/boolean.h"
#include "ns3/simulator.h"
#include "ns3/channel.h"
#include "ns3/mac64-address.h"
#include "ns3/mac48-address.h"
#include "ns3/mac16-address.h"
#include "ns3/mac8-address.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("MockNetDevice");
NS_OBJECT_ENSURE_REGISTERED (MockNetDevice);
TypeId
MockNetDevice::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::MockNetDevice")
.SetParent<NetDevice> ()
.SetGroupName("Network")
.AddConstructor<MockNetDevice> ()
.AddAttribute ("PointToPointMode",
"The device is configured in Point to Point mode",
BooleanValue (false),
MakeBooleanAccessor (&MockNetDevice::m_pointToPointMode),
MakeBooleanChecker ())
;
return tid;
}
MockNetDevice::MockNetDevice ()
: m_node (0),
m_mtu (0xffff),
m_ifIndex (0),
m_linkUp (true)
{
NS_LOG_FUNCTION (this);
}
void
MockNetDevice::Receive (Ptr<Packet> packet, uint16_t protocol,
Address to, Address from, NetDevice::PacketType packetType)
{
NS_LOG_FUNCTION (this << packet << protocol << to << from);
if (packetType != NetDevice::PACKET_OTHERHOST)
{
m_rxCallback (this, packet, protocol, from);
}
if (!m_promiscCallback.IsNull ())
{
m_promiscCallback (this, packet, protocol, from, to, packetType);
}
}
void
MockNetDevice::SetIfIndex (const uint32_t index)
{
NS_LOG_FUNCTION (this << index);
m_ifIndex = index;
}
uint32_t
MockNetDevice::GetIfIndex (void) const
{
NS_LOG_FUNCTION (this);
return m_ifIndex;
}
Ptr<Channel>
MockNetDevice::GetChannel (void) const
{
NS_LOG_FUNCTION (this);
return 0;
}
void
MockNetDevice::SetAddress (Address address)
{
NS_LOG_FUNCTION (this << address);
m_address = address;
}
Address
MockNetDevice::GetAddress (void) const
{
NS_LOG_FUNCTION (this);
return m_address;
}
bool
MockNetDevice::SetMtu (const uint16_t mtu)
{
NS_LOG_FUNCTION (this << mtu);
m_mtu = mtu;
return true;
}
uint16_t
MockNetDevice::GetMtu (void) const
{
NS_LOG_FUNCTION (this);
return m_mtu;
}
bool
MockNetDevice::IsLinkUp (void) const
{
NS_LOG_FUNCTION (this);
return m_linkUp;
}
void
MockNetDevice::AddLinkChangeCallback (Callback<void> callback)
{
NS_LOG_FUNCTION (this << &callback);
m_linkChangeCallbacks.ConnectWithoutContext (callback);
}
bool
MockNetDevice::IsBroadcast (void) const
{
NS_LOG_FUNCTION (this);
if (m_pointToPointMode)
{
return false;
}
if (Mac64Address::IsMatchingType (m_address))
{
return false;
}
if (Mac8Address::IsMatchingType (m_address))
{
return false;
}
return true;
}
Address
MockNetDevice::GetBroadcast (void) const
{
NS_LOG_FUNCTION (this);
Address address;
if (Mac48Address::IsMatchingType (m_address))
{
address = Mac48Address::GetBroadcast ();
}
else if (Mac16Address::IsMatchingType (m_address))
{
address = Mac16Address::GetBroadcast ();
}
return address;
}
bool
MockNetDevice::IsMulticast (void) const
{
NS_LOG_FUNCTION (this);
if (m_pointToPointMode)
{
return false;
}
if (Mac64Address::IsMatchingType (m_address))
{
return false;
}
if (Mac8Address::IsMatchingType (m_address))
{
return false;
}
return true;
}
Address
MockNetDevice::GetMulticast (Ipv4Address multicastGroup) const
{
NS_LOG_FUNCTION (this << multicastGroup);
Address address;
if (Mac48Address::IsMatchingType (m_address))
{
address = Mac48Address::GetMulticast (multicastGroup);
}
else if (Mac16Address::IsMatchingType (m_address))
{
address = Mac16Address::GetMulticast (Ipv6Address::MakeIpv4MappedAddress (multicastGroup));
}
return address;
}
Address MockNetDevice::GetMulticast (Ipv6Address addr) const
{
NS_LOG_FUNCTION (this << addr);
Address address;
if (Mac48Address::IsMatchingType (m_address))
{
address = Mac48Address::GetMulticast (addr);
}
else if (Mac16Address::IsMatchingType (m_address))
{
address = Mac16Address::GetMulticast (addr);
}
return address;
}
bool
MockNetDevice::IsPointToPoint (void) const
{
NS_LOG_FUNCTION (this);
if (m_pointToPointMode)
{
return true;
}
return false;
}
bool
MockNetDevice::IsBridge (void) const
{
NS_LOG_FUNCTION (this);
return false;
}
bool
MockNetDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
{
NS_LOG_FUNCTION (this << packet << dest << protocolNumber);
return SendFrom (packet, m_address, dest, protocolNumber);
}
bool
MockNetDevice::SendFrom (Ptr<Packet> p, const Address& source, const Address& dest, uint16_t protocolNumber)
{
NS_LOG_FUNCTION (this << p << source << dest << protocolNumber);
if (p->GetSize () > GetMtu ())
{
return false;
}
if (!m_sendCallback.IsNull ())
{
m_sendCallback (this, p, protocolNumber, source, dest, NetDevice::PACKET_HOST);
}
return true;
}
Ptr<Node>
MockNetDevice::GetNode (void) const
{
NS_LOG_FUNCTION (this);
return m_node;
}
void
MockNetDevice::SetNode (Ptr<Node> node)
{
NS_LOG_FUNCTION (this << node);
m_node = node;
}
bool
MockNetDevice::NeedsArp (void) const
{
NS_LOG_FUNCTION (this);
if (m_pointToPointMode)
{
return false;
}
return true;
}
void
MockNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
{
NS_LOG_FUNCTION (this << &cb);
m_rxCallback = cb;
}
void
MockNetDevice::DoDispose (void)
{
NS_LOG_FUNCTION (this);
m_node = 0;
m_rxCallback.Nullify ();
m_promiscCallback.Nullify ();
m_sendCallback.Nullify ();
NetDevice::DoDispose ();
}
void
MockNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
{
NS_LOG_FUNCTION (this << &cb);
m_promiscCallback = cb;
}
bool
MockNetDevice::SupportsSendFrom (void) const
{
NS_LOG_FUNCTION (this);
return true;
}
void
MockNetDevice::SetSendCallback (PromiscReceiveCallback cb)
{
NS_LOG_FUNCTION (this << &cb);
m_sendCallback = cb;
}
} // namespace ns3

View File

@@ -0,0 +1,132 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2020 Universita' di Firenze, Italy
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
*/
#ifndef MOCK_NET_DEVICE_H
#define MOCK_NET_DEVICE_H
#include <stdint.h>
#include <string>
#include "ns3/traced-callback.h"
#include "ns3/net-device.h"
namespace ns3 {
class Node;
/**
* \ingroup netdevice
*
* This device assumes 48-bit mac addressing; there is also the possibility to
* add an ErrorModel if you want to force losses on the device.
*
* The device can be installed on a node through the MockNetDeviceHelper.
* In case of manual creation, the user is responsible for assigning an unique
* address to the device.
*
* By default the device is in Broadcast mode, with infinite bandwidth.
*
* \brief simple net device for simple things and testing
*/
class MockNetDevice : public NetDevice
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
MockNetDevice ();
/**
* Pretend that a packet has been received from a connected Channel.
*
* Note that no analysis is performed on the addresses, and the
* packet is forwarded to the callbacks according to the packetType.
*
* \param packet Packet received on the channel
* \param protocol protocol number
* \param to address packet should be sent to
* \param from address packet was sent from
* \param packetType type of the packet (e.g., NetDevice::PACKET_HOST, NetDevice::PACKET_OTHERHOST, etc.)
*/
void Receive (Ptr<Packet> packet, uint16_t protocol, Address to, Address from, NetDevice::PacketType packetType);
// inherited from NetDevice base class.
virtual void SetIfIndex (const uint32_t index);
virtual uint32_t GetIfIndex (void) const;
virtual Ptr<Channel> GetChannel (void) const;
virtual void SetAddress (Address address);
virtual Address GetAddress (void) const;
virtual bool SetMtu (const uint16_t mtu);
virtual uint16_t GetMtu (void) const;
virtual bool IsLinkUp (void) const;
virtual void AddLinkChangeCallback (Callback<void> callback);
virtual bool IsBroadcast (void) const;
virtual Address GetBroadcast (void) const;
virtual bool IsMulticast (void) const;
virtual Address GetMulticast (Ipv4Address multicastGroup) const;
virtual Address GetMulticast (Ipv6Address addr) const;
virtual bool IsPointToPoint (void) const;
virtual bool IsBridge (void) const;
virtual bool Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
virtual bool SendFrom (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
virtual Ptr<Node> GetNode (void) const;
virtual void SetNode (Ptr<Node> node);
virtual bool NeedsArp (void) const;
virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
virtual bool SupportsSendFrom (void) const;
/**
*
* Add a callback to be invoked when the MockNetDevice has a packet to "send".
*
* In the callback the PacketType is always set to NetDevice::PACKET_HOST.
*
* \param cb callback to invoke whenever the MockNetDevice has one packet to "send".
*
*/
void SetSendCallback (PromiscReceiveCallback cb);
protected:
virtual void DoDispose (void);
private:
NetDevice::ReceiveCallback m_rxCallback; //!< Receive callback
NetDevice::PromiscReceiveCallback m_promiscCallback; //!< Promiscuous receive callback
NetDevice::PromiscReceiveCallback m_sendCallback; //!< Send callback
Ptr<Node> m_node; //!< Node this netDevice is associated to
uint16_t m_mtu; //!< MTU
uint32_t m_ifIndex; //!< Interface index
Address m_address; //!< MAC address
bool m_linkUp; //!< Flag indicating whether or not the link is up
bool m_pointToPointMode; //!< Enabling this will disable Broadcast and Arp.
/**
* List of callbacks to fire if the link changes state (up or down).
*/
TracedCallback<> m_linkChangeCallbacks;
};
} // namespace ns3
#endif /* MOCK_NET_DEVICE_H */

View File

@@ -0,0 +1,313 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2020 Universita' di Firenze, Italy
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
*/
#include "ns3/test.h"
#include "ns3/socket-factory.h"
#include "ns3/simulator.h"
#include "ns3/socket.h"
#include "ns3/boolean.h"
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/inet6-socket-address.h"
#include "ns3/internet-stack-helper.h"
#include "ns3/ipv6-address-helper.h"
#include "ns3/icmpv6-l4-protocol.h"
#include "ns3/sixlowpan-net-device.h"
#include "ns3/sixlowpan-header.h"
#include "ns3/sixlowpan-helper.h"
#include "mock-net-device.h"
#include <string>
#include <limits>
#include <vector>
using namespace ns3;
/**
* \ingroup sixlowpan
* \defgroup sixlowpan-test 6LoWPAN module tests
*/
/**
* \ingroup sixlowpan-test
* \ingroup tests
*
* \brief 6LoWPAN IPHC stateful compression Test
*/
class SixlowpanIphcStatefulImplTest : public TestCase
{
/**
* \brief Structure to hold the Rx/Tx packets.
*/
typedef struct
{
Ptr<Packet> packet; /**< Packet data */
Address src; /**< Source address */
Address dst; /**< Destination address */
} Data;
std::vector<Data> m_txPackets; //!< Transmitted packets
std::vector<Data> m_rxPackets; //!< Received packets
bool ReceiveFromMockDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
Address const &source, Address const &destination, NetDevice::PacketType packetType);
bool PromiscReceiveFromSixLowPanDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
Address const &source, Address const &destination, NetDevice::PacketType packetType);
void SendOnePacket (NetDeviceContainer devices, Ipv6Address from, Ipv6Address to);
NetDeviceContainer m_mockDevices; //!< MockNetDevice container
NetDeviceContainer m_sixDevices; //!< SixLowPanNetDevice container
public:
virtual void DoRun (void);
SixlowpanIphcStatefulImplTest ();
};
SixlowpanIphcStatefulImplTest::SixlowpanIphcStatefulImplTest ()
: TestCase ("Sixlowpan IPHC stateful implementation")
{
}
bool
SixlowpanIphcStatefulImplTest::ReceiveFromMockDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
Address const &source, Address const &destination, NetDevice::PacketType packetType)
{
Data incomingPkt;
incomingPkt.packet = packet->Copy ();
incomingPkt.src = source;
incomingPkt.dst = destination;
m_txPackets.push_back (incomingPkt);
Ptr<MockNetDevice> mockDev = DynamicCast<MockNetDevice> (m_mockDevices.Get(1));
if (mockDev)
{
uint32_t id = mockDev->GetNode ()->GetId ();
Simulator::ScheduleWithContext (id, Time(1), &MockNetDevice::Receive, mockDev, incomingPkt.packet, protocol, destination, source, packetType);
}
return true;
}
bool
SixlowpanIphcStatefulImplTest::PromiscReceiveFromSixLowPanDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
Address const &source, Address const &destination, NetDevice::PacketType packetType)
{
Data incomingPkt;
incomingPkt.packet = packet->Copy ();
incomingPkt.src = source;
incomingPkt.dst = destination;
m_rxPackets.push_back (incomingPkt);
return true;
}
void
SixlowpanIphcStatefulImplTest::SendOnePacket (NetDeviceContainer devices, Ipv6Address from, Ipv6Address to)
{
Ptr<Packet> pkt = Create<Packet> (10);
Ipv6Header ipHdr;
ipHdr.SetSourceAddress (from);
ipHdr.SetDestinationAddress (to);
ipHdr.SetHopLimit (64);
ipHdr.SetPayloadLength (10);
ipHdr.SetNextHeader (0xff);
pkt->AddHeader (ipHdr);
devices.Get (0)->Send (pkt, Mac48Address ("00:00:00:00:00:02"), 0);
}
void
SixlowpanIphcStatefulImplTest::DoRun (void)
{
NodeContainer nodes;
nodes.Create(2);
// First node, setup NetDevices.
Ptr<MockNetDevice> mockNetDevice0 = CreateObject<MockNetDevice> ();
nodes.Get (0)->AddDevice (mockNetDevice0);
mockNetDevice0->SetNode (nodes.Get (0));
mockNetDevice0->SetAddress (Mac48Address ("00:00:00:00:00:01"));
mockNetDevice0->SetMtu (150);
mockNetDevice0->SetSendCallback ( MakeCallback (&SixlowpanIphcStatefulImplTest::ReceiveFromMockDevice, this) );
m_mockDevices.Add (mockNetDevice0);
// Second node, setup NetDevices.
Ptr<MockNetDevice> mockNetDevice1 = CreateObject<MockNetDevice> ();
nodes.Get (1)->AddDevice (mockNetDevice1);
mockNetDevice1->SetNode (nodes.Get (1));
mockNetDevice1->SetAddress (Mac48Address ("00:00:00:00:00:02"));
mockNetDevice1->SetMtu (150);
m_mockDevices.Add (mockNetDevice1);
InternetStackHelper internetv6;
internetv6.Install (nodes);
SixLowPanHelper sixlowpan;
m_sixDevices = sixlowpan.Install (m_mockDevices);
m_sixDevices.Get (1)->SetPromiscReceiveCallback ( MakeCallback (&SixlowpanIphcStatefulImplTest::PromiscReceiveFromSixLowPanDevice, this) );
Ipv6AddressHelper ipv6;
ipv6.SetBase (Ipv6Address ("2001:2::"), Ipv6Prefix (64));
Ipv6InterfaceContainer deviceInterfaces;
deviceInterfaces = ipv6.Assign (m_sixDevices);
// This is a hack to prevent Router Solicitations and Duplicate Address Detection being sent.
for (auto i = nodes.Begin (); i != nodes.End (); i++)
{
Ptr<Node> node = *i;
Ptr<Ipv6L3Protocol> ipv6L3 = (*i)->GetObject<Ipv6L3Protocol> ();
if (ipv6L3)
{
ipv6L3->SetAttribute ("IpForward", BooleanValue (true));
ipv6L3->SetAttribute ("SendIcmpv6Redirect", BooleanValue (false));
}
Ptr<Icmpv6L4Protocol> icmpv6 = (*i)->GetObject<Icmpv6L4Protocol> ();
if (icmpv6)
{
icmpv6->SetAttribute ("DAD", BooleanValue (false));
}
}
sixlowpan.AddContext (m_sixDevices, 0, Ipv6Prefix ("2001:2::", 64), Time (Minutes (30)));
sixlowpan.AddContext (m_sixDevices, 1, Ipv6Prefix ("2001:1::", 64), Time (Minutes (30)));
Ipv6Address srcElided = deviceInterfaces.GetAddress (0, 1);
Ipv6Address dstElided = Ipv6Address::MakeAutoconfiguredAddress (Mac48Address ("00:00:00:00:00:02"), Ipv6Prefix ("2001:2::", 64));
Simulator::Schedule (Seconds (1), &SixlowpanIphcStatefulImplTest::SendOnePacket, this, m_sixDevices,
Ipv6Address::GetAny (),
dstElided);
Simulator::Schedule (Seconds (2), &SixlowpanIphcStatefulImplTest::SendOnePacket, this, m_sixDevices,
Ipv6Address ("2001:2::f00d:f00d:cafe:cafe"),
Ipv6Address ("2001:1::0000:00ff:fe00:cafe"));
Simulator::Schedule (Seconds (3), &SixlowpanIphcStatefulImplTest::SendOnePacket, this, m_sixDevices,
Ipv6Address ("2001:1::0000:00ff:fe00:cafe"),
Ipv6Address ("2001:1::f00d:f00d:cafe:cafe"));
Simulator::Schedule (Seconds (4), &SixlowpanIphcStatefulImplTest::SendOnePacket, this, m_sixDevices,
srcElided,
Ipv6Address ("2001:1::f00d:f00d:cafe:cafe"));
Simulator::Stop (Seconds (10));
Simulator::Run ();
Simulator::Destroy ();
// ------ Now the tests ------------
SixLowPanIphc iphcHdr;
Ipv6Header ipv6Hdr;
// first packet sent, expected CID(0) SAC(1) SAM (0) M(0) DAC(1) DAM (3)
m_txPackets[0].packet->RemoveHeader (iphcHdr);
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetCid (), false, "CID should be false, is true");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSac (), true, "SAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSam (), SixLowPanIphc::HC_INLINE, "SAM should be HC_INLINE, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetM (), false, "M should be false, is true");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDac (), true, "DAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSrcContextId (), 0, "Src context should be 0, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDstContextId (), 0, "Dst context should be 0, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDam (), SixLowPanIphc::HC_COMPR_0, "DAM should be HC_COMPR_0, it is not");
// first packet received, expected :: -> dstElided
m_rxPackets[0].packet->RemoveHeader (ipv6Hdr);
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetSourceAddress (), Ipv6Address::GetAny (), "Src address wrongly rebuilt");
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetDestinationAddress (), dstElided, "Dst address wrongly rebuilt");
// second packet sent, expected CID(1) SAC(1) SAM (1) M(0) DAC(1) DAM (2)
m_txPackets[1].packet->RemoveHeader (iphcHdr);
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetCid (), true, "CID should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSac (), true, "SAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSam (), SixLowPanIphc::HC_COMPR_64, "SAM should be HC_COMPR_64, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetM (), false, "M should be false, is true");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDac (), true, "DAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSrcContextId (), 0, "Src context should be 0, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDstContextId (), 1, "Dst context should be 1, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDam (), SixLowPanIphc::HC_COMPR_16, "DAM should be HC_COMPR_16, it is not");
// second packet received, expected 2001:2::f00d:f00d:cafe:cafe -> 2001:1::0000:00ff:fe00:cafe
m_rxPackets[1].packet->RemoveHeader (ipv6Hdr);
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetSourceAddress (), Ipv6Address ("2001:2::f00d:f00d:cafe:cafe"), "Src address wrongly rebuilt");
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetDestinationAddress (), Ipv6Address ("2001:1::0000:00ff:fe00:cafe"), "Dst address wrongly rebuilt");
// third packet sent, expected CID(17) SAC(1) SAM (2) M(0) DAC(1) DAM (1)
m_txPackets[2].packet->RemoveHeader (iphcHdr);
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetCid (), true, "CID should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSac (), true, "SAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSam (), SixLowPanIphc::HC_COMPR_16, "SAM should be HC_COMPR_16, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetM (), false, "M should be false, is true");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDac (), true, "DAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSrcContextId (), 1, "Src context should be 1, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDstContextId (), 1, "Dst context should be 1, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDam (), SixLowPanIphc::HC_COMPR_64, "DAM should be HC_COMPR_64, it is not");
// third packet received, expected 2001:1::0000:00ff:fe00:cafe -> 2001:1::f00d:f00d:cafe:cafe
m_rxPackets[2].packet->RemoveHeader (ipv6Hdr);
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetSourceAddress (), Ipv6Address ("2001:1::0000:00ff:fe00:cafe"), "Src address wrongly rebuilt");
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetDestinationAddress (), Ipv6Address ("2001:1::f00d:f00d:cafe:cafe"), "Dst address wrongly rebuilt");
// fourth packet sent, expected CID(1) SAC(1) SAM (3) M(0) DAC(1) DAM (1)
m_txPackets[3].packet->RemoveHeader (iphcHdr);
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetCid (), true, "CID should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSac (), true, "SAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSam (), SixLowPanIphc::HC_COMPR_0, "SAM should be HC_COMPR_0, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetM (), false, "M should be false, is true");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDac (), true, "DAC should be true, is false");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetSrcContextId (), 0, "Src context should be 0, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDstContextId (), 1, "Dst context should be 1, it is not");
NS_TEST_EXPECT_MSG_EQ (iphcHdr.GetDam (), SixLowPanIphc::HC_COMPR_64, "DAM should be HC_COMPR_64, it is not");
// fourth packet received, expected srcElided -> 2001:1::f00d:f00d:cafe:cafe
m_rxPackets[3].packet->RemoveHeader (ipv6Hdr);
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetSourceAddress (), srcElided, "Src address wrongly rebuilt");
NS_TEST_EXPECT_MSG_EQ (ipv6Hdr.GetDestinationAddress (), Ipv6Address ("2001:1::f00d:f00d:cafe:cafe"), "Dst address wrongly rebuilt");
m_rxPackets.clear ();
m_txPackets.clear ();
}
/**
* \ingroup sixlowpan-test
* \ingroup tests
*
* \brief 6LoWPAN IPHC TestSuite
*/
class SixlowpanIphcStatefulTestSuite : public TestSuite
{
public:
SixlowpanIphcStatefulTestSuite ();
private:
};
SixlowpanIphcStatefulTestSuite::SixlowpanIphcStatefulTestSuite ()
: TestSuite ("sixlowpan-iphc-stateful", UNIT)
{
AddTestCase (new SixlowpanIphcStatefulImplTest (), TestCase::QUICK);
}
static SixlowpanIphcStatefulTestSuite g_sixlowpanIphcStatefulTestSuite; //!< Static variable for test initialization

View File

@@ -11,8 +11,10 @@ def build(bld):
module_test = bld.create_ns3_module_test_library('sixlowpan')
module_test.source = [
'test/mock-net-device.cc',
'test/sixlowpan-hc1-test.cc',
'test/sixlowpan-iphc-test.cc',
'test/sixlowpan-iphc-stateful-test.cc',
'test/sixlowpan-fragmentation-test.cc',
]