From 49641e1d4eb8729565ea1f8a1db5efd132066a8a Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Thu, 14 Feb 2019 16:05:12 -0800 Subject: [PATCH] [lowpan] introduce buffer writer to lowpan compressor (#3597) --- src/core/thread/lowpan.cpp | 200 +++++++++++++---------------- src/core/thread/lowpan.hpp | 179 ++++++++++++++++++++++++-- src/core/thread/mesh_forwarder.cpp | 18 +-- tests/unit/test_lowpan.cpp | 11 +- 4 files changed, 272 insertions(+), 136 deletions(-) diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index eeb94377f..b3711a34e 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -98,13 +98,13 @@ exit: return error; } -int Lowpan::CompressSourceIid(const Mac::Address &aMacAddr, - const Ip6::Address &aIpAddr, - const Context & aContext, - uint16_t & aHcCtl, - uint8_t * aBuf) +otError Lowpan::CompressSourceIid(const Mac::Address &aMacAddr, + const Ip6::Address &aIpAddr, + const Context & aContext, + uint16_t & aHcCtl, + BufferWriter & aBuf) { - uint8_t * cur = aBuf; + otError error = OT_ERROR_NONE; Ip6::Address ipaddr; Mac::Address tmp; @@ -122,28 +122,26 @@ int Lowpan::CompressSourceIid(const Mac::Address &aMacAddr, if (memcmp(ipaddr.GetIid(), aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize) == 0) { aHcCtl |= kHcSrcAddrMode2; - cur[0] = aIpAddr.mFields.m8[14]; - cur[1] = aIpAddr.mFields.m8[15]; - cur += 2; + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8 + 14, 2)); } else { aHcCtl |= kHcSrcAddrMode1; - memcpy(cur, aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize); - cur += Ip6::Address::kInterfaceIdentifierSize; + SuccessOrExit(error = aBuf.Write(aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize)); } } - return static_cast(cur - aBuf); +exit: + return error; } -int Lowpan::CompressDestinationIid(const Mac::Address &aMacAddr, - const Ip6::Address &aIpAddr, - const Context & aContext, - uint16_t & aHcCtl, - uint8_t * aBuf) +otError Lowpan::CompressDestinationIid(const Mac::Address &aMacAddr, + const Ip6::Address &aIpAddr, + const Context & aContext, + uint16_t & aHcCtl, + BufferWriter & aBuf) { - uint8_t * cur = aBuf; + otError error = OT_ERROR_NONE; Ip6::Address ipaddr; Mac::Address tmp; @@ -161,25 +159,23 @@ int Lowpan::CompressDestinationIid(const Mac::Address &aMacAddr, if (memcmp(ipaddr.GetIid(), aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize) == 0) { aHcCtl |= kHcDstAddrMode2; - cur[0] = aIpAddr.mFields.m8[14]; - cur[1] = aIpAddr.mFields.m8[15]; - cur += 2; + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8 + 14, 2)); } else { aHcCtl |= kHcDstAddrMode1; - memcpy(cur, aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize); - cur += Ip6::Address::kInterfaceIdentifierSize; + SuccessOrExit(error = aBuf.Write(aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize)); } } - return static_cast(cur - aBuf); +exit: + return error; } -int Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, uint8_t *aBuf) +otError Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf) { + otError error = OT_ERROR_NONE; NetworkData::Leader &networkData = GetNetif().GetNetworkDataLeader(); - uint8_t * cur = aBuf; Context multicastContext; aHcCtl |= kHcMulticast; @@ -192,24 +188,21 @@ int Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, uin if (aIpAddr.mFields.m8[1] == 0x02 && i >= 15) { aHcCtl |= kHcDstAddrMode3; - cur[0] = aIpAddr.mFields.m8[15]; - cur++; + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8[15])); } // Check if multicast address can be compressed to 32-bits (ffxx::00xx:xxxx) else if (i >= 13) { aHcCtl |= kHcDstAddrMode2; - cur[0] = aIpAddr.mFields.m8[1]; - memcpy(cur + 1, aIpAddr.mFields.m8 + 13, 3); - cur += 4; + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8[1])); + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8 + 13, 3)); } // Check if multicast address can be compressed to 48-bits (ffxx::00xx:xxxx:xxxx) else if (i >= 11) { aHcCtl |= kHcDstAddrMode1; - cur[0] = aIpAddr.mFields.m8[1]; - memcpy(cur + 1, aIpAddr.mFields.m8 + 11, 5); - cur += 6; + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8[1])); + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8 + 11, 5)); } else { @@ -219,14 +212,12 @@ int Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, uin memcmp(multicastContext.mPrefix, aIpAddr.mFields.m8 + 4, 8) == 0) { aHcCtl |= kHcDstAddrContext | kHcDstAddrMode0; - memcpy(cur, aIpAddr.mFields.m8 + 1, 2); - memcpy(cur + 2, aIpAddr.mFields.m8 + 12, 4); - cur += 6; + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8 + 1, 2)); + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8 + 12, 4)); } else { - memcpy(cur, aIpAddr.mFields.m8, sizeof(Ip6::Address)); - cur += sizeof(Ip6::Address); + SuccessOrExit(error = aBuf.Write(aIpAddr.mFields.m8, sizeof(Ip6::Address))); } } @@ -234,13 +225,18 @@ int Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, uin } } - return static_cast(cur - aBuf); +exit: + return error; } -int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest, uint8_t *aBuf) +otError Lowpan::Compress(Message & aMessage, + const Mac::Address &aMacSource, + const Mac::Address &aMacDest, + BufferWriter & aBuf) { + otError error = OT_ERROR_NONE; NetworkData::Leader &networkData = GetNetif().GetNetworkDataLeader(); - uint8_t * cur = aBuf; + uint8_t * start = aBuf.GetWritePointer(); uint16_t hcCtl = 0; Ip6::Header ip6Header; uint8_t * ip6HeaderBytes = reinterpret_cast(&ip6Header); @@ -268,14 +264,13 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma hcCtl = kHcDispatch; // Lowpan HC Control Bits - cur += 2; + SuccessOrExit(error = aBuf.Advance(sizeof(hcCtl))); // Context Identifier if (srcContext.mContextId != 0 || dstContext.mContextId != 0) { hcCtl |= kHcContextId; - cur[0] = ((srcContext.mContextId << 4) | dstContext.mContextId) & 0xff; - cur++; + SuccessOrExit(error = aBuf.Write(((srcContext.mContextId << 4) | dstContext.mContextId) & 0xff)); } dscp = ((ip6HeaderBytes[0] << 2) & 0x3c) | (ip6HeaderBytes[1] >> 6); @@ -294,8 +289,7 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma // Elide Flow Label and carry Traffic Class in-line. hcCtl |= kHcFlowLabel; - cur[0] = ecn | dscp; - cur++; + SuccessOrExit(error = aBuf.Write(ecn | dscp)); } } else if (dscp == 0) @@ -303,17 +297,15 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma // Carry Flow Label and ECN only with 2-bit padding. hcCtl |= kHcTrafficClass; - cur[0] = ecn | (ip6HeaderBytes[1] & 0x0f); - memcpy(cur + 1, ip6HeaderBytes + 2, 2); - cur += 3; + SuccessOrExit(error = aBuf.Write(ecn | (ip6HeaderBytes[1] & 0x0f))); + SuccessOrExit(error = aBuf.Write(ip6HeaderBytes + 2, 2)); } else { // Carry Flow Label and Traffic Class in-line. - cur[0] = ecn | dscp; - cur[1] = ip6HeaderBytes[1] & 0x0f; - memcpy(cur + 2, ip6HeaderBytes + 2, 2); - cur += 4; + SuccessOrExit(error = aBuf.Write(ecn | dscp)); + SuccessOrExit(error = aBuf.Write(ip6HeaderBytes[1] & 0x0f)); + SuccessOrExit(error = aBuf.Write(ip6HeaderBytes + 2, 2)); } // Next Header @@ -326,8 +318,7 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma break; default: - cur[0] = static_cast(ip6Header.GetNextHeader()); - cur++; + SuccessOrExit(error = aBuf.Write(static_cast(ip6Header.GetNextHeader()))); break; } @@ -347,8 +338,7 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma break; default: - cur[0] = ip6Header.GetHopLimit(); - cur++; + SuccessOrExit(error = aBuf.Write(ip6Header.GetHopLimit())); break; } @@ -359,41 +349,39 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma } else if (ip6Header.GetSource().IsLinkLocal()) { - cur += CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, cur); + SuccessOrExit(error = CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, aBuf)); } else if (srcContextValid) { hcCtl |= kHcSrcAddrContext; - cur += CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, cur); + SuccessOrExit(error = CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, aBuf)); } else { - memcpy(cur, ip6Header.GetSource().mFields.m8, sizeof(ip6Header.GetSource())); - cur += sizeof(Ip6::Address); + SuccessOrExit(error = aBuf.Write(ip6Header.GetSource().mFields.m8, sizeof(ip6Header.GetSource()))); } // Destination Address if (ip6Header.GetDestination().IsMulticast()) { - cur += CompressMulticast(ip6Header.GetDestination(), hcCtl, cur); + SuccessOrExit(error = CompressMulticast(ip6Header.GetDestination(), hcCtl, aBuf)); } else if (ip6Header.GetDestination().IsLinkLocal()) { - cur += CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, cur); + SuccessOrExit(error = CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, aBuf)); } else if (dstContextValid) { hcCtl |= kHcDstAddrContext; - cur += CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, cur); + SuccessOrExit(error = CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, aBuf)); } else { - memcpy(cur, &ip6Header.GetDestination(), sizeof(ip6Header.GetDestination())); - cur += sizeof(Ip6::Address); + SuccessOrExit(error = aBuf.Write(&ip6Header.GetDestination(), sizeof(ip6Header.GetDestination()))); } - aBuf[0] = hcCtl >> 8; - aBuf[1] = hcCtl & 0xff; + start[0] = hcCtl >> 8; + start[1] = hcCtl & 0xff; aMessage.MoveOffset(sizeof(ip6Header)); nextHeader = static_cast(ip6Header.GetNextHeader()); @@ -403,19 +391,18 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma switch (nextHeader) { case Ip6::kProtoHopOpts: - cur += CompressExtensionHeader(aMessage, cur, nextHeader); + SuccessOrExit(error = CompressExtensionHeader(aMessage, aBuf, nextHeader)); break; case Ip6::kProtoUdp: - cur += CompressUdp(aMessage, cur); + error = CompressUdp(aMessage, aBuf); 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++; + SuccessOrExit(error = aBuf.Write(kExtHdrDispatch | kExtHdrEidIp6)); - cur += Compress(aMessage, aMacSource, aMacDest, cur); + error = Compress(aMessage, aMacSource, aMacDest, aBuf); // fall through @@ -425,37 +412,38 @@ int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Ma } exit: - return static_cast(cur - aBuf); + return error; } -int Lowpan::CompressExtensionHeader(Message &aMessage, uint8_t *aBuf, uint8_t &aNextHeader) +otError Lowpan::CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uint8_t &aNextHeader) { + otError error = OT_ERROR_NONE; Ip6::ExtensionHeader extHeader; Ip6::OptionHeader optionHeader; - uint8_t * cur = aBuf; uint8_t len; uint8_t padLength = 0; uint16_t offset; + uint8_t tmpByte; aMessage.Read(aMessage.GetOffset(), sizeof(extHeader), &extHeader); aMessage.MoveOffset(sizeof(extHeader)); - cur[0] = kExtHdrDispatch | kExtHdrEidHbh; + tmpByte = kExtHdrDispatch | kExtHdrEidHbh; switch (extHeader.GetNextHeader()) { case Ip6::kProtoUdp: case Ip6::kProtoIp6: - cur[0] |= kExtHdrNextHeader; + tmpByte |= kExtHdrNextHeader; break; default: - cur++; - cur[0] = static_cast(extHeader.GetNextHeader()); + SuccessOrExit(error = aBuf.Write(tmpByte)); + tmpByte = static_cast(extHeader.GetNextHeader()); break; } - cur++; + SuccessOrExit(error = aBuf.Write(tmpByte)); len = (extHeader.GetLength() + 1) * 8 - sizeof(extHeader); @@ -496,21 +484,18 @@ int Lowpan::CompressExtensionHeader(Message &aMessage, uint8_t *aBuf, uint8_t &a aNextHeader = static_cast(extHeader.GetNextHeader()); - cur[0] = len; - cur++; - - aMessage.Read(aMessage.GetOffset(), len, cur); + SuccessOrExit(error = aBuf.Write(len)); + SuccessOrExit(error = aBuf.Write(aMessage, len)); aMessage.MoveOffset(len + padLength); - cur += len; - return static_cast(cur - aBuf); +exit: + return error; } -int Lowpan::CompressUdp(Message &aMessage, uint8_t *aBuf) +otError Lowpan::CompressUdp(Message &aMessage, BufferWriter &aBuf) { + otError error = OT_ERROR_NONE; Ip6::UdpHeader udpHeader; - uint8_t * cur = aBuf; - uint8_t * udpCtl = cur; uint16_t source; uint16_t destination; @@ -518,40 +503,37 @@ int Lowpan::CompressUdp(Message &aMessage, uint8_t *aBuf) source = udpHeader.GetSourcePort(); destination = udpHeader.GetDestinationPort(); - cur[0] = kUdpDispatch; - cur++; - if ((source & 0xfff0) == 0xf0b0 && (destination & 0xfff0) == 0xf0b0) { - *udpCtl |= 3; - *cur++ = (((source & 0xf) << 4) | (destination & 0xf)) & 0xff; + SuccessOrExit(error = aBuf.Write(kUdpDispatch | 3)); + SuccessOrExit(error = aBuf.Write((((source & 0xf) << 4) | (destination & 0xf)) & 0xff)); } else if ((source & 0xff00) == 0xf000) { - *udpCtl |= 2; - *cur++ = source & 0xff; - *cur++ = destination >> 8; - *cur++ = destination & 0xff; + SuccessOrExit(error = aBuf.Write(kUdpDispatch | 2)); + SuccessOrExit(error = aBuf.Write(source & 0xff)); + SuccessOrExit(error = aBuf.Write(destination >> 8)); + SuccessOrExit(error = aBuf.Write(destination & 0xff)); } else if ((destination & 0xff00) == 0xf000) { - *udpCtl |= 1; - *cur++ = source >> 8; - *cur++ = source & 0xff; - *cur++ = destination & 0xff; + SuccessOrExit(error = aBuf.Write(kUdpDispatch | 1)); + SuccessOrExit(error = aBuf.Write(source >> 8)); + SuccessOrExit(error = aBuf.Write(source & 0xff)); + SuccessOrExit(error = aBuf.Write(destination & 0xff)); } else { - memcpy(cur, &udpHeader, Ip6::UdpHeader::GetLengthOffset()); - cur += Ip6::UdpHeader::GetLengthOffset(); + SuccessOrExit(error = aBuf.Write(kUdpDispatch)); + SuccessOrExit(error = aBuf.Write(&udpHeader, Ip6::UdpHeader::GetLengthOffset())); } - memcpy(cur, reinterpret_cast(&udpHeader) + Ip6::UdpHeader::GetChecksumOffset(), 2); - cur += 2; + SuccessOrExit(error = aBuf.Write(reinterpret_cast(&udpHeader) + Ip6::UdpHeader::GetChecksumOffset(), 2)); aMessage.MoveOffset(sizeof(udpHeader)); - return static_cast(cur - aBuf); +exit: + return error; } otError Lowpan::DispatchToNextHeader(uint8_t aDispatch, Ip6::IpProto &aNextHeader) diff --git a/src/core/thread/lowpan.hpp b/src/core/thread/lowpan.hpp index 78c3e3c1d..62ce285bf 100644 --- a/src/core/thread/lowpan.hpp +++ b/src/core/thread/lowpan.hpp @@ -36,6 +36,7 @@ #include "openthread-core-config.h" +#include "common/debug.hpp" #include "common/locator.hpp" #include "common/message.hpp" #include "mac/mac_frame.hpp" @@ -74,6 +75,147 @@ struct Context bool mCompressFlag; ///< The Context compression flag. }; +/** + * This class defines a buffer writer used by the 6LoWPAN compressor. + * + */ +class BufferWriter +{ +public: + /** + * This constructor initializes the buffer writer. + * + * @param[in] aBuf A pointer to the write buffer. + * @param[in] aLength The size of the write buffer. + * + */ + BufferWriter(uint8_t *aBuf, uint8_t aLength) + { + mWritePointer = aBuf; + mRemainingLength = aLength; + } + + /** + * This method indicates whether there is buffer space available to write @p aLength bytes. + * + * @param[in] aLength Number of bytes to write. + * + * @retval TRUE Enough buffer space is available to write the requested number of bytes. + * @retval FALSE Insufficient buffer space to write the requested number of bytes. + * + */ + bool CanWrite(uint8_t aLength) const { return mRemainingLength >= aLength; } + + /** + * This method returns the current write pointer value. + * + * @returns the current write pointer value. + * + */ + uint8_t *GetWritePointer(void) { return mWritePointer; } + + /** + * This method advances the write pointer. + * + * @param[in] aLength Number of bytes to advance. + * + * @retval TRUE Enough buffer space is available to advance the requested number of bytes. + * @retval FALSE Insufficient buffer space to advance the requested number of bytes. + * + */ + otError Advance(uint8_t aLength) + { + otError error = OT_ERROR_NONE; + + VerifyOrExit(CanWrite(aLength), error = OT_ERROR_NO_BUFS); + + mWritePointer += aLength; + mRemainingLength -= aLength; + + exit: + return error; + } + + /** + * This method writes a byte into the buffer and updates the write pointer, if space is available. + * + * @param[in] aByte Byte to write. + * + * @retval OT_ERROR_NONE Successfully wrote the byte and updated the pointer. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte. + * + */ + otError Write(uint8_t aByte) + { + otError error = OT_ERROR_NONE; + + VerifyOrExit(CanWrite(sizeof(aByte)), error = OT_ERROR_NO_BUFS); + + *mWritePointer++ = aByte; + mRemainingLength--; + + exit: + return error; + } + + /** + * This method writes a byte sequence into the buffer and updates the write pointer, if space is available. + * + * @param[in] aBuf A pointer to the byte sequence. + * @param[in] aLength Number of bytes to write. + * + * @retval OT_ERROR_NONE Successfully wrote the byte sequence and updated the pointer. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte sequence. + * + */ + otError Write(const void *aBuf, uint8_t aLength) + { + otError error = OT_ERROR_NONE; + + VerifyOrExit(CanWrite(aLength), error = OT_ERROR_NO_BUFS); + + memcpy(mWritePointer, aBuf, aLength); + mWritePointer += aLength; + mRemainingLength -= aLength; + + exit: + return error; + } + + /** + * This method writes a byte sequence into the buffer and updates the write pointer, if space is available. + * + * The byte sequence is taken from a message buffer at the current message buffer's offset. + * + * @param[in] aMessage A message buffer. + * @param[in] aLength Number of bytes to write. + * + * @retval OT_ERROR_NONE Successfully wrote the byte sequence and updated the pointer. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte sequence. + * + */ + otError Write(const Message &aMessage, uint8_t aLength) + { + otError error = OT_ERROR_NONE; + int rval; + + VerifyOrExit(CanWrite(aLength), error = OT_ERROR_NO_BUFS); + + rval = aMessage.Read(aMessage.GetOffset(), aLength, mWritePointer); + assert(rval == aLength); + + mWritePointer += aLength; + mRemainingLength -= aLength; + + exit: + return error; + } + +private: + uint8_t *mWritePointer; + uint8_t mRemainingLength; +}; + /** * This class implements LOWPAN_IPHC header compression. * @@ -113,7 +255,10 @@ public: * @returns The size of the compressed header in bytes. * */ - int Compress(Message &aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest, uint8_t *aBuf); + otError Compress(Message & aMessage, + const Mac::Address &aMacSource, + const Mac::Address &aMacDest, + BufferWriter & aBuf); /** * This method decompresses a LOWPAN_IPHC header. @@ -216,19 +361,19 @@ private: kUdpPortMask = 3 << 0, }; - int CompressExtensionHeader(Message &aMessage, uint8_t *aBuf, uint8_t &aNextHeader); - int CompressSourceIid(const Mac::Address &aMacAddr, - const Ip6::Address &aIpAddr, - const Context & aContext, - uint16_t & aHcCtl, - uint8_t * aBuf); - int CompressDestinationIid(const Mac::Address &aMacAddr, - const Ip6::Address &aIpAddr, - const Context & aContext, - uint16_t & aHcCtl, - uint8_t * aBuf); - int CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, uint8_t *aBuf); - int CompressUdp(Message &aMessage, uint8_t *aBuf); + otError CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uint8_t &aNextHeader); + otError CompressSourceIid(const Mac::Address &aMacAddr, + const Ip6::Address &aIpAddr, + const Context & aContext, + uint16_t & aHcCtl, + BufferWriter & aBuf); + otError CompressDestinationIid(const Mac::Address &aMacAddr, + const Ip6::Address &aIpAddr, + const Context & aContext, + uint16_t & aHcCtl, + BufferWriter & aBuf); + otError CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf); + otError CompressUdp(Message &aMessage, BufferWriter &aBuf); int DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength); int DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength); @@ -429,6 +574,12 @@ OT_TOOL_PACKED_BEGIN class FragmentHeader { public: + enum + { + kInitialHeaderSize = 4, ///< Initial fragment header size in octets. + kSubsequentHeaderSize = 5, ///< Subsequent fragment header size in octets. + }; + /** * This constructor initializes the Fragment Header. * diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index d34d713ea..23963903e 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -684,7 +684,6 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) uint8_t * payload; uint8_t headerLength; uint16_t payloadLength; - int hcLength; uint16_t fragmentLength; uint16_t dstpan; uint8_t secCtl = Mac::Frame::kSecNone; @@ -870,12 +869,16 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) // copy IPv6 Header if (aMessage.GetOffset() == 0) { - hcLength = netif.GetLowpan().Compress(aMessage, meshSource, meshDest, payload); - assert(hcLength > 0); - headerLength += static_cast(hcLength); + Lowpan::BufferWriter buffer(payload, aFrame.GetMaxPayloadLength() - headerLength - + Lowpan::FragmentHeader::kInitialHeaderSize); + uint8_t hcLength; - payloadLength = aMessage.GetLength() - aMessage.GetOffset(); + error = netif.GetLowpan().Compress(aMessage, meshSource, meshDest, buffer); + assert(error == OT_ERROR_NONE); + hcLength = static_cast(buffer.GetWritePointer() - payload); + headerLength += hcLength; + payloadLength = aMessage.GetLength() - aMessage.GetOffset(); fragmentLength = aFrame.GetMaxPayloadLength() - headerLength; if (payloadLength > fragmentLength) @@ -898,9 +901,7 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) aMessage.SetDatagramTag(mFragTag++); } - memmove(payload + 4, payload, headerLength); - - payloadLength = (aFrame.GetMaxPayloadLength() - headerLength - 4) & ~0x7; + memmove(payload + Lowpan::FragmentHeader::kInitialHeaderSize, payload, hcLength); fragmentHeader = reinterpret_cast(payload); fragmentHeader->Init(); @@ -910,6 +911,7 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) payload += fragmentHeader->GetHeaderLength(); headerLength += fragmentHeader->GetHeaderLength(); + payloadLength = (aFrame.GetMaxPayloadLength() - headerLength) & ~0x7; } payload += hcLength; diff --git a/tests/unit/test_lowpan.cpp b/tests/unit/test_lowpan.cpp index 6ef4437d1..e0eb0918a 100644 --- a/tests/unit/test_lowpan.cpp +++ b/tests/unit/test_lowpan.cpp @@ -178,15 +178,20 @@ static void Test(TestIphcVector &aVector, bool aCompress, bool aDecompress) if (aCompress) { + Lowpan::BufferWriter buffer(result, 127); + VerifyOrQuit((message = sInstance->GetMessagePool().New(Message::kTypeIp6, 0)) != NULL, "6lo: Ip6::NewMessage failed"); aVector.GetUncompressedStream(*message); - int compressBytes = sLowpan->Compress(*message, aVector.mMacSource, aVector.mMacDestination, result); + VerifyOrQuit(sLowpan->Compress(*message, aVector.mMacSource, aVector.mMacDestination, buffer) == aVector.mError, + "6lo: Lowpan:Compress failed"); if (aVector.mError == OT_ERROR_NONE) { + uint8_t compressBytes = buffer.GetWritePointer() - result; + // Append payload to the LOWPAN_IPHC. message->Read(message->GetOffset(), message->GetLength() - message->GetOffset(), result + compressBytes); @@ -198,10 +203,6 @@ static void Test(TestIphcVector &aVector, bool aCompress, bool aDecompress) VerifyOrQuit(message->GetOffset() == aVector.mPayloadOffset, "6lo: Lowpan::Compress failed"); VerifyOrQuit(memcmp(iphc, result, iphcLength) == 0, "6lo: Lowpan::Compress failed"); } - else - { - VerifyOrQuit(compressBytes < 0, "6lo: Lowpan::Compress failed"); - } message->Free(); message = NULL;