From fbbd26d24b9743f35d8cb57cc3a2549fe002a136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Duda?= Date: Wed, 26 Oct 2016 22:13:53 +0200 Subject: [PATCH] 6LOWPAN: Add support to compression and decompression of IP-in-IP. (#887) --- src/core/thread/lowpan.cpp | 60 +++++++++++++++++++++++++----- src/core/thread/mesh_forwarder.cpp | 8 +--- tests/unit/test_lowpan.cpp | 6 +-- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index 22f900dee..9e6d7fae8 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -221,7 +221,7 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma bool srcContextValid = true, dstContextValid = true; uint8_t nextHeader; - aMessage.Read(0, sizeof(ip6Header), &ip6Header); + aMessage.Read(aMessage.GetOffset(), sizeof(ip6Header), &ip6Header); if (mNetworkData.GetContext(ip6Header.GetSource(), srcContext) != kThreadError_None) { @@ -284,6 +284,7 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma { case Ip6::kProtoHopOpts: case Ip6::kProtoUdp: + case Ip6::kProtoIp6: hcCtl |= kHcNextHeader; break; @@ -356,7 +357,7 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma aBuf[0] = hcCtl >> 8; aBuf[1] = hcCtl & 0xff; - aMessage.SetOffset(sizeof(ip6Header)); + aMessage.MoveOffset(sizeof(ip6Header)); nextHeader = static_cast(ip6Header.GetNextHeader()); @@ -372,6 +373,13 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma cur += CompressUdp(aMessage, cur); ExitNow(); + case Ip6::kProtoIp6: + // For IP-in-IP the NH bit of the LOWPAN_NHC encoding MUST be set to zero. + cur[0] = kExtHdrDispatch | kExtHdrEidIp6; + cur++; + + cur += Compress(aMessage, aMacSource, aMacDest, cur); + default: ExitNow(); } @@ -398,6 +406,7 @@ int Lowpan::CompressExtensionHeader(Message &aMessage, uint8_t *aBuf, uint8_t &a switch (extHeader.GetNextHeader()) { case Ip6::kProtoUdp: + case Ip6::kProtoIp6: cur[0] |= kExtHdrNextHeader; break; @@ -931,16 +940,20 @@ int Lowpan::Decompress(Message &aMessage, const Mac::Address &aMacSource, const Ip6::Header ip6Header; const uint8_t *cur = aBuf; bool compressed; - uint16_t remaining; int rval; + uint16_t remaining; + uint16_t ip6PayloadLength; + uint16_t compressedLength = 0; + uint16_t currentOffset = aMessage.GetOffset(); compressed = (((static_cast(cur[0]) << 8) | cur[1]) & kHcNextHeader) != 0; - VerifyOrExit((rval = DecompressBaseHeader(ip6Header, aMacSource, aMacDest, aBuf)) >= 0, ;); + VerifyOrExit((rval = DecompressBaseHeader(ip6Header, aMacSource, aMacDest, aBuf)) >= 0, + error = kThreadError_Parse); cur += rval; SuccessOrExit(error = aMessage.Append(&ip6Header, sizeof(ip6Header))); - SuccessOrExit(error = aMessage.SetOffset(sizeof(ip6Header))); + SuccessOrExit(error = aMessage.MoveOffset(sizeof(ip6Header))); while (compressed) { @@ -948,9 +961,23 @@ int Lowpan::Decompress(Message &aMessage, const Mac::Address &aMacSource, const if ((cur[0] & kExtHdrDispatchMask) == kExtHdrDispatch) { - compressed = (cur[0] & kExtHdrNextHeader) != 0; - VerifyOrExit((rval = DecompressExtensionHeader(aMessage, cur, remaining)) >= 0, - error = kThreadError_Parse); + if ((cur[0] & kExtHdrEidMask) == kExtHdrEidIp6) + { + compressed = false; + + cur++; + remaining--; + + VerifyOrExit((rval = Decompress(aMessage, aMacSource, aMacDest, cur, remaining, + (aDatagramLength ? aDatagramLength - aMessage.GetLength() : 0))) >= 0, + error = kThreadError_Parse); + } + else + { + compressed = (cur[0] & kExtHdrNextHeader) != 0; + VerifyOrExit((rval = DecompressExtensionHeader(aMessage, cur, remaining)) >= 0, + error = kThreadError_Parse); + } } else if ((cur[0] & kUdpDispatchMask) == kUdpDispatch) { @@ -966,8 +993,23 @@ int Lowpan::Decompress(Message &aMessage, const Mac::Address &aMacSource, const cur += rval; } + compressedLength = static_cast(cur - aBuf); + + if (aDatagramLength) + { + ip6PayloadLength = HostSwap16(aDatagramLength - sizeof(Ip6::Header)); + } + else + { + ip6PayloadLength = HostSwap16(aMessage.GetOffset() - currentOffset - + sizeof(Ip6::Header) + aBufLen - compressedLength); + } + + aMessage.Write(currentOffset + Ip6::Header::GetPayloadLengthOffset(), + sizeof(ip6PayloadLength), &ip6PayloadLength); + exit: - return (error == kThreadError_None) ? static_cast(cur - aBuf) : -1; + return (error == kThreadError_None) ? static_cast(compressedLength) : -1; } } // namespace Lowpan diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index b700fc683..5686b9de2 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -1567,8 +1567,7 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength, aFrameLength -= static_cast(headerLength); SuccessOrExit(error = message->SetLength(datagramLength)); - datagramLength = HostSwap16(datagramLength - sizeof(Ip6::Header)); - message->Write(Ip6::Header::GetPayloadLengthOffset(), sizeof(datagramLength), &datagramLength); + message->SetDatagramTag(datagramTag); message->SetTimeout(kReassemblyTimeout); @@ -1670,7 +1669,6 @@ void MeshForwarder::HandleLowpanHC(uint8_t *aFrame, uint8_t aFrameLength, ThreadError error = kThreadError_None; Message *message; int headerLength; - uint16_t ip6PayloadLength; VerifyOrExit((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeIp6, 0)) != NULL, error = kThreadError_NoBufs); @@ -1684,10 +1682,6 @@ void MeshForwarder::HandleLowpanHC(uint8_t *aFrame, uint8_t aFrameLength, aFrameLength -= static_cast(headerLength); SuccessOrExit(error = message->SetLength(message->GetLength() + aFrameLength)); - - ip6PayloadLength = HostSwap16(message->GetLength() - sizeof(Ip6::Header)); - message->Write(Ip6::Header::GetPayloadLengthOffset(), sizeof(ip6PayloadLength), &ip6PayloadLength); - message->Write(message->GetOffset(), aFrameLength, aFrame); // Security Check diff --git a/tests/unit/test_lowpan.cpp b/tests/unit/test_lowpan.cpp index b079bca8f..c8178719c 100644 --- a/tests/unit/test_lowpan.cpp +++ b/tests/unit/test_lowpan.cpp @@ -96,10 +96,6 @@ void TestLowpanIphc(void) SuccessOrQuit(message->Append(frame.GetPayload() + decompressedBytes, ip6PayloadLength), "6lo: Message::Append failed"); - ip6PayloadLength = HostSwap16(message->GetLength() - - sizeof(Ip6::Header)); - message->Write(Ip6::Header::GetPayloadLengthOffset(), - sizeof(ip6PayloadLength), &ip6PayloadLength); resultLength = message->GetLength(); message->Read(0, resultLength, result); @@ -110,6 +106,8 @@ void TestLowpanIphc(void) VerifyOrQuit(memcmp(ipVector.data(), result, resultLength) == 0, "6lo: Lowpan::Decompress failed"); + message->SetOffset(0); + // ===> Test Lowpan::Compress int compressBytes = sMockLowpan.Compress(*message, macSource, macDest, result);