mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 15:47:46 +00:00
[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:
@@ -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 \
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user