[mle] update RouteTlv to check number of allocated IDs (#8463)

This commit contains smaller enhancements in `RouteTlv`:

- `RouteTlv::IsValid()` checks that number of allocated IDs in
  the Router ID Mask is less than max number of routers.
- It also checks that the TLV contains correct number of Route
  Data entries matching the number of allocated router IDs.
- A new method `SetRouteData()` is added to set all the
  data fields (link quality in/out and route cost) for a given
  router index.
- These changes help ensure that messages containing invalid
  `RouteTlv` are rejected (avoid situation where we may have
  more allocated router IDs than max routers).
This commit is contained in:
Abtin Keshavarzian
2022-12-01 19:45:31 -08:00
committed by GitHub
parent 87284f22eb
commit 89e403815a
11 changed files with 203 additions and 98 deletions
+1
View File
@@ -342,6 +342,7 @@ LOCAL_SRC_FILES := \
src/core/thread/mesh_forwarder_mtd.cpp \
src/core/thread/mle.cpp \
src/core/thread/mle_router.cpp \
src/core/thread/mle_tlvs.cpp \
src/core/thread/mle_types.cpp \
src/core/thread/mlr_manager.cpp \
src/core/thread/neighbor_table.cpp \
+1
View File
@@ -639,6 +639,7 @@ openthread_core_files = [
"thread/mle.hpp",
"thread/mle_router.cpp",
"thread/mle_router.hpp",
"thread/mle_tlvs.cpp",
"thread/mle_tlvs.hpp",
"thread/mle_types.cpp",
"thread/mle_types.hpp",
+1
View File
@@ -209,6 +209,7 @@ set(COMMON_SOURCES
thread/mesh_forwarder_mtd.cpp
thread/mle.cpp
thread/mle_router.cpp
thread/mle_tlvs.cpp
thread/mle_types.cpp
thread/mlr_manager.cpp
thread/neighbor_table.cpp
+1
View File
@@ -299,6 +299,7 @@ SOURCES_COMMON = \
thread/mesh_forwarder_mtd.cpp \
thread/mle.cpp \
thread/mle_router.cpp \
thread/mle_tlvs.cpp \
thread/mle_types.cpp \
thread/mlr_manager.cpp \
thread/neighbor_table.cpp \
+27
View File
@@ -200,6 +200,33 @@ inline unsigned long ToUlong(uint32_t aUint32)
return static_cast<unsigned long>(aUint32);
}
/**
* This function counts the number of `1` bits in the binary representation of a given unsigned int bit-mask value.
*
* @tparam UintType The unsigned int type (MUST be `uint8_t`, uint16_t`, uint32_t`, or `uint64_t`).
*
* @param[in] aMask A bit mask.
*
* @returns The number of `1` bits in @p aMask.
*
*/
template <typename UintType> uint8_t CountBitsInMask(UintType aMask)
{
static_assert(TypeTraits::IsSame<UintType, uint8_t>::kValue || TypeTraits::IsSame<UintType, uint16_t>::kValue ||
TypeTraits::IsSame<UintType, uint32_t>::kValue || TypeTraits::IsSame<UintType, uint64_t>::kValue,
"UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`");
uint8_t count = 0;
while (aMask != 0)
{
aMask &= aMask - 1;
count++;
}
return count;
}
} // namespace ot
#endif // NUM_UTILS_HPP_
+70
View File
@@ -0,0 +1,70 @@
/*
* 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 function for generating and processing MLE TLVs.
*/
#include "mle_tlvs.hpp"
#include "common/code_utils.hpp"
namespace ot {
namespace Mle {
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
void RouteTlv::Init(void)
{
SetType(kRoute);
SetLength(sizeof(*this) - sizeof(Tlv));
mRouterIdMask.Clear();
memset(mRouteData, 0, sizeof(mRouteData));
}
bool RouteTlv::IsValid(void) const
{
bool isValid = false;
uint8_t numAllocatedIds;
VerifyOrExit(GetLength() >= sizeof(mRouterIdSequence) + sizeof(mRouterIdMask));
numAllocatedIds = mRouterIdMask.GetNumberOfAllocatedIds();
VerifyOrExit(numAllocatedIds <= Mle::kMaxRouters);
isValid = (GetRouteDataLength() >= numAllocatedIds);
exit:
return isValid;
}
#endif // #if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
} // namespace Mle
} // namespace ot
+57 -89
View File
@@ -256,13 +256,7 @@ public:
* This method initializes the TLV.
*
*/
void Init(void)
{
SetType(kRoute);
SetLength(sizeof(*this) - sizeof(Tlv));
mRouterIdMask.Clear();
memset(mRouteData, 0, sizeof(mRouteData));
}
void Init(void);
/**
* This method indicates whether or not the TLV appears to be well-formed.
@@ -271,7 +265,7 @@ public:
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() >= sizeof(mRouterIdSequence) + sizeof(mRouterIdMask); }
bool IsValid(void) const;
/**
* This method returns the Router ID Sequence value.
@@ -340,18 +334,6 @@ public:
*/
uint8_t GetRouteCost(uint8_t aRouterIndex) const { return mRouteData[aRouterIndex] & kRouteCostMask; }
/**
* This method sets the Route Cost value for a given Router index.
*
* @param[in] aRouterIndex The Router index.
* @param[in] aRouteCost The Route Cost value.
*
*/
void SetRouteCost(uint8_t aRouterIndex, uint8_t aRouteCost)
{
mRouteData[aRouterIndex] = (mRouteData[aRouterIndex] & ~kRouteCostMask) | aRouteCost;
}
/**
* This method returns the Link Quality In value for a given Router index.
*
@@ -365,19 +347,6 @@ public:
return static_cast<LinkQuality>((mRouteData[aRouterIndex] & kLinkQualityInMask) >> kLinkQualityInOffset);
}
/**
* This method sets the Link Quality In value for a given Router index.
*
* @param[in] aRouterIndex The Router index.
* @param[in] aLinkQuality The Link Quality In value for a given Router index.
*
*/
void SetLinkQualityIn(uint8_t aRouterIndex, LinkQuality aLinkQuality)
{
mRouteData[aRouterIndex] = (mRouteData[aRouterIndex] & ~kLinkQualityInMask) |
((aLinkQuality << kLinkQualityInOffset) & kLinkQualityInMask);
}
/**
* This method returns the Link Quality Out value for a given Router index.
*
@@ -392,16 +361,19 @@ public:
}
/**
* This method sets the Link Quality Out value for a given Router index.
* This method sets the Route Data (Link Quality In/Out and Route Cost) for a given Router index.
*
* @param[in] aRouterIndex The Router index.
* @param[in] aLinkQuality The Link Quality Out value for a given Router index.
* @param[in] aRouterIndex The Router index.
* @param[in] aLinkQualityIn The Link Quality In value.
* @param[in] aLinkQualityOut The Link Quality Out value.
* @param[in] aRouteCost The Route Cost value.
*
*/
void SetLinkQualityOut(uint8_t aRouterIndex, LinkQuality aLinkQuality)
void SetRouteData(uint8_t aRouterIndex, LinkQuality aLinkQualityIn, LinkQuality aLinkQualityOut, uint8_t aRouteCost)
{
mRouteData[aRouterIndex] = (mRouteData[aRouterIndex] & ~kLinkQualityOutMask) |
((aLinkQuality << kLinkQualityOutOffset) & kLinkQualityOutMask);
mRouteData[aRouterIndex] = (((aLinkQualityIn << kLinkQualityInOffset) & kLinkQualityInMask) |
((aLinkQualityOut << kLinkQualityOutOffset) & kLinkQualityOutMask) |
((aRouteCost << kRouteCostOffset) & kRouteCostMask));
}
private:
@@ -538,30 +510,6 @@ public:
}
}
/**
* This method sets the Route Cost value for a given Router index.
*
* @param[in] aRouterIndex The Router index.
* @param[in] aRouteCost The Route Cost value.
*
*/
void SetRouteCost(uint8_t aRouterIndex, uint8_t aRouteCost)
{
if (aRouterIndex & 1)
{
mRouteData[aRouterIndex + aRouterIndex / 2 + 1] = aRouteCost;
}
else
{
mRouteData[aRouterIndex + aRouterIndex / 2] =
(mRouteData[aRouterIndex + aRouterIndex / 2] & ~kRouteCostMask) |
((aRouteCost >> kOddEntryOffset) & kRouteCostMask);
mRouteData[aRouterIndex + aRouterIndex / 2 + 1] = static_cast<uint8_t>(
(mRouteData[aRouterIndex + aRouterIndex / 2 + 1] & ~(kRouteCostMask << kOddEntryOffset)) |
((aRouteCost & kRouteCostMask) << kOddEntryOffset));
}
}
/**
* This method returns the Link Quality In value for a given Router index.
*
@@ -570,26 +518,12 @@ public:
* @returns The Link Quality In value for a given Router index.
*
*/
uint8_t GetLinkQualityIn(uint8_t aRouterIndex) const
LinkQuality GetLinkQualityIn(uint8_t aRouterIndex) const
{
int offset = ((aRouterIndex & 1) ? kOddEntryOffset : 0);
return (mRouteData[aRouterIndex + aRouterIndex / 2] & (kLinkQualityInMask >> offset)) >>
(kLinkQualityInOffset - offset);
}
/**
* This method sets the Link Quality In value for a given Router index.
*
* @param[in] aRouterIndex The Router index.
* @param[in] aLinkQuality The Link Quality In value for a given Router index.
*
*/
void SetLinkQualityIn(uint8_t aRouterIndex, uint8_t aLinkQuality)
{
int offset = ((aRouterIndex & 1) ? kOddEntryOffset : 0);
mRouteData[aRouterIndex + aRouterIndex / 2] =
(mRouteData[aRouterIndex + aRouterIndex / 2] & ~(kLinkQualityInMask >> offset)) |
((aLinkQuality << (kLinkQualityInOffset - offset)) & (kLinkQualityInMask >> offset));
return static_cast<LinkQuality>(
(mRouteData[aRouterIndex + aRouterIndex / 2] & (kLinkQualityInMask >> offset)) >>
(kLinkQualityInOffset - offset));
}
/**
@@ -609,18 +543,19 @@ public:
}
/**
* This method sets the Link Quality Out value for a given Router index.
* This method sets the Route Data (Link Quality In/Out and Route Cost) for a given Router index.
*
* @param[in] aRouterIndex The Router index.
* @param[in] aLinkQuality The Link Quality Out value for a given Router index.
* @param[in] aRouterIndex The Router index.
* @param[in] aLinkQualityIn The Link Quality In value.
* @param[in] aLinkQualityOut The Link Quality Out value.
* @param[in] aRouteCost The Route Cost value.
*
*/
void SetLinkQualityOut(uint8_t aRouterIndex, LinkQuality aLinkQuality)
void SetRouteData(uint8_t aRouterIndex, LinkQuality aLinkQualityIn, LinkQuality aLinkQualityOut, uint8_t aRouteCost)
{
int offset = ((aRouterIndex & 1) ? kOddEntryOffset : 0);
mRouteData[aRouterIndex + aRouterIndex / 2] =
(mRouteData[aRouterIndex + aRouterIndex / 2] & ~(kLinkQualityOutMask >> offset)) |
((aLinkQuality << (kLinkQualityOutOffset - offset)) & (kLinkQualityOutMask >> offset));
SetLinkQualityIn(aRouterIndex, aLinkQualityIn);
SetLinkQualityOut(aRouterIndex, aLinkQualityOut);
SetRouteCost(aRouterIndex, aRouteCost);
}
private:
@@ -632,6 +567,39 @@ private:
static constexpr uint8_t kRouteCostMask = 0xf << kRouteCostOffset;
static constexpr uint8_t kOddEntryOffset = 4;
void SetRouteCost(uint8_t aRouterIndex, uint8_t aRouteCost)
{
if (aRouterIndex & 1)
{
mRouteData[aRouterIndex + aRouterIndex / 2 + 1] = aRouteCost;
}
else
{
mRouteData[aRouterIndex + aRouterIndex / 2] =
(mRouteData[aRouterIndex + aRouterIndex / 2] & ~kRouteCostMask) |
((aRouteCost >> kOddEntryOffset) & kRouteCostMask);
mRouteData[aRouterIndex + aRouterIndex / 2 + 1] = static_cast<uint8_t>(
(mRouteData[aRouterIndex + aRouterIndex / 2 + 1] & ~(kRouteCostMask << kOddEntryOffset)) |
((aRouteCost & kRouteCostMask) << kOddEntryOffset));
}
}
void SetLinkQualityIn(uint8_t aRouterIndex, uint8_t aLinkQuality)
{
int offset = ((aRouterIndex & 1) ? kOddEntryOffset : 0);
mRouteData[aRouterIndex + aRouterIndex / 2] =
(mRouteData[aRouterIndex + aRouterIndex / 2] & ~(kLinkQualityInMask >> offset)) |
((aLinkQuality << (kLinkQualityInOffset - offset)) & (kLinkQualityInMask >> offset));
}
void SetLinkQualityOut(uint8_t aRouterIndex, LinkQuality aLinkQuality)
{
int offset = ((aRouterIndex & 1) ? kOddEntryOffset : 0);
mRouteData[aRouterIndex + aRouterIndex / 2] =
(mRouteData[aRouterIndex + aRouterIndex / 2] & ~(kLinkQualityOutMask >> offset)) |
((aLinkQuality << (kLinkQualityOutOffset - offset)) & (kLinkQualityOutMask >> offset));
}
uint8_t mRouterIdSequence;
RouterIdSet mRouterIdMask;
// Since we do hold 12 (compressible to 11) bits of data per router, each entry occupies 1.5 bytes,
+12
View File
@@ -64,6 +64,18 @@ DeviceMode::InfoString DeviceMode::ToString(void) const
return string;
}
uint8_t RouterIdSet::GetNumberOfAllocatedIds(void) const
{
uint8_t count = 0;
for (uint8_t byte : mRouterIdSet)
{
count += CountBitsInMask(byte);
}
return count;
}
const char *RoleToString(DeviceRole aRole)
{
static const char *const kRoleStrings[] = {
+13 -3
View File
@@ -540,7 +540,7 @@ public:
* @retval FALSE If the Router ID bit is not set.
*
*/
bool Contains(uint8_t aRouterId) const { return (mRouterIdSet[aRouterId / 8] & (0x80 >> (aRouterId % 8))) != 0; }
bool Contains(uint8_t aRouterId) const { return (mRouterIdSet[aRouterId / 8] & MaskFor(aRouterId)) != 0; }
/**
* This method sets a given Router ID.
@@ -548,7 +548,7 @@ public:
* @param[in] aRouterId The Router ID to set.
*
*/
void Add(uint8_t aRouterId) { mRouterIdSet[aRouterId / 8] |= 0x80 >> (aRouterId % 8); }
void Add(uint8_t aRouterId) { mRouterIdSet[aRouterId / 8] |= MaskFor(aRouterId); }
/**
* This method removes a given Router ID.
@@ -556,9 +556,19 @@ public:
* @param[in] aRouterId The Router ID to remove.
*
*/
void Remove(uint8_t aRouterId) { mRouterIdSet[aRouterId / 8] &= ~(0x80 >> (aRouterId % 8)); }
void Remove(uint8_t aRouterId) { mRouterIdSet[aRouterId / 8] &= ~MaskFor(aRouterId); }
/**
* This method calculates the number of allocated Router IDs in the set.
*
* @returns The number of allocated Router IDs in the set.
*
*/
uint8_t GetNumberOfAllocatedIds(void) const;
private:
static uint8_t MaskFor(uint8_t aRouterId) { return (0x80 >> (aRouterId % 8)); }
uint8_t mRouterIdSet[BitVectorBytes(Mle::kMaxRouterId + 1)];
} OT_TOOL_PACKED_END;
+2 -6
View File
@@ -559,9 +559,7 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb
if (router->GetRloc16() == Get<Mle::Mle>().GetRloc16())
{
aRouteTlv.SetLinkQualityIn(routerCount, kLinkQuality0);
aRouteTlv.SetLinkQualityOut(routerCount, kLinkQuality0);
aRouteTlv.SetRouteCost(routerCount, 1);
aRouteTlv.SetRouteData(routerCount, kLinkQuality0, kLinkQuality0, 1);
}
else
{
@@ -588,9 +586,7 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb
routeCost = 0;
}
aRouteTlv.SetRouteCost(routerCount, routeCost);
aRouteTlv.SetLinkQualityOut(routerCount, router->GetLinkQualityOut());
aRouteTlv.SetLinkQualityIn(routerCount, router->GetLinkQualityIn());
aRouteTlv.SetRouteData(routerCount, router->GetLinkQualityIn(), router->GetLinkQualityOut(), routeCost);
}
routerCount++;
+18
View File
@@ -131,6 +131,24 @@ void TestNumUtils(void)
VerifyOrQuit(DivideAndRoundToClosest<uint8_t>(9, 10) == 1);
VerifyOrQuit(DivideAndRoundToClosest<uint8_t>(10, 10) == 1);
VerifyOrQuit(CountBitsInMask<uint8_t>(0) == 0);
VerifyOrQuit(CountBitsInMask<uint8_t>(1) == 1);
VerifyOrQuit(CountBitsInMask<uint8_t>(2) == 1);
VerifyOrQuit(CountBitsInMask<uint8_t>(3) == 2);
VerifyOrQuit(CountBitsInMask<uint8_t>(4) == 1);
VerifyOrQuit(CountBitsInMask<uint8_t>(7) == 3);
VerifyOrQuit(CountBitsInMask<uint8_t>(11) == 3);
VerifyOrQuit(CountBitsInMask<uint8_t>(15) == 4);
VerifyOrQuit(CountBitsInMask<uint8_t>(0x11) == 2);
VerifyOrQuit(CountBitsInMask<uint8_t>(0xef) == 7);
VerifyOrQuit(CountBitsInMask<uint8_t>(0xff) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0) == 0);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff00) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xaa55) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xffff) == 16);
printf("TestNumUtils() passed\n");
}