[core] adding FrameData class for parsing frames (#7892)

This commit adds a new class `FrameData` which is a sub-class of
`Data` (acts as a wrapper over a buffer pointer and a length). It is
used in `MeshForwarder` and `Lowpan` to simplify the method calls
(can pass `FrameData` instance instead of pointer and length). It
also provides helper methods for parsing the frame content (e.g.,
reading `uint16/32` value assuming big or little endian encoding).
When read successfully, the `FrameData` is updated to skip over the
read content. These methods help simplify `Lowpan` parsing and
decompression code. In particular the `Lowpan` methods now directly
update the passed-in `FrameData` to skip over the parsed header
portion (instead of returning the parsed header length).
This commit is contained in:
Abtin Keshavarzian
2022-07-14 17:04:47 -07:00
committed by GitHub
parent 366786dbed
commit 13416b15fb
15 changed files with 736 additions and 411 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_data.cpp \
src/core/common/heap.cpp \
src/core/common/heap_data.cpp \
src/core/common/heap_string.cpp \
+2
View File
@@ -397,6 +397,8 @@ openthread_core_files = [
"common/error.cpp",
"common/error.hpp",
"common/extension.hpp",
"common/frame_data.cpp",
"common/frame_data.hpp",
"common/heap.cpp",
"common/heap.hpp",
"common/heap_allocatable.hpp",
+1
View File
@@ -97,6 +97,7 @@ set(COMMON_SOURCES
common/crc16.cpp
common/data.cpp
common/error.cpp
common/frame_data.cpp
common/heap.cpp
common/heap_data.cpp
common/heap_string.cpp
+2
View File
@@ -187,6 +187,7 @@ SOURCES_COMMON = \
common/crc16.cpp \
common/data.cpp \
common/error.cpp \
common/frame_data.cpp \
common/heap.cpp \
common/heap_data.cpp \
common/heap_string.cpp \
@@ -437,6 +438,7 @@ HEADERS_COMMON = \
common/equatable.hpp \
common/error.hpp \
common/extension.hpp \
common/frame_data.hpp \
common/heap.hpp \
common/heap_allocatable.hpp \
common/heap_array.hpp \
+107
View File
@@ -0,0 +1,107 @@
/*
* 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 includes implementation of `FrameData`.
*/
#include "frame_data.hpp"
#include "common/code_utils.hpp"
#include "common/encoding.hpp"
namespace ot {
Error FrameData::ReadUint8(uint8_t &aUint8)
{
return ReadBytes(&aUint8, sizeof(uint8_t));
}
Error FrameData::ReadBigEndianUint16(uint16_t &aUint16)
{
Error error;
SuccessOrExit(error = ReadBytes(&aUint16, sizeof(uint16_t)));
aUint16 = Encoding::BigEndian::HostSwap16(aUint16);
exit:
return error;
}
Error FrameData::ReadBigEndianUint32(uint32_t &aUint32)
{
Error error;
SuccessOrExit(error = ReadBytes(&aUint32, sizeof(uint32_t)));
aUint32 = Encoding::BigEndian::HostSwap32(aUint32);
exit:
return error;
}
Error FrameData::ReadLittleEndianUint16(uint16_t &aUint16)
{
Error error;
SuccessOrExit(error = ReadBytes(&aUint16, sizeof(uint16_t)));
aUint16 = Encoding::LittleEndian::HostSwap16(aUint16);
exit:
return error;
}
Error FrameData::ReadLittleEndianUint32(uint32_t &aUint32)
{
Error error;
SuccessOrExit(error = ReadBytes(&aUint32, sizeof(uint32_t)));
aUint32 = Encoding::LittleEndian::HostSwap32(aUint32);
exit:
return error;
}
Error FrameData::ReadBytes(void *aBuffer, uint16_t aLength)
{
Error error = kErrorNone;
VerifyOrExit(CanRead(aLength), error = kErrorParse);
memcpy(aBuffer, GetBytes(), aLength);
SkipOver(aLength);
exit:
return error;
}
void FrameData::SkipOver(uint16_t aLength)
{
Init(GetBytes() + aLength, GetLength() - aLength);
}
} // namespace ot
+177
View File
@@ -0,0 +1,177 @@
/*
* 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 includes definitions for `FrameData`.
*/
#ifndef FRAME_DATA_HPP_
#define FRAME_DATA_HPP_
#include "openthread-core-config.h"
#include "common/data.hpp"
#include "common/type_traits.hpp"
namespace ot {
/**
* This class represents a frame `Data` which is simply a wrapper over a pointer to a buffer with a given frame length.
*
* It provide helper method to parse the content. As data is parsed and read, the `FrameData` is updated to skip over
* the read content.
*
*/
class FrameData : public Data<kWithUint16Length>
{
public:
/**
* This method indicates whether or not there are enough bytes remaining in the `FrameData` to read a given number
* of bytes.
*
* @param[in] aLength The read length to check.
*
* @retval TRUE There are enough remaining bytes to read @p aLength bytes.
* @retval FALSE There are not enough remaining bytes to read @p aLength bytes.
*
*/
bool CanRead(uint16_t aLength) const { return GetLength() >= aLength; }
/**
* This method reads an `uint8_t` value from the `FrameData`.
*
* If read successfully, the `FrameData` is updated to skip over the read content.
*
* @param[out] aUint8 A reference to an `uint8_t` to return the read value.
*
* @retval kErrorNone Successfully read `uint8_t` value and skipped over it.
* @retval kErrorParse Not enough bytes remaining to read.
*
*/
Error ReadUint8(uint8_t &aUint8);
/**
* This method reads an `uint16_t` value assuming big endian encoding from the `FrameData`.
*
* If read successfully, the `FrameData` is updated to skip over the read content.
*
* @param[out] aUint16 A reference to an `uint16_t` to return the read value.
*
* @retval kErrorNone Successfully read `uint16_t` value and skipped over it.
* @retval kErrorParse Not enough bytes remaining to read.
*
*/
Error ReadBigEndianUint16(uint16_t &aUint16);
/**
* This method reads an `uint32_t` value assuming big endian encoding from the `FrameData`.
*
* If read successfully, the `FrameData` is updated to skip over the read content.
*
* @param[out] aUint32 A reference to an `uint32_t` to return the read value.
*
* @retval kErrorNone Successfully read `uint32_t` value and skipped over it.
* @retval kErrorParse Not enough bytes remaining to read.
*
*/
Error ReadBigEndianUint32(uint32_t &aUint32);
/**
* This method reads an `uint16_t` value assuming little endian encoding from the `FrameData`.
*
* If read successfully, the `FrameData` is updated to skip over the read content.
*
* @param[out] aUint16 A reference to an `uint16_t` to return the read value.
*
* @retval kErrorNone Successfully read `uint16_t` value and skipped over it.
* @retval kErrorParse Not enough bytes remaining to read.
*
*/
Error ReadLittleEndianUint16(uint16_t &aUint16);
/**
* This method reads an `uint32_t` value assuming little endian encoding from the `FrameData`.
*
* If read successfully, the `FrameData` is updated to skip over the read content.
*
* @param[out] aUint32 A reference to an `uint32_t` to return the read value.
*
* @retval kErrorNone Successfully read `uint32_t` value and skipped over it.
* @retval kErrorParse Not enough bytes remaining to read.
*
*/
Error ReadLittleEndianUint32(uint32_t &aUint32);
/**
* This method reads a given number of bytes from the `FrameData`.
*
* If read successfully, the `FrameData` is updated to skip over the read content.
*
* @param[out] aBuffer The buffer to copy the read bytes into.
* @param[in] aLength Number of bytes to read.
*
* @retval kErrorNone Successfully read @p aLength bytes into @p aBuffer and skipped over them.
* @retval kErrorParse Not enough bytes remaining to read @p aLength.
*
*/
Error ReadBytes(void *aBuffer, uint16_t aLength);
/**
* This template method reads an object from the `FrameData`.
*
* @tparam ObjectType The object type to read from the message.
*
* @param[out] aObject A reference to the object to read into.
*
* @retval kErrorNone Successfully read @p aObject and skipped over the read content.
* @retval kErrorParse Not enough bytes remaining to read the entire object.
*
*/
template <typename ObjectType> Error Read(ObjectType &aObject)
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
return ReadBytes(&aObject, sizeof(ObjectType));
}
/**
* This method skips over a given number of bytes from `FrameData`.
*
* The caller MUST make sure that the @p aLength is smaller than current data length. Otherwise the behavior of
* this method is undefined.
*
* @param[in] aLength The length (number of bytes) to skip over.
*
*/
void SkipOver(uint16_t aLength);
};
} // namespace ot
#endif // FRAME_DATA_HPP_
+35
View File
@@ -662,6 +662,24 @@ public:
return AppendBytes(&aObject, sizeof(ObjectType));
}
/**
* This method appends bytes from a given `Data` instance to the end of the message.
*
* On success, this method grows the message by the size of the appended data.
*
* @tparam kDataLengthType Determines the data length type (`uint8_t` or `uint16_t`).
*
* @param[in] aData A reference to `Data` to append to the message.
*
* @retval kErrorNone Successfully appended the bytes from @p aData.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*
*/
template <DataLengthType kDataLengthType> Error AppendData(const Data<kDataLengthType> &aData)
{
return AppendBytes(aData.GetBytes(), aData.GetLength());
}
/**
* This method reads bytes from the message.
*
@@ -807,6 +825,23 @@ public:
WriteBytes(aOffset, &aObject, sizeof(ObjectType));
}
/**
* This method writes bytes from a given `Data` instance to the message.
*
* This method will not resize the message. The given data to write MUST fit within the existing message buffer
* (from the given offset @p aOffset up to the message's length).
*
* @tparam kDataLengthType Determines the data length type (`uint8_t` or `uint16_t`).
*
* @param[in] aOffset Byte offset within the message to begin writing.
* @param[in] aData The `Data` to write to the message.
*
*/
template <DataLengthType kDataLengthType> void WriteData(uint16_t aOffset, const Data<kDataLengthType> &aData)
{
WriteBytes(aOffset, aData.GetBytes(), aData.GetLength());
}
/**
* This method copies bytes from one message to another.
*
+16 -26
View File
@@ -1534,66 +1534,56 @@ Error Headers::DecompressFrom(const Message & aMessage,
{
static constexpr uint16_t kReadLength = Lowpan::FragmentHeader::kSubsequentFragmentHeaderSize + sizeof(Headers);
uint8_t frameBuffer[kReadLength];
uint16_t frameLength;
uint8_t frameBuffer[kReadLength];
uint16_t frameLength;
FrameData frameData;
frameLength = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(frameBuffer));
frameData.Init(frameBuffer, frameLength);
return DecompressFrom(frameBuffer, frameLength, aMacSource, aMacDest, aMessage.GetInstance());
return DecompressFrom(frameData, aMacSource, aMacDest, aMessage.GetInstance());
}
Error Headers::DecompressFrom(const uint8_t * aFrame,
uint16_t aFrameLength,
Error Headers::DecompressFrom(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Instance & aInstance)
{
Error error = kErrorNone;
Error error = kErrorNone;
FrameData frameData = aFrameData;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
int headerLength;
bool nextHeaderCompressed;
if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone)
if (fragmentHeader.ParseFrom(frameData) == kErrorNone)
{
// Only the first fragment header is followed by a LOWPAN_IPHC header
VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = kErrorNotFound);
aFrame += fragmentHeaderLength;
aFrameLength -= fragmentHeaderLength;
}
VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = kErrorNotFound);
headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressBaseHeader(mIp6Header, nextHeaderCompressed, aMacSource,
aMacDest, aFrame, aFrameLength);
VerifyOrExit(Lowpan::Lowpan::IsLowpanHc(frameData), error = kErrorNotFound);
VerifyOrExit(headerLength > 0, error = kErrorParse);
aFrame += headerLength;
aFrameLength -= headerLength;
SuccessOrExit(error = aInstance.Get<Lowpan::Lowpan>().DecompressBaseHeader(mIp6Header, nextHeaderCompressed,
aMacSource, aMacDest, frameData));
switch (mIp6Header.GetNextHeader())
{
case kProtoUdp:
if (nextHeaderCompressed)
{
headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressUdpHeader(mHeader.mUdp, aFrame, aFrameLength);
VerifyOrExit(headerLength >= 0, error = kErrorParse);
SuccessOrExit(error = aInstance.Get<Lowpan::Lowpan>().DecompressUdpHeader(mHeader.mUdp, frameData));
}
else
{
VerifyOrExit(aFrameLength >= sizeof(Udp::Header), error = kErrorParse);
mHeader.mUdp = *reinterpret_cast<const Udp::Header *>(aFrame);
SuccessOrExit(error = frameData.Read(mHeader.mUdp));
}
break;
case kProtoTcp:
VerifyOrExit(aFrameLength >= sizeof(Tcp::Header), error = kErrorParse);
mHeader.mTcp = *reinterpret_cast<const Tcp::Header *>(aFrame);
SuccessOrExit(error = frameData.Read(mHeader.mTcp));
break;
case kProtoIcmp6:
VerifyOrExit(aFrameLength >= sizeof(Icmp::Header), error = kErrorParse);
mHeader.mIcmp = *reinterpret_cast<const Icmp::Header *>(aFrame);
SuccessOrExit(error = frameData.Read(mHeader.mIcmp));
break;
default:
+3 -4
View File
@@ -42,6 +42,7 @@
#include <openthread/udp.h>
#include "common/encoding.hpp"
#include "common/frame_data.hpp"
#include "common/locator.hpp"
#include "common/log.hpp"
#include "common/message.hpp"
@@ -416,8 +417,7 @@ public:
/**
* This method decompresses lowpan frame and parses the IPv6 and UDP/TCP/ICMP6 headers.
*
* @param[in] aFrame Buffer containig the lowpan frame.
* @param[in] aFrameLength Number of bytes in @p aFrame.
* @param[in] aFrameData The lowpan frame data.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[in] aInstance The OpenThread instance.
@@ -427,8 +427,7 @@ public:
* @retval kErrorParse Failed to parse the headers.
*
*/
Error DecompressFrom(const uint8_t * aFrame,
uint16_t aFrameLength,
Error DecompressFrom(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Instance & aInstance);
+156 -185
View File
@@ -655,26 +655,21 @@ exit:
return error;
}
int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
bool & aCompressedNextHeader,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
const uint8_t * aBuf,
uint16_t aBufLength)
Error Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
bool & aCompressedNextHeader,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
FrameData & aFrameData)
{
NetworkData::Leader &networkData = Get<NetworkData::Leader>();
Error error = kErrorParse;
const uint8_t * cur = aBuf;
const uint8_t * end = aBuf + aBufLength;
uint16_t hcCtl;
uint8_t byte;
Context srcContext, dstContext;
bool srcContextValid = true, dstContextValid = true;
uint8_t nextHeader;
uint8_t * bytes;
VerifyOrExit(cur + 2 <= end);
hcCtl = ReadUint16(cur);
cur += 2;
SuccessOrExit(aFrameData.ReadBigEndianUint16(hcCtl));
// check Dispatch bits
VerifyOrExit((hcCtl & kHcDispatchMask) == kHcDispatch);
@@ -685,19 +680,17 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
if ((hcCtl & kHcContextId) != 0)
{
VerifyOrExit(cur < end);
SuccessOrExit(aFrameData.ReadUint8(byte));
if (networkData.GetContext(cur[0] >> 4, srcContext) != kErrorNone)
if (networkData.GetContext(byte >> 4, srcContext) != kErrorNone)
{
srcContextValid = false;
}
if (networkData.GetContext(cur[0] & 0xf, dstContext) != kErrorNone)
if (networkData.GetContext(byte & 0xf, dstContext) != kErrorNone)
{
dstContextValid = false;
}
cur++;
}
else
{
@@ -711,34 +704,35 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
// Traffic Class and Flow Label
if ((hcCtl & kHcTrafficFlowMask) != kHcTrafficFlow)
{
VerifyOrExit(cur < end);
uint8_t *ip6HeaderBytes = reinterpret_cast<uint8_t *>(&aIp6Header);
bytes = reinterpret_cast<uint8_t *>(&aIp6Header);
bytes[1] |= (cur[0] & 0xc0) >> 2;
VerifyOrExit(aFrameData.GetLength() > 0);
ip6HeaderBytes[1] |= (aFrameData.GetBytes()[0] & 0xc0) >> 2;
if ((hcCtl & kHcTrafficClass) == 0)
{
bytes[0] |= (cur[0] >> 2) & 0x0f;
bytes[1] |= (cur[0] << 6) & 0xc0;
cur++;
IgnoreError(aFrameData.ReadUint8(byte));
ip6HeaderBytes[0] |= (byte >> 2) & 0x0f;
ip6HeaderBytes[1] |= (byte << 6) & 0xc0;
}
if ((hcCtl & kHcFlowLabel) == 0)
{
VerifyOrExit(cur + 3 <= end);
bytes[1] |= cur[0] & 0x0f;
bytes[2] |= cur[1];
bytes[3] |= cur[2];
cur += 3;
VerifyOrExit(aFrameData.GetLength() >= 3);
ip6HeaderBytes[1] |= aFrameData.GetBytes()[0] & 0x0f;
ip6HeaderBytes[2] |= aFrameData.GetBytes()[1];
ip6HeaderBytes[3] |= aFrameData.GetBytes()[2];
aFrameData.SkipOver(3);
}
}
// Next Header
if ((hcCtl & kHcNextHeader) == 0)
{
VerifyOrExit(cur < end);
aIp6Header.SetNextHeader(cur[0]);
cur++;
SuccessOrExit(aFrameData.ReadUint8(byte));
aIp6Header.SetNextHeader(byte);
aCompressedNextHeader = false;
}
else
@@ -762,9 +756,8 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
break;
default:
VerifyOrExit(cur < end);
aIp6Header.SetHopLimit(cur[0]);
cur++;
SuccessOrExit(aFrameData.ReadUint8(byte));
aIp6Header.SetHopLimit(byte);
break;
}
@@ -774,25 +767,19 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
case kHcSrcAddrMode0:
if ((hcCtl & kHcSrcAddrContext) == 0)
{
VerifyOrExit(cur + sizeof(Ip6::Address) <= end);
memcpy(&aIp6Header.GetSource(), cur, sizeof(aIp6Header.GetSource()));
cur += sizeof(Ip6::Address);
SuccessOrExit(aFrameData.Read(aIp6Header.GetSource()));
}
break;
case kHcSrcAddrMode1:
VerifyOrExit(cur + Ip6::InterfaceIdentifier::kSize <= end);
aIp6Header.GetSource().GetIid().SetBytes(cur);
cur += Ip6::InterfaceIdentifier::kSize;
SuccessOrExit(aFrameData.Read(aIp6Header.GetSource().GetIid()));
break;
case kHcSrcAddrMode2:
VerifyOrExit(cur + 2 <= end);
aIp6Header.GetSource().mFields.m8[11] = 0xff;
aIp6Header.GetSource().mFields.m8[12] = 0xfe;
memcpy(aIp6Header.GetSource().mFields.m8 + 14, cur, 2);
cur += 2;
SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetSource().mFields.m8 + 14, 2));
break;
case kHcSrcAddrMode3:
@@ -821,23 +808,17 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
{
case kHcDstAddrMode0:
VerifyOrExit((hcCtl & kHcDstAddrContext) == 0);
VerifyOrExit(cur + sizeof(Ip6::Address) <= end);
memcpy(&aIp6Header.GetDestination(), cur, sizeof(aIp6Header.GetDestination()));
cur += sizeof(Ip6::Address);
SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination()));
break;
case kHcDstAddrMode1:
VerifyOrExit(cur + Ip6::InterfaceIdentifier::kSize <= end);
aIp6Header.GetDestination().GetIid().SetBytes(cur);
cur += Ip6::InterfaceIdentifier::kSize;
SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination().GetIid()));
break;
case kHcDstAddrMode2:
VerifyOrExit(cur + 2 <= end);
aIp6Header.GetDestination().mFields.m8[11] = 0xff;
aIp6Header.GetDestination().mFields.m8[12] = 0xfe;
memcpy(aIp6Header.GetDestination().mFields.m8 + 14, cur, 2);
cur += 2;
SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 14, 2));
break;
case kHcDstAddrMode3:
@@ -869,30 +850,22 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
switch (hcCtl & kHcDstAddrModeMask)
{
case kHcDstAddrMode0:
VerifyOrExit(cur + sizeof(Ip6::Address) <= end);
memcpy(aIp6Header.GetDestination().mFields.m8, cur, sizeof(Ip6::Address));
cur += sizeof(Ip6::Address);
SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination()));
break;
case kHcDstAddrMode1:
VerifyOrExit(cur + 6 <= end);
aIp6Header.GetDestination().mFields.m8[1] = cur[0];
memcpy(aIp6Header.GetDestination().mFields.m8 + 11, cur + 1, 5);
cur += 6;
SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[1]));
SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 11, 5));
break;
case kHcDstAddrMode2:
VerifyOrExit(cur + 4 <= end);
aIp6Header.GetDestination().mFields.m8[1] = cur[0];
memcpy(aIp6Header.GetDestination().mFields.m8 + 13, cur + 1, 3);
cur += 4;
SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[1]));
SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 13, 3));
break;
case kHcDstAddrMode3:
VerifyOrExit(cur < end);
aIp6Header.GetDestination().mFields.m8[1] = 0x02;
aIp6Header.GetDestination().mFields.m8[15] = cur[0];
cur++;
aIp6Header.GetDestination().mFields.m8[1] = 0x02;
SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[15]));
break;
}
}
@@ -901,14 +874,11 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
switch (hcCtl & kHcDstAddrModeMask)
{
case 0:
VerifyOrExit(cur + 6 <= end);
VerifyOrExit(dstContextValid);
aIp6Header.GetDestination().mFields.m8[1] = cur[0];
aIp6Header.GetDestination().mFields.m8[2] = cur[1];
SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 1, 2));
aIp6Header.GetDestination().mFields.m8[3] = dstContext.mPrefix.GetLength();
memcpy(aIp6Header.GetDestination().mFields.m8 + 4, dstContext.mPrefix.GetBytes(), 8);
memcpy(aIp6Header.GetDestination().mFields.m8 + 12, cur + 2, 4);
cur += 6;
SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 12, 4));
break;
default:
@@ -919,54 +889,41 @@ int Lowpan::DecompressBaseHeader(Ip6::Header & aIp6Header,
if ((hcCtl & kHcNextHeader) != 0)
{
VerifyOrExit(cur < end);
SuccessOrExit(DispatchToNextHeader(cur[0], nextHeader));
VerifyOrExit(aFrameData.GetLength() > 0);
SuccessOrExit(DispatchToNextHeader(*aFrameData.GetBytes(), nextHeader));
aIp6Header.SetNextHeader(nextHeader);
}
error = kErrorNone;
exit:
return (error == kErrorNone) ? static_cast<int>(cur - aBuf) : -1;
return error;
}
int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength)
Error Lowpan::DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData)
{
Error error = kErrorParse;
const uint8_t * cur = aBuf;
const uint8_t * end = aBuf + aBufLength;
uint8_t hdr[2];
uint8_t len;
uint8_t nextHeader;
uint8_t ctl = cur[0];
uint8_t padLength;
Ip6::OptionPad1 optionPad1;
Ip6::OptionPadN optionPadN;
Error error = kErrorParse;
uint8_t hdr[2];
uint8_t len;
uint8_t ctl;
uint8_t padLength;
VerifyOrExit(cur < end);
cur++;
SuccessOrExit(aFrameData.ReadUint8(ctl));
// next header
if (ctl & kExtHdrNextHeader)
{
VerifyOrExit(cur < end);
SuccessOrExit(aFrameData.ReadUint8(len));
len = cur[0];
cur++;
VerifyOrExit(cur + len <= end);
SuccessOrExit(DispatchToNextHeader(cur[len], nextHeader));
hdr[0] = static_cast<uint8_t>(nextHeader);
VerifyOrExit(aFrameData.CanRead(len + 1));
SuccessOrExit(DispatchToNextHeader(aFrameData.GetBytes()[len], hdr[0]));
}
else
{
VerifyOrExit(cur + 2 <= end);
SuccessOrExit(aFrameData.ReadUint8(hdr[0]));
SuccessOrExit(aFrameData.ReadUint8(len));
hdr[0] = cur[0];
len = cur[1];
cur += 2;
VerifyOrExit(cur + len <= end);
VerifyOrExit(aFrameData.CanRead(len));
}
// length
@@ -976,9 +933,9 @@ int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, ui
aMessage.MoveOffset(sizeof(hdr));
// payload
SuccessOrExit(aMessage.AppendBytes(cur, len));
SuccessOrExit(aMessage.AppendBytes(aFrameData.GetBytes(), len));
aMessage.MoveOffset(len);
cur += len;
aFrameData.SkipOver(len);
// The RFC6282 says: "The trailing Pad1 or PadN option MAY be elided by the compressor.
// A decompressor MUST ensure that the containing header is padded out to a multiple of 8 octets
@@ -989,11 +946,15 @@ int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, ui
{
if (padLength == 1)
{
Ip6::OptionPad1 optionPad1;
optionPad1.Init();
SuccessOrExit(aMessage.AppendBytes(&optionPad1, padLength));
}
else
{
Ip6::OptionPadN optionPadN;
optionPadN.Init(padLength);
SuccessOrExit(aMessage.AppendBytes(&optionPadN, padLength));
}
@@ -1004,163 +965,145 @@ int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, ui
error = kErrorNone;
exit:
return (error == kErrorNone) ? static_cast<int>(cur - aBuf) : -1;
return error;
}
int Lowpan::DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength)
Error Lowpan::DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData)
{
Error error = kErrorParse;
const uint8_t *cur = aBuf;
const uint8_t *end = aBuf + aBufLength;
uint8_t udpCtl;
Error error = kErrorParse;
uint8_t udpCtl;
uint8_t byte;
uint16_t srcPort = 0;
uint16_t dstPort = 0;
VerifyOrExit(cur < end);
udpCtl = cur[0];
cur++;
SuccessOrExit(aFrameData.ReadUint8(udpCtl));
VerifyOrExit((udpCtl & kUdpDispatchMask) == kUdpDispatch);
memset(&aUdpHeader, 0, sizeof(aUdpHeader));
aUdpHeader.Clear();
// source and dest ports
switch (udpCtl & kUdpPortMask)
{
case 0:
VerifyOrExit(cur + 4 <= end);
aUdpHeader.SetSourcePort(ReadUint16(cur));
aUdpHeader.SetDestinationPort(ReadUint16(cur + 2));
cur += 4;
SuccessOrExit(aFrameData.ReadBigEndianUint16(srcPort));
SuccessOrExit(aFrameData.ReadBigEndianUint16(dstPort));
break;
case 1:
VerifyOrExit(cur + 3 <= end);
aUdpHeader.SetSourcePort(ReadUint16(cur));
aUdpHeader.SetDestinationPort(0xf000 | cur[2]);
cur += 3;
SuccessOrExit(aFrameData.ReadBigEndianUint16(srcPort));
SuccessOrExit(aFrameData.ReadUint8(byte));
dstPort = (0xf000 | byte);
break;
case 2:
VerifyOrExit(cur + 3 <= end);
aUdpHeader.SetSourcePort(0xf000 | cur[0]);
aUdpHeader.SetDestinationPort(ReadUint16(cur + 1));
cur += 3;
SuccessOrExit(aFrameData.ReadUint8(byte));
srcPort = (0xf000 | byte);
SuccessOrExit(aFrameData.ReadBigEndianUint16(dstPort));
break;
case 3:
VerifyOrExit(cur < end);
aUdpHeader.SetSourcePort(0xf0b0 | (cur[0] >> 4));
aUdpHeader.SetDestinationPort(0xf0b0 | (cur[0] & 0xf));
cur++;
SuccessOrExit(aFrameData.ReadUint8(byte));
srcPort = (0xf0b0 | (byte >> 4));
dstPort = (0xf0b0 | (byte & 0xf));
break;
}
// checksum
aUdpHeader.SetSourcePort(srcPort);
aUdpHeader.SetDestinationPort(dstPort);
if ((udpCtl & kUdpChecksum) != 0)
{
ExitNow();
}
else
{
VerifyOrExit(cur + 2 <= end);
aUdpHeader.SetChecksum(ReadUint16(cur));
cur += 2;
uint16_t checksum;
SuccessOrExit(aFrameData.ReadBigEndianUint16(checksum));
aUdpHeader.SetChecksum(checksum);
}
error = kErrorNone;
exit:
return (error == kErrorNone) ? static_cast<int>(cur - aBuf) : -1;
return error;
}
int Lowpan::DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength)
Error Lowpan::DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength)
{
Error error;
Ip6::Udp::Header udpHeader;
int headerLen = -1;
headerLen = DecompressUdpHeader(udpHeader, aBuf, aBufLength);
VerifyOrExit(headerLen >= 0);
SuccessOrExit(error = DecompressUdpHeader(udpHeader, aFrameData));
// length
if (aDatagramLength == 0)
{
udpHeader.SetLength(sizeof(udpHeader) + static_cast<uint16_t>(aBufLength - headerLen));
udpHeader.SetLength(sizeof(udpHeader) + aFrameData.GetLength());
}
else
{
udpHeader.SetLength(aDatagramLength - aMessage.GetOffset());
}
VerifyOrExit(aMessage.Append(udpHeader) == kErrorNone, headerLen = -1);
SuccessOrExit(error = aMessage.Append(udpHeader));
aMessage.MoveOffset(sizeof(udpHeader));
exit:
return headerLen;
return error;
}
int Lowpan::Decompress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
const uint8_t * aBuf,
uint16_t aBufLength,
uint16_t aDatagramLength)
Error Lowpan::Decompress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
FrameData & aFrameData,
uint16_t aDatagramLength)
{
Error error = kErrorParse;
Ip6::Header ip6Header;
const uint8_t *cur = aBuf;
uint16_t remaining = aBufLength;
bool compressed;
int rval;
uint16_t ip6PayloadLength;
uint16_t compressedLength = 0;
uint16_t currentOffset = aMessage.GetOffset();
Error error = kErrorParse;
Ip6::Header ip6Header;
bool compressed;
uint16_t ip6PayloadLength;
uint16_t currentOffset = aMessage.GetOffset();
VerifyOrExit(remaining >= 2);
VerifyOrExit((rval = DecompressBaseHeader(ip6Header, compressed, aMacSource, aMacDest, cur, remaining)) >= 0);
cur += rval;
remaining -= rval;
SuccessOrExit(DecompressBaseHeader(ip6Header, compressed, aMacSource, aMacDest, aFrameData));
SuccessOrExit(aMessage.Append(ip6Header));
aMessage.MoveOffset(sizeof(ip6Header));
while (compressed)
{
VerifyOrExit(remaining >= 1);
uint8_t byte;
if ((cur[0] & kExtHdrDispatchMask) == kExtHdrDispatch)
VerifyOrExit(aFrameData.GetLength() > 0);
byte = *aFrameData.GetBytes();
if ((byte & kExtHdrDispatchMask) == kExtHdrDispatch)
{
if ((cur[0] & kExtHdrEidMask) == kExtHdrEidIp6)
if ((byte & kExtHdrEidMask) == kExtHdrEidIp6)
{
compressed = false;
cur++;
remaining--;
aFrameData.SkipOver(sizeof(uint8_t));
VerifyOrExit((rval = Decompress(aMessage, aMacSource, aMacDest, cur, remaining, aDatagramLength)) >= 0);
SuccessOrExit(Decompress(aMessage, aMacSource, aMacDest, aFrameData, aDatagramLength));
}
else
{
compressed = (cur[0] & kExtHdrNextHeader) != 0;
VerifyOrExit((rval = DecompressExtensionHeader(aMessage, cur, remaining)) >= 0);
compressed = (byte & kExtHdrNextHeader) != 0;
SuccessOrExit(DecompressExtensionHeader(aMessage, aFrameData));
}
}
else if ((cur[0] & kUdpDispatchMask) == kUdpDispatch)
else if ((byte & kUdpDispatchMask) == kUdpDispatch)
{
compressed = false;
VerifyOrExit((rval = DecompressUdpHeader(aMessage, cur, remaining, aDatagramLength)) >= 0);
SuccessOrExit(DecompressUdpHeader(aMessage, aFrameData, aDatagramLength));
}
else
{
ExitNow();
}
VerifyOrExit(remaining >= rval);
cur += rval;
remaining -= rval;
}
compressedLength = static_cast<uint16_t>(cur - aBuf);
if (aDatagramLength)
{
ip6PayloadLength = HostSwap16(aDatagramLength - currentOffset - sizeof(Ip6::Header));
@@ -1168,7 +1111,7 @@ int Lowpan::Decompress(Message & aMessage,
else
{
ip6PayloadLength =
HostSwap16(aMessage.GetOffset() - currentOffset - sizeof(Ip6::Header) + aBufLength - compressedLength);
HostSwap16(aMessage.GetOffset() - currentOffset - sizeof(Ip6::Header) + aFrameData.GetLength());
}
aMessage.Write(currentOffset + Ip6::Header::kPayloadLengthFieldOffset, ip6PayloadLength);
@@ -1176,7 +1119,7 @@ int Lowpan::Decompress(Message & aMessage,
error = kErrorNone;
exit:
return (error == kErrorNone) ? static_cast<int>(compressedLength) : -1;
return error;
}
Ip6::Ecn Lowpan::DecompressEcn(const Message &aMessage, uint16_t aOffset) const
@@ -1229,9 +1172,21 @@ void MeshHeader::Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft
mHopsLeft = aHopsLeft;
}
bool MeshHeader::IsMeshHeader(const uint8_t *aFrame, uint16_t aFrameLength)
bool MeshHeader::IsMeshHeader(const FrameData &aFrameData)
{
return (aFrameLength >= kMinHeaderLength) && ((*aFrame & kDispatchMask) == kDispatch);
return (aFrameData.GetLength() >= kMinHeaderLength) && ((*aFrameData.GetBytes() & kDispatchMask) == kDispatch);
}
Error MeshHeader::ParseFrom(FrameData &aFrameData)
{
Error error;
uint16_t headerLength;
SuccessOrExit(error = ParseFrom(aFrameData.GetBytes(), aFrameData.GetLength(), headerLength));
aFrameData.SkipOver(headerLength);
exit:
return error;
}
Error MeshHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength)
@@ -1320,15 +1275,14 @@ uint16_t MeshHeader::WriteTo(uint8_t *aFrame) const
return static_cast<uint16_t>(cur - aFrame);
}
uint16_t MeshHeader::WriteTo(Message &aMessage, uint16_t aOffset) const
Error MeshHeader::AppendTo(Message &aMessage) const
{
uint8_t frame[kDeepHopsHeaderLength];
uint16_t headerLength;
headerLength = WriteTo(frame);
aMessage.WriteBytes(aOffset, frame, headerLength);
return headerLength;
return aMessage.AppendBytes(frame, headerLength);
}
//---------------------------------------------------------------------------------------------------------------------
@@ -1341,11 +1295,28 @@ void FragmentHeader::Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset)
mOffset = (aOffset & kOffsetMask);
}
bool FragmentHeader::IsFragmentHeader(const FrameData &aFrameData)
{
return IsFragmentHeader(aFrameData.GetBytes(), aFrameData.GetLength());
}
bool FragmentHeader::IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength)
{
return (aFrameLength >= kFirstFragmentHeaderSize) && ((*aFrame & kDispatchMask) == kDispatch);
}
Error FragmentHeader::ParseFrom(FrameData &aFrameData)
{
Error error;
uint16_t headerLength;
SuccessOrExit(error = ParseFrom(aFrameData.GetBytes(), aFrameData.GetLength(), headerLength));
aFrameData.SkipOver(headerLength);
exit:
return error;
}
Error FragmentHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength)
{
Error error = kErrorParse;
+90 -43
View File
@@ -37,6 +37,7 @@
#include "openthread-core-config.h"
#include "common/debug.hpp"
#include "common/frame_data.hpp"
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/non_copyable.hpp"
@@ -244,6 +245,19 @@ public:
return (aHeader[0] & (Lowpan::kHcDispatchMask >> 8)) == (Lowpan::kHcDispatch >> 8);
}
/**
* This method indicates whether or not header in a given frame is a LOWPAN_IPHC header.
*
* @param[in] aFrameData The frame data.
*
* @retval TRUE If the header matches the LOWPAN_IPHC dispatch value.
* @retval FALSE If the header does not match the LOWPAN_IPHC dispatch value.
*/
static bool IsLowpanHc(const FrameData &aFrameData)
{
return (aFrameData.GetLength() > 0) && IsLowpanHc(aFrameData.GetBytes());
}
/**
* This method compresses an IPv6 header.
*
@@ -260,54 +274,59 @@ public:
/**
* This method decompresses a LOWPAN_IPHC header.
*
* @param[out] aMessage A reference where the IPv6 header will be placed.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[in] aBuf A pointer to the LOWPAN_IPHC header.
* @param[in] aBufLength The number of bytes in @p aBuf.
* @param[in] aDatagramLength The IPv6 datagram length.
* If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
*
* @returns The size of the compressed header in bytes.
* @param[out] aMessage A reference where the IPv6 header will be placed.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[in,out] aFrameData A frame data containing the LOWPAN_IPHC header.
* @param[in] aDatagramLength The IPv6 datagram length.
*
* @retval kErrorNone The header was decompressed successfully. @p aMessage and @p aFrameData are updated.
* @retval kErrorParse Failed to parse the lowpan header.
* @retval kErrorNoBufs Could not grow @p aMessage to write the parsed IPv6 header.
*
*/
int Decompress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
const uint8_t * aBuf,
uint16_t aBufLength,
uint16_t aDatagramLength);
Error Decompress(Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
FrameData & aFrameData,
uint16_t aDatagramLength);
/**
* This method decompresses a LOWPAN_IPHC header.
*
* @param[out] aIp6Header A reference where the IPv6 header will be placed.
* @param[out] aCompressedNextHeader A boolean reference to output whether next header is compressed or not.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[in] aBuf A pointer to the LOWPAN_IPHC header.
* @param[in] aBufLength The number of bytes in @p aBuf.
* If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
*
* @returns The size of the compressed header in bytes or -1 if decompression fails.
* @param[out] aIp6Header A reference where the IPv6 header will be placed.
* @param[out] aCompressedNextHeader A boolean reference to output whether next header is compressed or not.
* @param[in] aMacSource The MAC source address.
* @param[in] aMacDest The MAC destination address.
* @param[in,out] aFrameData A frame data containing the LOWPAN_IPHC header.
*
* @retval kErrorNone The header was decompressed successfully. @p aIp6Headre and @p aFrameData are updated.
* @retval kErrorParse Failed to parse the lowpan header.
*
*/
int DecompressBaseHeader(Ip6::Header & aIp6Header,
bool & aCompressedNextHeader,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
const uint8_t * aBuf,
uint16_t aBufLength);
Error DecompressBaseHeader(Ip6::Header & aIp6Header,
bool & aCompressedNextHeader,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
FrameData & aFrameData);
/**
* This method decompresses a LOWPAN_NHC UDP header.
*
* @param[out] aUdpHeader A reference where the UDP header will be placed.
* @param[in] aBuf A pointer to the LOWPAN_NHC header.
* @param[in] aBufLength The number of bytes in @p aBuf.
* If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
*
* @returns The size of the compressed header in bytes or -1 if decompression fails.
* @param[out] aUdpHeader A reference where the UDP header will be placed.
* @param[in,out] aFrameData A frame data containing the LOWPAN_NHC header.
*
* @retval kErrorNone The header was decompressed successfully. @p aUdpHeader and @p aFrameData are updated.
* @retval kErrorParse Failed to parse the lowpan header.
*
*/
int DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength);
Error DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData);
/**
* This method decompresses the IPv6 ECN field in a LOWPAN_IPHC header.
@@ -403,8 +422,8 @@ private:
Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf);
Error CompressUdp(Message &aMessage, BufferWriter &aBuf);
int DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength);
int DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength);
Error DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData);
Error DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength);
Error DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader);
static void CopyContext(const Context &aContext, Ip6::Address &aAddress);
@@ -445,7 +464,7 @@ public:
* @retval FALSE If the header does not match the Mesh Header dispatch value.
*
*/
static bool IsMeshHeader(const uint8_t *aFrame, uint16_t aFrameLength);
static bool IsMeshHeader(const FrameData &aFrameData);
/**
* This method parses the Mesh Header from a frame @p aFrame.
@@ -460,6 +479,19 @@ public:
*/
Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
/**
* This method parses the Mesh Header from a given frame data.
*
* If the Mesh Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
*
* @param[in,out] aFrameData The frame data to parse from.
*
* @retval kErrorNone Mesh Header parsed successfully. @p aFrameData is updated to skip over parsed header.
* @retval kErrorParse Mesh Header could not be parsed.
*
*/
Error ParseFrom(FrameData &aFrameData);
/**
* This method parses the Mesh Header from a given message.
*
@@ -542,18 +574,16 @@ public:
uint16_t WriteTo(uint8_t *aFrame) const;
/**
* This method writes the Mesh Header to a message at a given offset.
* This method appends the Mesh Header to a given message.
*
* @note This method expects the @p aMessage length to be already set such that there is enough space for the
* entire Mesh Header to be written.
*
* @param[out] aMessage A message to write the Mesh Header into.
* @param[in] aOffset The offset at which to write the header.
* @param[out] aMessage A message to append the Mesh Header to.
*
* @returns The header length (number of bytes written).
* @retval kErrorNone Successfully appended the Mesh Header to @p aMessage.
* @retval kErrorNoBufs Insufficient available buffers to grow @p aMessage.
*
*/
uint16_t WriteTo(Message &aMessage, uint16_t aOffset) const;
Error AppendTo(Message &aMessage) const;
private:
static constexpr uint8_t kDispatch = 2 << 6;
@@ -612,11 +642,13 @@ public:
* header (dispatch byte) matches the Fragment Header dispatch value. It does not fully parse and validate the
* Fragment Header. `ParseFrom()` method can be used to fully parse and validate the header.
*
* @param[in] aFrameData The frame data.
*
* @retval TRUE If the header matches the Fragment Header dispatch value.
* @retval FALSE If the header does not match the Fragment Header dispatch value.
*
*/
static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
static bool IsFragmentHeader(const FrameData &aFrameData);
/**
* This method parses the Fragment Header from a frame @p aFrame.
@@ -629,7 +661,20 @@ public:
* @retval kErrorParse Fragment header could not be parsed from @p aFrame.
*
*/
Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength); //~~~ REMOVE OR MAKE PRIVATE
/**
* This method parses the Fragment Header from a given frame data.
*
* If the Fragment Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
*
* @param[in,out] aFrameData The frame data to parse from.
*
* @retval kErrorNone Fragment Header parsed successfully. @p aFrameData is updated to skip over parsed header.
* @retval kErrorParse Fragment header could not be parsed.
*
*/
Error ParseFrom(FrameData &aFrameData);
/**
* This method parses the Fragment Header from a message.
@@ -694,6 +739,8 @@ private:
static constexpr uint8_t kTagIndex = 2; // Start index of Tag field in the Fragment Header byte sequence.
static constexpr uint8_t kOffsetIndex = 4; // Start index of Offset field in the Fragment Header byte sequence.
static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
uint16_t mSize;
uint16_t mTag;
uint16_t mOffset;
+31 -50
View File
@@ -1332,8 +1332,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
ThreadLinkInfo linkInfo;
Mac::Address macDest;
Mac::Address macSource;
uint8_t * payload;
uint16_t payloadLength;
FrameData frameData;
Error error = kErrorNone;
VerifyOrExit(mEnabled, error = kErrorInvalidState);
@@ -1343,8 +1342,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
linkInfo.SetFrom(aFrame);
payload = aFrame.GetPayload();
payloadLength = aFrame.GetPayloadLength();
frameData.Init(aFrame.GetPayload(), aFrame.GetPayloadLength());
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
Get<Utils::SupervisionListener>().UpdateOnReceive(macSource, linkInfo.IsLinkSecurityEnabled());
@@ -1353,23 +1351,23 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
switch (aFrame.GetType())
{
case Mac::Frame::kFcfFrameData:
if (Lowpan::MeshHeader::IsMeshHeader(payload, payloadLength))
if (Lowpan::MeshHeader::IsMeshHeader(frameData))
{
#if OPENTHREAD_FTD
HandleMesh(payload, payloadLength, macSource, linkInfo);
HandleMesh(frameData, macSource, linkInfo);
#endif
}
else if (Lowpan::FragmentHeader::IsFragmentHeader(payload, payloadLength))
else if (Lowpan::FragmentHeader::IsFragmentHeader(frameData))
{
HandleFragment(payload, payloadLength, macSource, macDest, linkInfo);
HandleFragment(frameData, macSource, macDest, linkInfo);
}
else if (payloadLength >= 1 && Lowpan::Lowpan::IsLowpanHc(payload))
else if (Lowpan::Lowpan::IsLowpanHc(frameData))
{
HandleLowpanHC(payload, payloadLength, macSource, macDest, linkInfo);
HandleLowpanHC(frameData, macSource, macDest, linkInfo);
}
else
{
VerifyOrExit(payloadLength == 0, error = kErrorNotLowpanDataFrame);
VerifyOrExit(frameData.GetLength() == 0, error = kErrorNotLowpanDataFrame);
LogFrame("Received empty payload frame", aFrame, kErrorNone);
}
@@ -1392,21 +1390,16 @@ exit:
}
}
void MeshForwarder::HandleFragment(const uint8_t * aFrame,
uint16_t aFrameLength,
void MeshForwarder::HandleFragment(FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo)
{
Error error = kErrorNone;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
Message * message = nullptr;
// Check the fragment header
SuccessOrExit(error = fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength));
aFrame += fragmentHeaderLength;
aFrameLength -= fragmentHeaderLength;
SuccessOrExit(error = fragmentHeader.ParseFrom(aFrameData));
#if OPENTHREAD_CONFIG_MULTI_RADIO
@@ -1448,15 +1441,13 @@ void MeshForwarder::HandleFragment(const uint8_t * aFrame,
uint16_t datagramSize = fragmentHeader.GetDatagramSize();
#if OPENTHREAD_FTD
UpdateRoutes(aFrame, aFrameLength, aMacSource, aMacDest);
UpdateRoutes(aFrameData, aMacSource, aMacDest);
#endif
error = FrameToMessage(aFrame, aFrameLength, datagramSize, aMacSource, aMacDest, message);
SuccessOrExit(error);
SuccessOrExit(error = FrameToMessage(aFrameData, datagramSize, aMacSource, aMacDest, message));
VerifyOrExit(datagramSize >= message->GetLength(), error = kErrorParse);
error = message->SetLength(datagramSize);
SuccessOrExit(error);
SuccessOrExit(error = message->SetLength(datagramSize));
message->SetDatagramTag(fragmentHeader.GetDatagramTag());
message->SetTimestampToNow();
@@ -1489,7 +1480,7 @@ void MeshForwarder::HandleFragment(const uint8_t * aFrame,
if (msg.GetLength() == fragmentHeader.GetDatagramSize() &&
msg.GetDatagramTag() == fragmentHeader.GetDatagramTag() &&
msg.GetOffset() == fragmentHeader.GetDatagramOffset() &&
msg.GetOffset() + aFrameLength <= fragmentHeader.GetDatagramSize() &&
msg.GetOffset() + aFrameData.GetLength() <= fragmentHeader.GetDatagramSize() &&
msg.IsLinkSecurityEnabled() == aLinkInfo.IsLinkSecurityEnabled())
{
message = &msg;
@@ -1510,8 +1501,8 @@ void MeshForwarder::HandleFragment(const uint8_t * aFrame,
VerifyOrExit(message != nullptr, error = kErrorDrop);
message->WriteBytes(message->GetOffset(), aFrame, aFrameLength);
message->MoveOffset(aFrameLength);
message->WriteData(message->GetOffset(), aFrameData);
message->MoveOffset(aFrameData.GetLength());
message->AddRss(aLinkInfo.GetRss());
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
message->AddLqi(aLinkInfo.GetLqi());
@@ -1531,7 +1522,7 @@ exit:
}
else
{
LogFragmentFrameDrop(error, aFrameLength, aMacSource, aMacDest, fragmentHeader,
LogFragmentFrameDrop(error, aFrameData.GetLength(), aMacSource, aMacDest, fragmentHeader,
aLinkInfo.IsLinkSecurityEnabled());
FreeMessage(message);
}
@@ -1590,40 +1581,31 @@ bool MeshForwarder::UpdateReassemblyList(void)
return mReassemblyList.GetHead() != nullptr;
}
Error MeshForwarder::FrameToMessage(const uint8_t * aFrame,
uint16_t aFrameLength,
Error MeshForwarder::FrameToMessage(const FrameData & aFrameData,
uint16_t aDatagramSize,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Message *& aMessage)
{
Error error = kErrorNone;
int headerLength;
Error error = kErrorNone;
FrameData frameData = aFrameData;
Message::Priority priority;
error = GetFramePriority(aFrame, aFrameLength, aMacSource, aMacDest, priority);
SuccessOrExit(error);
SuccessOrExit(error = GetFramePriority(frameData, aMacSource, aMacDest, priority));
aMessage = Get<MessagePool>().Allocate(Message::kTypeIp6, /* aReserveHeader */ 0, Message::Settings(priority));
VerifyOrExit(aMessage, error = kErrorNoBufs);
headerLength =
Get<Lowpan::Lowpan>().Decompress(*aMessage, aMacSource, aMacDest, aFrame, aFrameLength, aDatagramSize);
VerifyOrExit(headerLength > 0, error = kErrorParse);
SuccessOrExit(error = Get<Lowpan::Lowpan>().Decompress(*aMessage, aMacSource, aMacDest, frameData, aDatagramSize));
aFrame += headerLength;
aFrameLength -= static_cast<uint16_t>(headerLength);
SuccessOrExit(error = aMessage->SetLength(aMessage->GetLength() + aFrameLength));
aMessage->WriteBytes(aMessage->GetOffset(), aFrame, aFrameLength);
aMessage->MoveOffset(aFrameLength);
SuccessOrExit(error = aMessage->AppendData(frameData));
aMessage->MoveOffset(frameData.GetLength());
exit:
return error;
}
void MeshForwarder::HandleLowpanHC(const uint8_t * aFrame,
uint16_t aFrameLength,
void MeshForwarder::HandleLowpanHC(const FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo)
@@ -1632,10 +1614,10 @@ void MeshForwarder::HandleLowpanHC(const uint8_t * aFrame,
Message *message = nullptr;
#if OPENTHREAD_FTD
UpdateRoutes(aFrame, aFrameLength, aMacSource, aMacDest);
UpdateRoutes(aFrameData, aMacSource, aMacDest);
#endif
SuccessOrExit(error = FrameToMessage(aFrame, aFrameLength, 0, aMacSource, aMacDest, message));
SuccessOrExit(error = FrameToMessage(aFrameData, 0, aMacSource, aMacDest, message));
message->SetLinkInfo(aLinkInfo);
@@ -1653,7 +1635,7 @@ exit:
}
else
{
LogLowpanHcFrameDrop(error, aFrameLength, aMacSource, aMacDest, aLinkInfo.IsLinkSecurityEnabled());
LogLowpanHcFrameDrop(error, aFrameData.GetLength(), aMacSource, aMacDest, aLinkInfo.IsLinkSecurityEnabled());
FreeMessage(message);
}
}
@@ -1676,8 +1658,7 @@ Error MeshForwarder::HandleDatagram(Message &aMessage, const ThreadLinkInfo &aLi
return Get<Ip6::Ip6>().HandleDatagram(aMessage, &netif, &aLinkInfo, false);
}
Error MeshForwarder::GetFramePriority(const uint8_t * aFrame,
uint16_t aFrameLength,
Error MeshForwarder::GetFramePriority(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Message::Priority & aPriority)
@@ -1685,7 +1666,7 @@ Error MeshForwarder::GetFramePriority(const uint8_t * aFrame,
Error error = kErrorNone;
Ip6::Headers headers;
SuccessOrExit(error = headers.DecompressFrom(aFrame, aFrameLength, aMacSource, aMacDest, GetInstance()));
SuccessOrExit(error = headers.DecompressFrom(aFrameData, aMacSource, aMacDest, GetInstance()));
aPriority = Ip6::Ip6::DscpToPriority(headers.GetIp6Header().GetDscp());
+9 -20
View File
@@ -38,6 +38,7 @@
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
#include "common/frame_data.hpp"
#include "common/locator.hpp"
#include "common/log.hpp"
#include "common/non_copyable.hpp"
@@ -425,16 +426,11 @@ private:
void SendIcmpErrorIfDstUnreach(const Message & aMessage,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest);
Error CheckReachability(const uint8_t * aFrame,
uint16_t aFrameLength,
Error CheckReachability(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest);
void UpdateRoutes(const uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest);
Error FrameToMessage(const uint8_t * aFrame,
uint16_t aFrameLength,
void UpdateRoutes(const FrameData &aFrameData, const Mac::Address &aMeshSource, const Mac::Address &aMeshDest);
Error FrameToMessage(const FrameData & aFrameData,
uint16_t aDatagramSize,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
@@ -442,17 +438,12 @@ private:
void GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
void GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
Message *PrepareNextDirectTransmission(void);
void HandleMesh(uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address & aMacSource,
const ThreadLinkInfo &aLinkInfo);
void HandleFragment(const uint8_t * aFrame,
uint16_t aFrameLength,
void HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSource, const ThreadLinkInfo &aLinkInfo);
void HandleFragment(FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo);
void HandleLowpanHC(const uint8_t * aFrame,
uint16_t aFrameLength,
void HandleLowpanHC(const FrameData & aFrameData,
const Mac::Address & aMacSource,
const Mac::Address & aMacDest,
const ThreadLinkInfo &aLinkInfo);
@@ -505,16 +496,14 @@ private:
static void ScheduleTransmissionTask(Tasklet &aTasklet);
void ScheduleTransmissionTask(void);
Error GetFramePriority(const uint8_t * aFrame,
uint16_t aFrameLength,
Error GetFramePriority(const FrameData & aFrameData,
const Mac::Address &aMacSource,
const Mac::Address &aMacDest,
Message::Priority & aPriority);
Error GetFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader,
uint16_t aSrcRloc16,
Message::Priority & aPriority);
void GetForwardFramePriority(const uint8_t * aFrame,
uint16_t aFrameLength,
void GetForwardFramePriority(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest,
Message::Priority & aPriority);
+24 -39
View File
@@ -666,15 +666,14 @@ exit:
return;
}
Error MeshForwarder::CheckReachability(const uint8_t * aFrame,
uint16_t aFrameLength,
Error MeshForwarder::CheckReachability(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest)
{
Error error;
Ip6::Headers ip6Headers;
error = ip6Headers.DecompressFrom(aFrame, aFrameLength, aMeshSource, aMeshDest, GetInstance());
error = ip6Headers.DecompressFrom(aFrameData, aMeshSource, aMeshDest, GetInstance());
if (error == kErrorNotFound)
{
@@ -704,41 +703,34 @@ void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::
Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aIp6Headers));
}
void MeshForwarder::HandleMesh(uint8_t * aFrame,
uint16_t aFrameLength,
const Mac::Address & aMacSource,
const ThreadLinkInfo &aLinkInfo)
void MeshForwarder::HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSource, const ThreadLinkInfo &aLinkInfo)
{
Error error = kErrorNone;
Message * message = nullptr;
Mac::Address meshDest;
Mac::Address meshSource;
Lowpan::MeshHeader meshHeader;
uint16_t headerLength;
// Security Check: only process Mesh Header frames that had security enabled.
VerifyOrExit(aLinkInfo.IsLinkSecurityEnabled(), error = kErrorSecurity);
SuccessOrExit(error = meshHeader.ParseFrom(aFrame, aFrameLength, headerLength));
SuccessOrExit(error = meshHeader.ParseFrom(aFrameData));
meshSource.SetShort(meshHeader.GetSource());
meshDest.SetShort(meshHeader.GetDestination());
aFrame += headerLength;
aFrameLength -= headerLength;
UpdateRoutes(aFrame, aFrameLength, meshSource, meshDest);
UpdateRoutes(aFrameData, meshSource, meshDest);
if (meshDest.GetShort() == Get<Mac::Mac>().GetShortAddress() ||
Get<Mle::MleRouter>().IsMinimalChild(meshDest.GetShort()))
{
if (Lowpan::FragmentHeader::IsFragmentHeader(aFrame, aFrameLength))
if (Lowpan::FragmentHeader::IsFragmentHeader(aFrameData))
{
HandleFragment(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
HandleFragment(aFrameData, meshSource, meshDest, aLinkInfo);
}
else if (Lowpan::Lowpan::IsLowpanHc(aFrame))
else if (Lowpan::Lowpan::IsLowpanHc(aFrameData))
{
HandleLowpanHC(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
HandleLowpanHC(aFrameData, meshSource, meshDest, aLinkInfo);
}
else
{
@@ -748,22 +740,21 @@ void MeshForwarder::HandleMesh(uint8_t * aFrame,
else if (meshHeader.GetHopsLeft() > 0)
{
Message::Priority priority = Message::kPriorityNormal;
uint16_t offset = 0;
Get<Mle::MleRouter>().ResolveRoutingLoops(aMacSource.GetShort(), meshDest.GetShort());
SuccessOrExit(error = CheckReachability(aFrame, aFrameLength, meshSource, meshDest));
SuccessOrExit(error = CheckReachability(aFrameData, meshSource, meshDest));
meshHeader.DecrementHopsLeft();
GetForwardFramePriority(aFrame, aFrameLength, meshSource, meshDest, priority);
GetForwardFramePriority(aFrameData, meshSource, meshDest, priority);
message =
Get<MessagePool>().Allocate(Message::kType6lowpan, /* aReserveHeader */ 0, Message::Settings(priority));
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->SetLength(meshHeader.GetHeaderLength() + aFrameLength));
offset += meshHeader.WriteTo(*message, offset);
message->WriteBytes(offset, aFrame, aFrameLength);
SuccessOrExit(error = meshHeader.AppendTo(*message));
SuccessOrExit(error = message->AppendData(aFrameData));
message->SetLinkInfo(aLinkInfo);
#if OPENTHREAD_CONFIG_MULTI_RADIO
@@ -789,14 +780,13 @@ exit:
if (error != kErrorNone)
{
LogInfo("Dropping rx mesh frame, error:%s, len:%d, src:%s, sec:%s", ErrorToString(error), aFrameLength,
aMacSource.ToString().AsCString(), ToYesNo(aLinkInfo.IsLinkSecurityEnabled()));
LogInfo("Dropping rx mesh frame, error:%s, len:%d, src:%s, sec:%s", ErrorToString(error),
aFrameData.GetLength(), aMacSource.ToString().AsCString(), ToYesNo(aLinkInfo.IsLinkSecurityEnabled()));
FreeMessage(message);
}
}
void MeshForwarder::UpdateRoutes(const uint8_t * aFrame,
uint16_t aFrameLength,
void MeshForwarder::UpdateRoutes(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest)
{
@@ -805,7 +795,7 @@ void MeshForwarder::UpdateRoutes(const uint8_t * aFrame,
VerifyOrExit(!aMeshDest.IsBroadcast() && aMeshSource.IsShort());
SuccessOrExit(ip6Headers.DecompressFrom(aFrame, aFrameLength, aMeshSource, aMeshDest, GetInstance()));
SuccessOrExit(ip6Headers.DecompressFrom(aFrameData, aMeshSource, aMeshDest, GetInstance()));
if (!ip6Headers.GetSourceAddress().GetIid().IsLocator() &&
Get<NetworkData::Leader>().IsOnMesh(ip6Headers.GetSourceAddress()))
@@ -944,22 +934,19 @@ exit:
return error;
}
void MeshForwarder::GetForwardFramePriority(const uint8_t * aFrame,
uint16_t aFrameLength,
void MeshForwarder::GetForwardFramePriority(const FrameData & aFrameData,
const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest,
Message::Priority & aPriority)
{
Error error = kErrorNone;
FrameData frameData = aFrameData;
bool isFragment = false;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone)
if (fragmentHeader.ParseFrom(frameData) == kErrorNone)
{
isFragment = true;
aFrame += fragmentHeaderLength;
aFrameLength -= fragmentHeaderLength;
if (fragmentHeader.GetDatagramOffset() > 0)
{
@@ -969,20 +956,18 @@ void MeshForwarder::GetForwardFramePriority(const uint8_t * aFrame,
}
// Get priority from IPv6 header or UDP destination port directly
error = GetFramePriority(aFrame, aFrameLength, aMeshSource, aMeshDest, aPriority);
error = GetFramePriority(frameData, aMeshSource, aMeshDest, aPriority);
exit:
if (error != kErrorNone)
{
LogNote("Failed to get forwarded frame priority, error:%s, len:%d, src:%d, dst:%s", ErrorToString(error),
aFrameLength, aMeshSource.ToString().AsCString(), aMeshDest.ToString().AsCString());
frameData.GetLength(), aMeshSource.ToString().AsCString(), aMeshDest.ToString().AsCString());
}
else if (isFragment)
{
UpdateFragmentPriority(fragmentHeader, aFrameLength, aMeshSource.GetShort(), aPriority);
UpdateFragmentPriority(fragmentHeader, frameData.GetLength(), aMeshSource.GetShort(), aPriority);
}
return;
}
// LCOV_EXCL_START
+82 -44
View File
@@ -145,12 +145,14 @@ static void Init(void)
*/
static void Test(TestIphcVector &aVector, bool aCompress, bool aDecompress)
{
Message *message = nullptr;
uint8_t result[512];
uint8_t iphc[512];
uint8_t ip6[512];
uint16_t iphcLength;
uint16_t ip6Length;
Message * message = nullptr;
uint8_t result[512];
uint8_t iphc[512];
uint8_t ip6[512];
uint16_t iphcLength;
uint16_t ip6Length;
FrameData frameData;
Error error;
aVector.GetCompressedStream(iphc, iphcLength);
aVector.GetUncompressedStream(ip6, ip6Length);
@@ -223,28 +225,29 @@ static void Test(TestIphcVector &aVector, bool aCompress, bool aDecompress)
{
VerifyOrQuit((message = sInstance->Get<MessagePool>().Allocate(Message::kTypeIp6)) != nullptr);
int decompressedBytes =
sLowpan->Decompress(*message, aVector.mMacSource, aVector.mMacDestination, iphc, iphcLength, 0);
frameData.Init(iphc, iphcLength);
error = sLowpan->Decompress(*message, aVector.mMacSource, aVector.mMacDestination, frameData, 0);
message->ReadBytes(0, result, message->GetLength());
if (aVector.mError == kErrorNone)
{
SuccessOrQuit(error, "Lowpan::Decompress failed");
// Append payload to the IPv6 Packet.
memcpy(result + message->GetLength(), iphc + decompressedBytes,
iphcLength - static_cast<uint16_t>(decompressedBytes));
memcpy(result + message->GetLength(), frameData.GetBytes(), frameData.GetLength());
DumpBuffer("Resulted IPv6 uncompressed packet", result,
message->GetLength() + iphcLength - static_cast<uint16_t>(decompressedBytes));
DumpBuffer("Resulted IPv6 uncompressed packet", result, message->GetLength() + frameData.GetLength());
VerifyOrQuit(decompressedBytes == aVector.mIphcHeader.mLength, "Lowpan::Decompress failed");
VerifyOrQuit((frameData.GetBytes() - iphc) == aVector.mIphcHeader.mLength, "Lowpan::Decompress failed");
VerifyOrQuit(message->GetOffset() == aVector.mPayloadOffset, "Lowpan::Decompress failed");
VerifyOrQuit(message->GetOffset() == message->GetLength(), "Lowpan::Decompress failed");
VerifyOrQuit(memcmp(ip6, result, ip6Length) == 0, "Lowpan::Decompress failed");
}
else
{
VerifyOrQuit(decompressedBytes < 0, "Lowpan::Decompress failed");
VerifyOrQuit(error == kErrorParse, "Lowpan::Decompress failed");
}
message->Free();
@@ -1864,7 +1867,7 @@ void TestLowpanMeshHeader(void)
uint8_t frame[kMaxFrameSize];
uint16_t length;
uint16_t headerLength;
FrameData frameData;
Lowpan::MeshHeader meshHeader;
meshHeader.Init(kSourceAddr, kDestAddr, 1);
@@ -1878,14 +1881,17 @@ void TestLowpanMeshHeader(void)
VerifyOrQuit(memcmp(frame, kMeshHeader1, length) == 0, "MeshHeader::WriteTo() failed");
memset(&meshHeader, 0, sizeof(meshHeader));
VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frame, length));
SuccessOrQuit(meshHeader.ParseFrom(frame, length, headerLength));
VerifyOrQuit(headerLength == length, "MeshHeader::ParseFrom() returned length is incorrect");
frameData.Init(frame, length);
VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frameData));
SuccessOrQuit(meshHeader.ParseFrom(frameData));
VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(meshHeader.GetSource() == kSourceAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetHopsLeft() == 1, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
frameData.Init(frame, length - 1);
VerifyOrQuit(meshHeader.ParseFrom(frameData) == kErrorParse,
"MeshHeader::ParseFrom() did not fail with incorrect length");
//- - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1901,27 +1907,34 @@ void TestLowpanMeshHeader(void)
VerifyOrQuit(memcmp(frame, kMeshHeader2, length) == 0, "MeshHeader::WriteTo() failed");
memset(&meshHeader, 0, sizeof(meshHeader));
VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frame, length));
SuccessOrQuit(meshHeader.ParseFrom(frame, length, headerLength));
VerifyOrQuit(headerLength == length, "MeshHeader::ParseFrom() returned length is incorrect");
frameData.Init(frame, length);
VerifyOrQuit(Lowpan::MeshHeader::IsMeshHeader(frameData));
SuccessOrQuit(meshHeader.ParseFrom(frameData));
VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(meshHeader.GetSource() == kSourceAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetHopsLeft() == 0x20, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
frameData.Init(frame, length - 1);
VerifyOrQuit(meshHeader.ParseFrom(frameData) == kErrorParse,
"MeshHeader::ParseFrom() did not fail with incorrect length");
//- - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(meshHeader.ParseFrom(kMeshHeader3, sizeof(kMeshHeader3), headerLength));
VerifyOrQuit(headerLength == sizeof(kMeshHeader3), "MeshHeader::ParseFrom() returned length is incorrect");
length = sizeof(kMeshHeader3);
frameData.Init(kMeshHeader3, sizeof(kMeshHeader3));
SuccessOrQuit(meshHeader.ParseFrom(frameData));
VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(frameData.GetBytes() - kMeshHeader3 == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(meshHeader.GetSource() == kSourceAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetDestination() == kDestAddr, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.GetHopsLeft() == 1, "failed after ParseFrom()");
VerifyOrQuit(meshHeader.WriteTo(frame) == sizeof(kMeshHeader1));
VerifyOrQuit(meshHeader.ParseFrom(kMeshHeader3, sizeof(kMeshHeader3) - 1, headerLength) == kErrorParse,
frameData.Init(kMeshHeader3, sizeof(kMeshHeader3) - 1);
VerifyOrQuit(meshHeader.ParseFrom(frameData) == kErrorParse,
"MeshHeader::ParseFrom() did not fail with incorrect length");
}
@@ -1945,7 +1958,7 @@ void TestLowpanFragmentHeader(void)
uint8_t frame[kMaxFrameSize];
uint16_t length;
uint16_t headerLength;
FrameData frameData;
Lowpan::FragmentHeader fragHeader;
fragHeader.InitFirstFragment(kSize, kTag);
@@ -1960,15 +1973,21 @@ void TestLowpanFragmentHeader(void)
VerifyOrQuit(memcmp(frame, kFragHeader1, length) == 0, "FragmentHeader::WriteTo() failed");
memset(&fragHeader, 0, sizeof(fragHeader));
VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frame, length));
SuccessOrQuit(fragHeader.ParseFrom(frame, length, headerLength));
VerifyOrQuit(headerLength == length, "FragmentHeader::ParseFrom() returned length is incorrect");
frameData.Init(frame, length);
VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frameData));
SuccessOrQuit(fragHeader.ParseFrom(frameData));
VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramOffset() == 0, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
frameData.Init(frame, length - 1);
VerifyOrQuit(fragHeader.ParseFrom(frameData) == kErrorParse,
"FragmentHeader::ParseFrom() did not fail with incorrect length");
VerifyOrQuit(frameData.GetLength() == length - 1);
VerifyOrQuit(frameData.GetBytes() == frame);
//- - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1990,51 +2009,70 @@ void TestLowpanFragmentHeader(void)
VerifyOrQuit(memcmp(frame, kFragHeader2, length) == 0, "FragmentHeader::WriteTo() failed");
memset(&fragHeader, 0, sizeof(fragHeader));
VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frame, length));
SuccessOrQuit(fragHeader.ParseFrom(frame, length, headerLength));
VerifyOrQuit(headerLength == length, "FragmentHeader::ParseFrom() returned length is incorrect");
frameData.Init(frame, length);
VerifyOrQuit(Lowpan::FragmentHeader::IsFragmentHeader(frameData));
SuccessOrQuit(fragHeader.ParseFrom(frameData));
VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramOffset() == kOffset, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
frameData.Init(frame, length - 1);
VerifyOrQuit(fragHeader.ParseFrom(frameData) == kErrorParse,
"FragmentHeader::ParseFrom() did not fail with incorrect length");
VerifyOrQuit(frameData.GetLength() == length - 1);
VerifyOrQuit(frameData.GetBytes() == frame);
//- - - - - - - - - - - - - - - - - - - - - - - - - -
length = sizeof(kFragHeader3);
memcpy(frame, kFragHeader3, length);
SuccessOrQuit(fragHeader.ParseFrom(frame, length, headerLength));
VerifyOrQuit(headerLength == length, "FragmentHeader::ParseFrom() returned length is incorrect");
frameData.Init(frame, length);
SuccessOrQuit(fragHeader.ParseFrom(frameData));
VerifyOrQuit(frameData.GetLength() == 0, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(frameData.GetBytes() - frame == length, "ParseFrom() did not skip over parsed content");
VerifyOrQuit(fragHeader.GetDatagramSize() == kSize, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramTag() == kTag, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.GetDatagramOffset() == 0, "failed after ParseFrom()");
VerifyOrQuit(fragHeader.ParseFrom(frame, length - 1, headerLength) == kErrorParse,
frameData.Init(frame, length - 1);
VerifyOrQuit(fragHeader.ParseFrom(frameData) == kErrorParse,
"FragmentHeader::ParseFrom() did not fail with incorrect length");
VerifyOrQuit(frameData.GetLength() == length - 1);
VerifyOrQuit(frameData.GetBytes() == frame);
//- - - - - - - - - - - - - - - - - - - - - - - - - -
length = sizeof(kInvalidFragHeader1);
memcpy(frame, kInvalidFragHeader1, length);
VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frame, length),
frameData.Init(frame, length);
VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frameData),
"IsFragmentHeader() did not detect invalid header");
VerifyOrQuit(fragHeader.ParseFrom(frame, length, headerLength) != kErrorNone,
VerifyOrQuit(fragHeader.ParseFrom(frameData) != kErrorNone,
"FragmentHeader::ParseFrom() did not fail with invalid header");
VerifyOrQuit(frameData.GetLength() == length);
VerifyOrQuit(frameData.GetBytes() == frame);
length = sizeof(kInvalidFragHeader2);
memcpy(frame, kInvalidFragHeader2, length);
VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frame, length),
frameData.Init(frame, length);
VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frameData),
"IsFragmentHeader() did not detect invalid header");
VerifyOrQuit(fragHeader.ParseFrom(frame, length, headerLength) != kErrorNone,
VerifyOrQuit(fragHeader.ParseFrom(frameData) != kErrorNone,
"FragmentHeader::ParseFrom() did not fail with invalid header");
VerifyOrQuit(frameData.GetLength() == length);
VerifyOrQuit(frameData.GetBytes() == frame);
length = sizeof(kInvalidFragHeader3);
memcpy(frame, kInvalidFragHeader3, length);
VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frame, length),
frameData.Init(frame, length);
VerifyOrQuit(!Lowpan::FragmentHeader::IsFragmentHeader(frameData),
"IsFragmentHeader() did not detect invalid header");
VerifyOrQuit(fragHeader.ParseFrom(frame, length, headerLength) != kErrorNone,
VerifyOrQuit(fragHeader.ParseFrom(frameData) != kErrorNone,
"FragmentHeader::ParseFrom() did not fail with invalid header");
VerifyOrQuit(frameData.GetLength() == length);
VerifyOrQuit(frameData.GetBytes() == frame);
}
} // namespace ot