diff --git a/Android.mk b/Android.mk index e950f806d..ab9697c77 100644 --- a/Android.mk +++ b/Android.mk @@ -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 \ diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index baf337056..7f431bc9e 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -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", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e0de03c5a..2cb0d4b79 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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 diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 7062dea02..7fb841e36 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -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 \ diff --git a/src/core/common/num_utils.hpp b/src/core/common/num_utils.hpp index d53134d6f..eb0493ac0 100644 --- a/src/core/common/num_utils.hpp +++ b/src/core/common/num_utils.hpp @@ -200,6 +200,33 @@ inline unsigned long ToUlong(uint32_t aUint32) return static_cast(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 uint8_t CountBitsInMask(UintType aMask) +{ + static_assert(TypeTraits::IsSame::kValue || TypeTraits::IsSame::kValue || + TypeTraits::IsSame::kValue || TypeTraits::IsSame::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_ diff --git a/src/core/thread/mle_tlvs.cpp b/src/core/thread/mle_tlvs.cpp new file mode 100644 index 000000000..dd40805e2 --- /dev/null +++ b/src/core/thread/mle_tlvs.cpp @@ -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 diff --git a/src/core/thread/mle_tlvs.hpp b/src/core/thread/mle_tlvs.hpp index 3e8e6ec51..10a3561a0 100644 --- a/src/core/thread/mle_tlvs.hpp +++ b/src/core/thread/mle_tlvs.hpp @@ -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((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( - (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( + (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( + (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, diff --git a/src/core/thread/mle_types.cpp b/src/core/thread/mle_types.cpp index f820e5785..0714d3ad7 100644 --- a/src/core/thread/mle_types.cpp +++ b/src/core/thread/mle_types.cpp @@ -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[] = { diff --git a/src/core/thread/mle_types.hpp b/src/core/thread/mle_types.hpp index 44be29ea4..50e13a3fe 100644 --- a/src/core/thread/mle_types.hpp +++ b/src/core/thread/mle_types.hpp @@ -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; diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 9cd38089a..87dfcce93 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -559,9 +559,7 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb if (router->GetRloc16() == Get().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++; diff --git a/tests/unit/test_serial_number.cpp b/tests/unit/test_serial_number.cpp index 67aeebfcb..727c1ea61 100644 --- a/tests/unit/test_serial_number.cpp +++ b/tests/unit/test_serial_number.cpp @@ -131,6 +131,24 @@ void TestNumUtils(void) VerifyOrQuit(DivideAndRoundToClosest(9, 10) == 1); VerifyOrQuit(DivideAndRoundToClosest(10, 10) == 1); + VerifyOrQuit(CountBitsInMask(0) == 0); + VerifyOrQuit(CountBitsInMask(1) == 1); + VerifyOrQuit(CountBitsInMask(2) == 1); + VerifyOrQuit(CountBitsInMask(3) == 2); + VerifyOrQuit(CountBitsInMask(4) == 1); + VerifyOrQuit(CountBitsInMask(7) == 3); + VerifyOrQuit(CountBitsInMask(11) == 3); + VerifyOrQuit(CountBitsInMask(15) == 4); + VerifyOrQuit(CountBitsInMask(0x11) == 2); + VerifyOrQuit(CountBitsInMask(0xef) == 7); + VerifyOrQuit(CountBitsInMask(0xff) == 8); + + VerifyOrQuit(CountBitsInMask(0) == 0); + VerifyOrQuit(CountBitsInMask(0xff00) == 8); + VerifyOrQuit(CountBitsInMask(0xff) == 8); + VerifyOrQuit(CountBitsInMask(0xaa55) == 8); + VerifyOrQuit(CountBitsInMask(0xffff) == 16); + printf("TestNumUtils() passed\n"); }