[core] adding FrameBuilder for constructing frames (#7935)

This commit adds a new class `FrameBuilder` which helps with
construction of frames in a given buffer. It provides helper methods
to append different items to the frame, e.g., bytes from a buffer or
`Message`, a `uint8`, `uint16` or `uint32` value assuming big or
little endian encoding, or a given object. It also provides methods
to overwrite previously appended content in the frame at a given
offset. This class is used in `Lowpan` (replacing `BufferWriter`)
which helps simplify the code. This commit also updates `Appender` to
use the `FrameBuilder` and adds a new unit test for `FrameBuidler`.
This commit is contained in:
Abtin Keshavarzian
2022-07-25 19:59:55 -07:00
committed by GitHub
parent 5bc71b2a4f
commit a282aa9f9b
15 changed files with 635 additions and 275 deletions
+1
View File
@@ -231,6 +231,7 @@ LOCAL_SRC_FILES := \
src/core/common/crc16.cpp \
src/core/common/data.cpp \
src/core/common/error.cpp \
src/core/common/frame_builder.cpp \
src/core/common/frame_data.cpp \
src/core/common/heap.cpp \
src/core/common/heap_data.cpp \
+2
View File
@@ -397,6 +397,8 @@ openthread_core_files = [
"common/error.cpp",
"common/error.hpp",
"common/extension.hpp",
"common/frame_builder.cpp",
"common/frame_builder.hpp",
"common/frame_data.cpp",
"common/frame_data.hpp",
"common/heap.cpp",
+1
View File
@@ -97,6 +97,7 @@ set(COMMON_SOURCES
common/crc16.cpp
common/data.cpp
common/error.cpp
common/frame_builder.cpp
common/frame_data.cpp
common/heap.cpp
common/heap_data.cpp
+2
View File
@@ -187,6 +187,7 @@ SOURCES_COMMON = \
common/crc16.cpp \
common/data.cpp \
common/error.cpp \
common/frame_builder.cpp \
common/frame_data.cpp \
common/heap.cpp \
common/heap_data.cpp \
@@ -438,6 +439,7 @@ HEADERS_COMMON = \
common/equatable.hpp \
common/error.hpp \
common/extension.hpp \
common/frame_builder.hpp \
common/frame_data.hpp \
common/heap.hpp \
common/heap_allocatable.hpp \
+4 -10
View File
@@ -45,9 +45,7 @@ Appender::Appender(Message &aMessage)
Appender::Appender(uint8_t *aBuffer, uint16_t aSize)
: mType(kBuffer)
{
mShared.mBuffer.mStart = aBuffer;
mShared.mBuffer.mCur = aBuffer;
mShared.mBuffer.mEnd = aBuffer + aSize;
mShared.mFrameBuilder.Init(aBuffer, aSize);
}
Error Appender::AppendBytes(const void *aBuffer, uint16_t aLength)
@@ -61,14 +59,10 @@ Error Appender::AppendBytes(const void *aBuffer, uint16_t aLength)
break;
case kBuffer:
VerifyOrExit(aLength <= static_cast<uint16_t>(mShared.mBuffer.mEnd - mShared.mBuffer.mCur),
error = kErrorNoBufs);
memcpy(mShared.mBuffer.mCur, aBuffer, aLength);
mShared.mBuffer.mCur += aLength;
error = mShared.mFrameBuilder.AppendBytes(aBuffer, aLength);
break;
}
exit:
return error;
}
@@ -83,7 +77,7 @@ uint16_t Appender::GetAppendedLength(void) const
break;
case kBuffer:
length = static_cast<uint16_t>(mShared.mBuffer.mCur - mShared.mBuffer.mStart);
length = mShared.mFrameBuilder.GetLength();
break;
}
@@ -92,7 +86,7 @@ uint16_t Appender::GetAppendedLength(void) const
void Appender::GetAsData(Data<kWithUint16Length> &aData)
{
aData.Init(mShared.mBuffer.mStart, GetAppendedLength());
aData.Init(mShared.mFrameBuilder.GetBytes(), mShared.mFrameBuilder.GetLength());
}
} // namespace ot
+4 -7
View File
@@ -36,7 +36,9 @@
#include "openthread-core-config.h"
#include "common/const_cast.hpp"
#include "common/data.hpp"
#include "common/frame_builder.hpp"
#include "common/message.hpp"
#include "common/type_traits.hpp"
@@ -150,7 +152,7 @@ public:
* @returns A pointer to the start of the data buffer associated with `Appender`.
*
*/
uint8_t *GetBufferStart(void) { return mShared.mBuffer.mStart; }
uint8_t *GetBufferStart(void) { return AsNonConst(mShared.mFrameBuilder.GetBytes()); }
/**
* This method gets the data buffer associated with `Appender` as a `Data`.
@@ -172,12 +174,7 @@ private:
uint16_t mStartOffset;
} mMessage;
struct
{
uint8_t *mStart;
uint8_t *mCur;
uint8_t *mEnd;
} mBuffer;
FrameBuilder mFrameBuilder;
} mShared;
};
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2022, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the `FrameBuilder` class.
*/
#include "frame_builder.hpp"
namespace ot {
void FrameBuilder::Init(void *aBuffer, uint16_t aLength)
{
mBuffer = static_cast<uint8_t *>(aBuffer);
mLength = 0;
mMaxLength = aLength;
}
Error FrameBuilder::AppendUint8(uint8_t aUint8)
{
return Append<uint8_t>(aUint8);
}
Error FrameBuilder::AppendBigEndianUint16(uint16_t aUint16)
{
return Append<uint16_t>(Encoding::BigEndian::HostSwap16(aUint16));
}
Error FrameBuilder::AppendBigEndianUint32(uint32_t aUint32)
{
return Append<uint32_t>(Encoding::BigEndian::HostSwap32(aUint32));
}
Error FrameBuilder::AppendLittleEndianUint16(uint16_t aUint16)
{
return Append<uint16_t>(Encoding::LittleEndian::HostSwap16(aUint16));
}
Error FrameBuilder::AppendLittleEndianUint32(uint32_t aUint32)
{
return Append<uint32_t>(Encoding::LittleEndian::HostSwap32(aUint32));
}
Error FrameBuilder::AppendBytes(const void *aBuffer, uint16_t aLength)
{
Error error = kErrorNone;
VerifyOrExit(CanAppend(aLength), error = kErrorNoBufs);
memcpy(mBuffer + mLength, aBuffer, aLength);
mLength += aLength;
exit:
return error;
}
Error FrameBuilder::AppendBytesFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
{
Error error = kErrorNone;
VerifyOrExit(CanAppend(aLength), error = kErrorNoBufs);
SuccessOrExit(error = aMessage.Read(aOffset, mBuffer + mLength, aLength));
mLength += aLength;
exit:
return error;
}
void FrameBuilder::WriteBytes(uint16_t aOffset, const void *aBuffer, uint16_t aLength)
{
memcpy(mBuffer + aOffset, aBuffer, aLength);
}
} // namespace ot
+238
View File
@@ -0,0 +1,238 @@
/*
* Copyright (c) 2022, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file defines OpenThread `FrameBuilder` class.
*/
#ifndef FRAME_BUILDER_HPP_
#define FRAME_BUILDER_HPP_
#include "openthread-core-config.h"
#include "common/error.hpp"
#include "common/message.hpp"
#include "common/type_traits.hpp"
namespace ot {
/**
* The `FrameBuilder` can be used to construct frame content in a given data buffer.
*
*/
class FrameBuilder
{
public:
/**
* This method initializes the `FrameBuilder` to use a given buffer.
*
* `FrameBuilder` MUST be initialized before its other methods are used.
*
* @param[in] aBuffer A pointer to a buffer.
* @param[in] aLength The data length (number of bytes in @p aBuffer).
*
*/
void Init(void *aBuffer, uint16_t aLength);
/**
* This method returns a pointer to the start of `FrameBuilder` buffer.
*
* @returns A pointer to the frame buffer.
*
*/
const uint8_t *GetBytes(void) const { return mBuffer; }
/**
* This method returns the current length of frame (number of bytes appended so far).
*
* @returns The current frame length.
*
*/
uint16_t GetLength(void) const { return mLength; }
/**
* This method returns the maximum length of frame.
*
* @returns The maximum frame length (max number of bytes in the frame buffer).
*
*/
uint16_t GetMaxLength(void) const { return mMaxLength; }
/**
* This method indicates whether or not there are enough bytes remaining in the `FrameBuilder` buffer to append a
* given number of bytes.
*
* @param[in] aLength The append length.
*
* @retval TRUE There are enough remaining bytes to append @p aLength bytes.
* @retval FALSE There are not enough remaining bytes to append @p aLength bytes.
*
*/
bool CanAppend(uint16_t aLength) const { return (static_cast<uint32_t>(mLength) + aLength) <= mMaxLength; }
/**
* This method appends an `uint8_t` value to the `FrameBuilder`.
*
* @param[in] aUint8 The `uint8_t` value to append.
*
* @retval kErrorNone Successfully appended the value.
* @retval kErrorNoBufs Insufficient available buffers.
*
*/
Error AppendUint8(uint8_t aUint8);
/**
* This method appends an `uint16_t` value assuming big endian encoding to the `FrameBuilder`.
*
* @param[in] aUint16 The `uint16_t` value to append.
*
* @retval kErrorNone Successfully appended the value.
* @retval kErrorNoBufs Insufficient available buffers.
*
*/
Error AppendBigEndianUint16(uint16_t aUint16);
/**
* This method appends an `uint32_t` value assuming big endian encoding to the `FrameBuilder`.
*
* @param[in] aUint32 The `uint32_t` value to append.
*
* @retval kErrorNone Successfully appended the value.
* @retval kErrorNoBufs Insufficient available buffers.
*
*/
Error AppendBigEndianUint32(uint32_t aUint32);
/**
* This method appends an `uint16_t` value assuming little endian encoding to the `FrameBuilder`.
*
* @param[in] aUint16 The `uint16_t` value to append.
*
* @retval kErrorNone Successfully appended the value.
* @retval kErrorNoBufs Insufficient available buffers.
*
*/
Error AppendLittleEndianUint16(uint16_t aUint16);
/**
* This method appends an `uint32_t` value assuming little endian encoding to the `FrameBuilder`.
*
* @param[in] aUint32 The `uint32_t` value to append.
*
* @retval kErrorNone Successfully appended the value.
* @retval kErrorNoBufs Insufficient available buffers.
*
*/
Error AppendLittleEndianUint32(uint32_t aUint32);
/**
* This method appends bytes from a given buffer to the `FrameBuilder`.
*
* @param[in] aBuffer A pointer to a data bytes to append.
* @param[in] aLength Number of bytes in @p aBuffer.
*
* @retval kErrorNone Successfully appended the bytes.
* @retval kErrorNoBufs Insufficient available buffers.
*
*/
Error AppendBytes(const void *aBuffer, uint16_t aLength);
/**
* This method appends bytes read from a given message to the `FrameBuilder`.
*
* @param[in] aMessage The message to read the bytes from.
* @param[in] aOffset The offset in @p aMessage to start reading the bytes from.
* @param[in] aLength Number of bytes to read from @p aMessage and append.
*
* @retval kErrorNone Successfully appended the bytes.
* @retval kErrorNoBufs Insufficient available buffers to append the requested @p aLength bytes.
* @retval kErrorParse Not enough bytes in @p aMessage to read @p aLength bytes from @p aOffset.
*
*/
Error AppendBytesFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength);
/**
* This method appends an object to the `FrameBuilder`.
*
* @tparam ObjectType The object type to append.
*
* @param[in] aObject A reference to the object to append.
*
* @retval kErrorNone Successfully appended the object.
* @retval kErrorNoBufs Insufficient available buffers to append @p aObject.
*
*/
template <typename ObjectType> Error Append(const ObjectType &aObject)
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
return AppendBytes(&aObject, sizeof(ObjectType));
}
/**
* This method writes bytes in `FrameBuilder` at a given offset overwriting the previously appended content.
*
* This method does not perform any bound checks. The caller MUST ensure that the given data length fits within the
* previously appended content. Otherwise the behavior of this method is undefined.
*
* @param[in] aOffset The offset to begin writing.
* @param[in] aBuffer A pointer to a data buffer to write.
* @param[in] aLength Number of bytes in @p aBuffer.
*
*/
void WriteBytes(uint16_t aOffset, const void *aBuffer, uint16_t aLength);
/**
* This methods writes an object to the `FrameBuilder` at a given offset overwriting previously appended content.
*
* This method does not perform any bound checks. The caller MUST ensure the given data length fits within the
* previously appended content. Otherwise the behavior of this method is undefined.
*
* @tparam ObjectType The object type to write.
*
* @param[in] aOffset The offset to begin writing.
* @param[in] aObject A reference to the object to write.
*
*/
template <typename ObjectType> void Write(uint16_t aOffset, const ObjectType &aObject)
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
WriteBytes(aOffset, &aObject, sizeof(ObjectType));
}
private:
uint8_t *mBuffer;
uint16_t mLength;
uint16_t mMaxLength;
};
} // namespace ot
#endif // FRAME_BUILDER_HPP_
+79 -98
View File
@@ -95,10 +95,9 @@ Error Lowpan::CompressSourceIid(const Mac::Address &aMacAddr,
const Ip6::Address &aIpAddr,
const Context & aContext,
uint16_t & aHcCtl,
BufferWriter & aBuf)
FrameBuilder & aFrameBuilder)
{
Error error = kErrorNone;
BufferWriter buf = aBuf;
Ip6::Address ipaddr;
Mac::Address tmp;
@@ -116,21 +115,16 @@ Error Lowpan::CompressSourceIid(const Mac::Address &aMacAddr,
if (ipaddr.GetIid() == aIpAddr.GetIid())
{
aHcCtl |= kHcSrcAddrMode2;
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8 + 14, 2));
SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 14, 2));
}
else
{
aHcCtl |= kHcSrcAddrMode1;
SuccessOrExit(error = buf.Write(aIpAddr.GetIid().GetBytes(), Ip6::InterfaceIdentifier::kSize));
SuccessOrExit(error = aFrameBuilder.Append(aIpAddr.GetIid()));
}
}
exit:
if (error == kErrorNone)
{
aBuf = buf;
}
return error;
}
@@ -138,10 +132,9 @@ Error Lowpan::CompressDestinationIid(const Mac::Address &aMacAddr,
const Ip6::Address &aIpAddr,
const Context & aContext,
uint16_t & aHcCtl,
BufferWriter & aBuf)
FrameBuilder & aFrameBuilder)
{
Error error = kErrorNone;
BufferWriter buf = aBuf;
Ip6::Address ipaddr;
Mac::Address tmp;
@@ -159,29 +152,23 @@ Error Lowpan::CompressDestinationIid(const Mac::Address &aMacAddr,
if (ipaddr.GetIid() == aIpAddr.GetIid())
{
aHcCtl |= kHcDstAddrMode2;
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8 + 14, 2));
SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 14, 2));
}
else
{
aHcCtl |= kHcDstAddrMode1;
SuccessOrExit(error = buf.Write(aIpAddr.GetIid().GetBytes(), Ip6::InterfaceIdentifier::kSize));
SuccessOrExit(error = aFrameBuilder.Append(aIpAddr.GetIid()));
}
}
exit:
if (error == kErrorNone)
{
aBuf = buf;
}
return error;
}
Error Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf)
Error Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, FrameBuilder &aFrameBuilder)
{
Error error = kErrorNone;
BufferWriter buf = aBuf;
Context multicastContext;
Error error = kErrorNone;
Context multicastContext;
aHcCtl |= kHcMulticast;
@@ -193,21 +180,21 @@ Error Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, B
if (aIpAddr.mFields.m8[1] == 0x02 && i >= 15)
{
aHcCtl |= kHcDstAddrMode3;
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8[15]));
SuccessOrExit(error = aFrameBuilder.AppendUint8(aIpAddr.mFields.m8[15]));
}
// Check if multicast address can be compressed to 32-bits (ffxx::00xx:xxxx)
else if (i >= 13)
{
aHcCtl |= kHcDstAddrMode2;
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8[1]));
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8 + 13, 3));
SuccessOrExit(error = aFrameBuilder.AppendUint8(aIpAddr.mFields.m8[1]));
SuccessOrExit(error = aFrameBuilder.AppendBytes(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;
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8[1]));
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8 + 11, 5));
SuccessOrExit(error = aFrameBuilder.AppendUint8(aIpAddr.mFields.m8[1]));
SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 11, 5));
}
else
{
@@ -217,12 +204,12 @@ Error Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, B
memcmp(multicastContext.mPrefix.GetBytes(), aIpAddr.mFields.m8 + 4, 8) == 0)
{
aHcCtl |= kHcDstAddrContext | kHcDstAddrMode0;
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8 + 1, 2));
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8 + 12, 4));
SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 1, 2));
SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 12, 4));
}
else
{
SuccessOrExit(error = buf.Write(aIpAddr.mFields.m8, sizeof(Ip6::Address)));
SuccessOrExit(error = aFrameBuilder.Append(aIpAddr));
}
}
@@ -231,41 +218,47 @@ Error Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, B
}
exit:
if (error == kErrorNone)
{
aBuf = buf;
}
return error;
}
Error Lowpan::Compress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
BufferWriter & aBuf)
FrameBuilder & aFrameBuilder)
{
Error error;
Error error = kErrorNone;
uint8_t headerDepth = 0xff;
do
while (headerDepth > 0)
{
error = Compress(aMessage, aMacSource, aMacDest, aBuf, headerDepth);
} while ((error != kErrorNone) && (headerDepth > 0));
FrameBuilder frameBuilder = aFrameBuilder;
error = Compress(aMessage, aMacSource, aMacDest, aFrameBuilder, headerDepth);
// We exit if `Compress()` is successful. Otherwise we reset
// the `aFrameBuidler` to its earlier state (remove all
// appended content from the failed `Compress()` call) and
// try again with a different `headerDepth`.
VerifyOrExit(error != kErrorNone);
aFrameBuilder = frameBuilder;
}
exit:
return error;
}
Error Lowpan::Compress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
BufferWriter & aBuf,
FrameBuilder & aFrameBuilder,
uint8_t & aHeaderDepth)
{
Error error = kErrorNone;
NetworkData::Leader &networkData = Get<NetworkData::Leader>();
uint16_t startOffset = aMessage.GetOffset();
BufferWriter buf = aBuf;
uint16_t hcCtl = kHcDispatch;
uint16_t hcCtlOffset = 0;
Ip6::Header ip6Header;
uint8_t * ip6HeaderBytes = reinterpret_cast<uint8_t *>(&ip6Header);
Context srcContext, dstContext;
@@ -295,13 +288,14 @@ Error Lowpan::Compress(Message & aMessage,
}
// Lowpan HC Control Bits
SuccessOrExit(error = buf.Advance(sizeof(hcCtl)));
hcCtlOffset = aFrameBuilder.GetLength();
SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(hcCtl));
// Context Identifier
if (srcContext.mContextId != 0 || dstContext.mContextId != 0)
{
hcCtl |= kHcContextId;
SuccessOrExit(error = buf.Write(((srcContext.mContextId << 4) | dstContext.mContextId) & 0xff));
SuccessOrExit(error = aFrameBuilder.AppendUint8(((srcContext.mContextId << 4) | dstContext.mContextId) & 0xff));
}
dscp = ((ip6HeaderBytes[0] << 2) & 0x3c) | (ip6HeaderBytes[1] >> 6);
@@ -320,7 +314,7 @@ Error Lowpan::Compress(Message & aMessage,
// Elide Flow Label and carry Traffic Class in-line.
hcCtl |= kHcFlowLabel;
SuccessOrExit(error = buf.Write(ecn | dscp));
SuccessOrExit(error = aFrameBuilder.AppendUint8(ecn | dscp));
}
}
else if (dscp == 0)
@@ -328,15 +322,15 @@ Error Lowpan::Compress(Message & aMessage,
// Carry Flow Label and ECN only with 2-bit padding.
hcCtl |= kHcTrafficClass;
SuccessOrExit(error = buf.Write(ecn | (ip6HeaderBytes[1] & 0x0f)));
SuccessOrExit(error = buf.Write(ip6HeaderBytes + 2, 2));
SuccessOrExit(error = aFrameBuilder.AppendUint8(ecn | (ip6HeaderBytes[1] & 0x0f)));
SuccessOrExit(error = aFrameBuilder.AppendBytes(ip6HeaderBytes + 2, 2));
}
else
{
// Carry Flow Label and Traffic Class in-line.
SuccessOrExit(error = buf.Write(ecn | dscp));
SuccessOrExit(error = buf.Write(ip6HeaderBytes[1] & 0x0f));
SuccessOrExit(error = buf.Write(ip6HeaderBytes + 2, 2));
SuccessOrExit(error = aFrameBuilder.AppendUint8(ecn | dscp));
SuccessOrExit(error = aFrameBuilder.AppendUint8(ip6HeaderBytes[1] & 0x0f));
SuccessOrExit(error = aFrameBuilder.AppendBytes(ip6HeaderBytes + 2, 2));
}
// Next Header
@@ -353,7 +347,7 @@ Error Lowpan::Compress(Message & aMessage,
OT_FALL_THROUGH;
default:
SuccessOrExit(error = buf.Write(static_cast<uint8_t>(ip6Header.GetNextHeader())));
SuccessOrExit(error = aFrameBuilder.AppendUint8(static_cast<uint8_t>(ip6Header.GetNextHeader())));
break;
}
@@ -373,7 +367,7 @@ Error Lowpan::Compress(Message & aMessage,
break;
default:
SuccessOrExit(error = buf.Write(ip6Header.GetHopLimit()));
SuccessOrExit(error = aFrameBuilder.AppendUint8(ip6Header.GetHopLimit()));
break;
}
@@ -384,35 +378,37 @@ Error Lowpan::Compress(Message & aMessage,
}
else if (ip6Header.GetSource().IsLinkLocal())
{
SuccessOrExit(error = CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, buf));
SuccessOrExit(error = CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, aFrameBuilder));
}
else if (srcContextValid)
{
hcCtl |= kHcSrcAddrContext;
SuccessOrExit(error = CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, buf));
SuccessOrExit(error = CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, aFrameBuilder));
}
else
{
SuccessOrExit(error = buf.Write(ip6Header.GetSource().mFields.m8, sizeof(ip6Header.GetSource())));
SuccessOrExit(error = aFrameBuilder.Append(ip6Header.GetSource()));
}
// Destination Address
if (ip6Header.GetDestination().IsMulticast())
{
SuccessOrExit(error = CompressMulticast(ip6Header.GetDestination(), hcCtl, buf));
SuccessOrExit(error = CompressMulticast(ip6Header.GetDestination(), hcCtl, aFrameBuilder));
}
else if (ip6Header.GetDestination().IsLinkLocal())
{
SuccessOrExit(error = CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, buf));
SuccessOrExit(
error = CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, aFrameBuilder));
}
else if (dstContextValid)
{
hcCtl |= kHcDstAddrContext;
SuccessOrExit(error = CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, buf));
SuccessOrExit(
error = CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, aFrameBuilder));
}
else
{
SuccessOrExit(error = buf.Write(&ip6Header.GetDestination(), sizeof(ip6Header.GetDestination())));
SuccessOrExit(error = aFrameBuilder.Append(ip6Header.GetDestination()));
}
headerDepth++;
@@ -426,18 +422,18 @@ Error Lowpan::Compress(Message & aMessage,
switch (nextHeader)
{
case Ip6::kProtoHopOpts:
SuccessOrExit(error = CompressExtensionHeader(aMessage, buf, nextHeader));
SuccessOrExit(error = CompressExtensionHeader(aMessage, aFrameBuilder, nextHeader));
break;
case Ip6::kProtoUdp:
error = CompressUdp(aMessage, buf);
error = CompressUdp(aMessage, aFrameBuilder);
ExitNow();
case Ip6::kProtoIp6:
// For IP-in-IP the NH bit of the LOWPAN_NHC encoding MUST be set to zero.
SuccessOrExit(error = buf.Write(kExtHdrDispatch | kExtHdrEidIp6));
SuccessOrExit(error = aFrameBuilder.AppendUint8(kExtHdrDispatch | kExtHdrEidIp6));
error = Compress(aMessage, aMacSource, aMacDest, buf);
error = Compress(aMessage, aMacSource, aMacDest, aFrameBuilder);
OT_FALL_THROUGH;
@@ -453,9 +449,7 @@ exit:
if (error == kErrorNone)
{
IgnoreError(aBuf.Write(hcCtl >> 8));
IgnoreError(aBuf.Write(hcCtl & 0xff));
aBuf = buf;
aFrameBuilder.Write<uint16_t>(hcCtlOffset, HostSwap16(hcCtl));
}
else
{
@@ -465,10 +459,9 @@ exit:
return error;
}
Error Lowpan::CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uint8_t &aNextHeader)
Error Lowpan::CompressExtensionHeader(Message &aMessage, FrameBuilder &aFrameBuilder, uint8_t &aNextHeader)
{
Error error = kErrorNone;
BufferWriter buf = aBuf;
uint16_t startOffset = aMessage.GetOffset();
Ip6::ExtensionHeader extHeader;
uint16_t len;
@@ -488,12 +481,12 @@ Error Lowpan::CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uin
break;
default:
SuccessOrExit(error = buf.Write(tmpByte));
SuccessOrExit(error = aFrameBuilder.AppendUint8(tmpByte));
tmpByte = static_cast<uint8_t>(extHeader.GetNextHeader());
break;
}
SuccessOrExit(error = buf.Write(tmpByte));
SuccessOrExit(error = aFrameBuilder.AppendUint8(tmpByte));
len = (extHeader.GetLength() + 1) * 8 - sizeof(extHeader);
@@ -540,16 +533,12 @@ Error Lowpan::CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uin
aNextHeader = static_cast<uint8_t>(extHeader.GetNextHeader());
SuccessOrExit(error = buf.Write(static_cast<uint8_t>(len)));
SuccessOrExit(error = buf.Write(aMessage, static_cast<uint8_t>(len)));
SuccessOrExit(error = aFrameBuilder.AppendUint8(static_cast<uint8_t>(len)));
SuccessOrExit(error = aFrameBuilder.AppendBytesFromMessage(aMessage, aMessage.GetOffset(), len));
aMessage.MoveOffset(len + padLength);
exit:
if (error == kErrorNone)
{
aBuf = buf;
}
else
if (error != kErrorNone)
{
aMessage.SetOffset(startOffset);
}
@@ -557,10 +546,9 @@ exit:
return error;
}
Error Lowpan::CompressUdp(Message &aMessage, BufferWriter &aBuf)
Error Lowpan::CompressUdp(Message &aMessage, FrameBuilder &aFrameBuilder)
{
Error error = kErrorNone;
BufferWriter buf = aBuf;
uint16_t startOffset = aMessage.GetOffset();
Ip6::Udp::Header udpHeader;
uint16_t source;
@@ -573,40 +561,33 @@ Error Lowpan::CompressUdp(Message &aMessage, BufferWriter &aBuf)
if ((source & 0xfff0) == 0xf0b0 && (destination & 0xfff0) == 0xf0b0)
{
SuccessOrExit(error = buf.Write(kUdpDispatch | 3));
SuccessOrExit(error = buf.Write((((source & 0xf) << 4) | (destination & 0xf)) & 0xff));
SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch | 3));
SuccessOrExit(error = aFrameBuilder.AppendUint8((((source & 0xf) << 4) | (destination & 0xf)) & 0xff));
}
else if ((source & 0xff00) == 0xf000)
{
SuccessOrExit(error = buf.Write(kUdpDispatch | 2));
SuccessOrExit(error = buf.Write(source & 0xff));
SuccessOrExit(error = buf.Write(destination >> 8));
SuccessOrExit(error = buf.Write(destination & 0xff));
SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch | 2));
SuccessOrExit(error = aFrameBuilder.AppendUint8(source & 0xff));
SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(destination));
}
else if ((destination & 0xff00) == 0xf000)
{
SuccessOrExit(error = buf.Write(kUdpDispatch | 1));
SuccessOrExit(error = buf.Write(source >> 8));
SuccessOrExit(error = buf.Write(source & 0xff));
SuccessOrExit(error = buf.Write(destination & 0xff));
SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch | 1));
SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(source));
SuccessOrExit(error = aFrameBuilder.AppendUint8(destination & 0xff));
}
else
{
SuccessOrExit(error = buf.Write(kUdpDispatch));
SuccessOrExit(error = buf.Write(&udpHeader, Ip6::Udp::Header::kLengthFieldOffset));
SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch));
SuccessOrExit(error = aFrameBuilder.AppendBytes(&udpHeader, Ip6::Udp::Header::kLengthFieldOffset));
}
SuccessOrExit(error =
buf.Write(reinterpret_cast<uint8_t *>(&udpHeader) + Ip6::Udp::Header::kChecksumFieldOffset, 2));
SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(udpHeader.GetChecksum()));
aMessage.MoveOffset(sizeof(udpHeader));
exit:
if (error == kErrorNone)
{
aBuf = buf;
}
else
if (error != kErrorNone)
{
aMessage.SetOffset(startOffset);
}
+15 -149
View File
@@ -37,6 +37,7 @@
#include "openthread-core-config.h"
#include "common/debug.hpp"
#include "common/frame_builder.hpp"
#include "common/frame_data.hpp"
#include "common/locator.hpp"
#include "common/message.hpp"
@@ -79,144 +80,6 @@ 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, uint16_t aLength)
: mWritePointer(aBuf)
, mEndPointer(aBuf + 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 (mWritePointer + aLength) <= mEndPointer; }
/**
* 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 kErrorNone Enough buffer space is available to advance the requested number of bytes.
* @retval kErrorNoBufs Insufficient buffer space to advance the requested number of bytes.
*
*/
Error Advance(uint8_t aLength)
{
Error error = kErrorNone;
VerifyOrExit(CanWrite(aLength), error = kErrorNoBufs);
mWritePointer += 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 kErrorNone Successfully wrote the byte and updated the pointer.
* @retval kErrorNoBufs Insufficient buffer space to write the byte.
*
*/
Error Write(uint8_t aByte)
{
Error error = kErrorNone;
VerifyOrExit(CanWrite(sizeof(aByte)), error = kErrorNoBufs);
*mWritePointer++ = aByte;
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 kErrorNone Successfully wrote the byte sequence and updated the pointer.
* @retval kErrorNoBufs Insufficient buffer space to write the byte sequence.
*
*/
Error Write(const void *aBuf, uint8_t aLength)
{
Error error = kErrorNone;
VerifyOrExit(CanWrite(aLength), error = kErrorNoBufs);
memcpy(mWritePointer, aBuf, aLength);
mWritePointer += 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 kErrorNone Successfully wrote the byte sequence and updated the pointer.
* @retval kErrorNoBufs Insufficient buffer space to write the byte sequence.
*
*/
Error Write(const Message &aMessage, uint8_t aLength)
{
Error error = kErrorNone;
int rval;
OT_UNUSED_VARIABLE(rval);
VerifyOrExit(CanWrite(aLength), error = kErrorNoBufs);
rval = aMessage.ReadBytes(aMessage.GetOffset(), mWritePointer, aLength);
OT_ASSERT(rval == aLength);
mWritePointer += aLength;
exit:
return error;
}
private:
uint8_t *mWritePointer;
uint8_t *mEndPointer;
};
/**
* This class implements LOWPAN_IPHC header compression.
*
@@ -261,15 +124,18 @@ public:
/**
* This method compresses an IPv6 header.
*
* @param[in] aMessage A reference to the IPv6 message.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[out] aBuf A pointer where the compressed IPv6 header will be placed.
* @param[in] aMessage A reference to the IPv6 message.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[in] aFrameBuilder The `FrameBuilder` to use to append the compressed headers.
*
* @returns The size of the compressed header in bytes.
*
*/
Error Compress(Message &aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest, BufferWriter &aBuf);
Error Compress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
FrameBuilder & aFrameBuilder);
/**
* This method decompresses a LOWPAN_IPHC header.
@@ -405,22 +271,22 @@ private:
Error Compress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
BufferWriter & aBuf,
FrameBuilder & aFrameBuilder,
uint8_t & aHeaderDepth);
Error CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uint8_t &aNextHeader);
Error CompressExtensionHeader(Message &aMessage, FrameBuilder &aFrameBuilder, uint8_t &aNextHeader);
Error CompressSourceIid(const Mac::Address &aMacAddr,
const Ip6::Address &aIpAddr,
const Context & aContext,
uint16_t & aHcCtl,
BufferWriter & aBuf);
FrameBuilder & aFrameBuilder);
Error CompressDestinationIid(const Mac::Address &aMacAddr,
const Ip6::Address &aIpAddr,
const Context & aContext,
uint16_t & aHcCtl,
BufferWriter & aBuf);
Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf);
Error CompressUdp(Message &aMessage, BufferWriter &aBuf);
FrameBuilder & aFrameBuilder);
Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, FrameBuilder &aFrameBuilder);
Error CompressUdp(Message &aMessage, FrameBuilder &aFrameBuilder);
Error DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData);
Error DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength);
+7 -6
View File
@@ -963,10 +963,11 @@ start:
// Compress IPv6 Header
if (aMessage.GetOffset() == 0)
{
Lowpan::BufferWriter buffer(payload,
maxPayloadLength - headerLength - Lowpan::FragmentHeader::kFirstFragmentHeaderSize);
uint8_t hcLength;
Mac::Address meshSource, meshDest;
FrameBuilder frameBuilder;
uint8_t hcLength;
Mac::Address meshSource, meshDest;
frameBuilder.Init(payload, maxPayloadLength - headerLength - Lowpan::FragmentHeader::kFirstFragmentHeaderSize);
if (aAddMeshHeader)
{
@@ -979,9 +980,9 @@ start:
meshDest = aMacDest;
}
SuccessOrAssert(Get<Lowpan::Lowpan>().Compress(aMessage, meshSource, meshDest, buffer));
SuccessOrAssert(Get<Lowpan::Lowpan>().Compress(aMessage, meshSource, meshDest, frameBuilder));
hcLength = static_cast<uint8_t>(buffer.GetWritePointer() - payload);
hcLength = static_cast<uint8_t>(frameBuilder.GetLength());
headerLength += hcLength;
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
fragmentLength = maxPayloadLength - headerLength;
+21
View File
@@ -320,6 +320,27 @@ target_link_libraries(ot-test-flash
add_test(NAME ot-test-flash COMMAND ot-test-flash)
add_executable(ot-test-frame-builder
test_frame_builder.cpp
)
target_include_directories(ot-test-frame-builder
PRIVATE
${COMMON_INCLUDES}
)
target_compile_options(ot-test-frame-builder
PRIVATE
${COMMON_COMPILE_OPTIONS}
)
target_link_libraries(ot-test-frame-builder
PRIVATE
${COMMON_LIBS}
)
add_test(NAME ot-test-frame_builder COMMAND ot-test-frame-builder)
add_executable(ot-test-heap
test_heap.cpp
)
+5
View File
@@ -123,6 +123,7 @@ check_PROGRAMS += \
ot-test-dso \
ot-test-ecdsa \
ot-test-flash \
ot-test-frame-builder \
ot-test-heap \
ot-test-heap-array \
ot-test-heap-string \
@@ -240,6 +241,10 @@ ot_test_flash_LDADD = $(COMMON_LDADD)
ot_test_flash_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_flash_SOURCES = $(COMMON_SOURCES) test_flash.cpp
ot_test_frame_builder_LDADD = $(COMMON_LDADD)
ot_test_frame_builder_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_frame_builder_SOURCES = $(COMMON_SOURCES) test_frame_builder.cpp
ot_test_hdlc_LDADD = $(COMMON_LDADD)
ot_test_hdlc_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_hdlc_SOURCES = $(COMMON_SOURCES) test_hdlc.cpp
+150
View File
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2022, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <openthread/config.h>
#include "test_platform.h"
#include "test_util.hpp"
#include "common/frame_builder.hpp"
namespace ot {
void TestFrameBuilder(void)
{
const uint8_t kData1[] = {0x01, 0x02, 0x03, 0x04, 0x05};
const uint8_t kData2[] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa};
static constexpr uint16_t kMaxBufferSize = sizeof(kData1) * 2 + sizeof(kData2);
Instance * instance;
Message * message;
uint16_t offset;
uint8_t buffer[kMaxBufferSize];
uint8_t zeroBuffer[kMaxBufferSize];
FrameBuilder frameBuilder;
printf("TestFrameBuilder\n");
instance = static_cast<Instance *>(testInitInstance());
VerifyOrQuit(instance != nullptr);
message = instance->Get<MessagePool>().Allocate(Message::kTypeIp6);
VerifyOrQuit(message != nullptr);
SuccessOrQuit(message->Append(kData1));
SuccessOrQuit(message->Append(kData2));
memset(buffer, 0, sizeof(buffer));
memset(zeroBuffer, 0, sizeof(zeroBuffer));
frameBuilder.Init(buffer, sizeof(buffer));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(frameBuilder.GetLength() == 0);
VerifyOrQuit(frameBuilder.GetMaxLength() == sizeof(buffer));
VerifyOrQuit(memcmp(buffer, zeroBuffer, sizeof(buffer)) == 0);
VerifyOrQuit(frameBuilder.CanAppend(sizeof(buffer)));
VerifyOrQuit(!frameBuilder.CanAppend(sizeof(buffer) + 1));
SuccessOrQuit(frameBuilder.Append(kData1));
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
VerifyOrQuit(memcmp(buffer + sizeof(kData1), zeroBuffer, sizeof(buffer) - sizeof(kData1)) == 0);
SuccessOrQuit(frameBuilder.AppendUint8(0x01));
SuccessOrQuit(frameBuilder.AppendBigEndianUint16(0x0203));
SuccessOrQuit(frameBuilder.AppendLittleEndianUint16(0x0504));
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1) * 2);
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
VerifyOrQuit(memcmp(buffer + sizeof(kData1), kData1, sizeof(kData1)) == 0);
SuccessOrQuit(frameBuilder.AppendBigEndianUint32(0x01020304));
SuccessOrQuit(frameBuilder.AppendUint8(0x05));
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1) * 3);
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
VerifyOrQuit(memcmp(buffer + sizeof(kData1), kData1, sizeof(kData1)) == 0);
VerifyOrQuit(memcmp(buffer + 2 * sizeof(kData1), kData1, sizeof(kData1)) == 0);
frameBuilder.Init(buffer, sizeof(buffer));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(frameBuilder.GetLength() == 0);
VerifyOrQuit(frameBuilder.GetMaxLength() == sizeof(buffer));
offset = sizeof(kData1);
SuccessOrQuit(frameBuilder.AppendBytesFromMessage(*message, offset, sizeof(kData2)));
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData2));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(memcmp(buffer, kData2, sizeof(kData2)) == 0);
frameBuilder.Init(buffer, sizeof(buffer));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(frameBuilder.GetLength() == 0);
VerifyOrQuit(frameBuilder.GetMaxLength() == sizeof(buffer));
SuccessOrQuit(frameBuilder.AppendLittleEndianUint32(0x04030201));
SuccessOrQuit(frameBuilder.AppendUint8(0x05));
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
SuccessOrQuit(frameBuilder.AppendBytes(zeroBuffer, sizeof(kData2)));
SuccessOrQuit(frameBuilder.Append(kData1));
VerifyOrQuit(frameBuilder.GetLength() == sizeof(buffer));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
VerifyOrQuit(memcmp(buffer + sizeof(kData1), zeroBuffer, sizeof(kData2)) == 0);
VerifyOrQuit(memcmp(buffer + sizeof(kData1) + sizeof(kData2), kData1, sizeof(kData1)) == 0);
VerifyOrQuit(!frameBuilder.CanAppend(1));
VerifyOrQuit(frameBuilder.AppendUint8(0x00) == kErrorNoBufs);
offset = sizeof(kData1);
frameBuilder.Write(offset, kData2);
VerifyOrQuit(frameBuilder.GetLength() == sizeof(buffer));
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
VerifyOrQuit(memcmp(buffer + sizeof(kData1), kData2, sizeof(kData2)) == 0);
VerifyOrQuit(memcmp(buffer + sizeof(kData1) + sizeof(kData2), kData1, sizeof(kData1)) == 0);
message->Free();
testFreeInstance(instance);
}
} // namespace ot
int main(void)
{
ot::TestFrameBuilder();
printf("All tests passed\n");
return 0;
}
+7 -5
View File
@@ -171,20 +171,22 @@ static void Test(TestIphcVector &aVector, bool aCompress, bool aDecompress)
if (aCompress)
{
Lowpan::BufferWriter buffer(result, 127);
Message * compressedMsg;
Ip6::Ecn ecn;
FrameBuilder frameBuilder;
Message * compressedMsg;
Ip6::Ecn ecn;
frameBuilder.Init(result, 127);
VerifyOrQuit((message = sInstance->Get<MessagePool>().Allocate(Message::kTypeIp6)) != nullptr);
aVector.GetUncompressedStream(*message);
VerifyOrQuit(sLowpan->Compress(*message, aVector.mMacSource, aVector.mMacDestination, buffer) ==
VerifyOrQuit(sLowpan->Compress(*message, aVector.mMacSource, aVector.mMacDestination, frameBuilder) ==
aVector.mError);
if (aVector.mError == kErrorNone)
{
uint8_t compressBytes = static_cast<uint8_t>(buffer.GetWritePointer() - result);
uint16_t compressBytes = frameBuilder.GetLength();
// Append payload to the LOWPAN_IPHC.
message->ReadBytes(message->GetOffset(), result + compressBytes,