diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 217d83097..b05b394c6 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -226,20 +226,18 @@ otError Commissioner::SendCommissionerSet(void) { otError error; otCommissioningDataset dataset; - SteeringDataTlv steeringData; + SteeringData & steeringData = static_cast(dataset.mSteeringData); Mac::ExtAddress joinerId; VerifyOrExit(mState == OT_COMMISSIONER_STATE_ACTIVE, error = OT_ERROR_INVALID_STATE); memset(&dataset, 0, sizeof(dataset)); - // session id dataset.mSessionId = mSessionId; dataset.mIsSessionIdSet = true; - // compute bloom filter + // Compute bloom filter steeringData.Init(); - steeringData.Clear(); for (Joiner *joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++) { @@ -250,18 +248,14 @@ otError Commissioner::SendCommissionerSet(void) if (joiner->mAny) { - steeringData.SetLength(1); - steeringData.Set(); + steeringData.SetToPermitAllJoiners(); break; } ComputeJoinerId(joiner->mEui64, joinerId); - steeringData.ComputeBloomFilter(joinerId); + steeringData.UpdateBloomFilter(joinerId); } - // set bloom filter - dataset.mSteeringData.mLength = steeringData.GetSteeringDataLength(); - memcpy(dataset.mSteeringData.m8, steeringData.GetValue(), dataset.mSteeringData.mLength); dataset.mIsSteeringDataSet = true; SuccessOrExit(error = SendMgmtCommissionerSetRequest(dataset, NULL, 0)); @@ -615,11 +609,8 @@ otError Commissioner::SendMgmtCommissionerSetRequest(const otCommissioningDatase if (aDataset.mIsSteeringDataSet) { - MeshCoP::SteeringDataTlv steeringData; - steeringData.Init(); - steeringData.SetLength(aDataset.mSteeringData.mLength); - SuccessOrExit(error = message->Append(&steeringData, sizeof(MeshCoP::Tlv))); - SuccessOrExit(error = message->Append(&aDataset.mSteeringData.m8, aDataset.mSteeringData.mLength)); + SuccessOrExit(error = Tlv::AppendTlv(*message, MeshCoP::Tlv::kSteeringData, aDataset.mSteeringData.m8, + aDataset.mSteeringData.mLength)); } if (aDataset.mIsJoinerUdpPortSet) diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index a447c4a27..250d7719a 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -275,19 +275,11 @@ exit: void Joiner::SaveDiscoveredJoinerRouter(const otActiveScanResult &aResult) { uint8_t priority; - bool doesAllowAny = true; - JoinerRouter *end = OT_ARRAY_END(mJoinerRouters); + bool doesAllowAny; + JoinerRouter *end = OT_ARRAY_END(mJoinerRouters); JoinerRouter *entry; - // Check whether Steering Data allows any joiner (it is all 0xff). - for (uint8_t i = 0; i < aResult.mSteeringData.mLength; i++) - { - if (aResult.mSteeringData.m8[i] != 0xff) - { - doesAllowAny = false; - break; - } - } + doesAllowAny = static_cast(aResult.mSteeringData).PermitsAllJoiners(); otLogInfoMeshCoP("Joiner discover network: %s, pan:0x%04x, port:%d, chan:%d, rssi:%d, allow-any:%s", static_cast(aResult.mExtAddress).ToString().AsCString(), aResult.mPanId, diff --git a/src/core/meshcop/meshcop.cpp b/src/core/meshcop/meshcop.cpp index b4e7fa308..fb60b092f 100644 --- a/src/core/meshcop/meshcop.cpp +++ b/src/core/meshcop/meshcop.cpp @@ -31,6 +31,10 @@ * This file implements common MeshCoP utility functions. */ +#include "meshcop.hpp" + +#include "common/crc16.hpp" +#include "common/debug.hpp" #include "common/locator-getters.hpp" #include "crypto/pbkdf2_cmac.h" #include "crypto/sha256.hpp" @@ -40,6 +44,76 @@ namespace ot { namespace MeshCoP { +void SteeringData::Init(uint8_t aLength) +{ + OT_ASSERT(aLength <= kMaxLength); + mLength = aLength; + memset(m8, 0, sizeof(m8)); +} + +void SteeringData::SetToPermitAllJoiners(void) +{ + Init(1); + m8[0] = kPermitAll; +} + +void SteeringData::UpdateBloomFilter(const Mac::ExtAddress &aJoinerId) +{ + HashBitIndexes indexes; + + OT_ASSERT((mLength > 0) && (mLength <= kMaxLength)); + + CalculateHashBitIndexes(aJoinerId, indexes); + + SetBit(indexes.mIndex[0] % GetNumBits()); + SetBit(indexes.mIndex[1] % GetNumBits()); +} + +bool SteeringData::Contains(const Mac::ExtAddress &aJoinerId) const +{ + HashBitIndexes indexes; + + CalculateHashBitIndexes(aJoinerId, indexes); + + return Contains(indexes); +} + +bool SteeringData::Contains(const HashBitIndexes &aIndexes) const +{ + return (mLength > 0) && GetBit(aIndexes.mIndex[0] % GetNumBits()) && GetBit(aIndexes.mIndex[1] % GetNumBits()); +} + +void SteeringData::CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes) +{ + Crc16 ccitt(Crc16::kCcitt); + Crc16 ansi(Crc16::kAnsi); + + for (uint8_t i = 0; i < sizeof(Mac::ExtAddress); i++) + { + ccitt.Update(aJoinerId.m8[i]); + ansi.Update(aJoinerId.m8[i]); + } + + aIndexes.mIndex[0] = ccitt.Get(); + aIndexes.mIndex[1] = ansi.Get(); +} + +bool SteeringData::DoesAllMatch(uint8_t aMatch) const +{ + bool matches = true; + + for (uint8_t i = 0; i < mLength; i++) + { + if (m8[i] != aMatch) + { + matches = false; + break; + } + } + + return matches; +} + void ComputeJoinerId(const Mac::ExtAddress &aEui64, Mac::ExtAddress &aJoinerId) { Crypto::Sha256 sha256; diff --git a/src/core/meshcop/meshcop.hpp b/src/core/meshcop/meshcop.hpp index 1598fbe7c..99c42531e 100644 --- a/src/core/meshcop/meshcop.hpp +++ b/src/core/meshcop/meshcop.hpp @@ -37,6 +37,8 @@ #include "openthread-core-config.h" +#include + #include #include "coap/coap.hpp" @@ -55,6 +57,155 @@ enum kBorderAgentUdpPort = 49191, ///< UDP port of border agent service. }; +/** + * This type represents Steering Data (bloom filter). + * + */ +class SteeringData : public otSteeringData +{ +public: + enum + { + kMaxLength = OT_STEERING_DATA_MAX_LENGTH, ///< Maximum Steering Data length (in bytes). + }; + + /** + * This structure represents the hash bit index values for the bloom filter calculated from a Joiner ID. + * + * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI. + * + */ + struct HashBitIndexes + { + enum + { + kNumIndexes = 2, ///< Number of hash bit indexes. + }; + + uint16_t mIndex[kNumIndexes]; ///< The hash bit index array. + }; + + /** + * This method initializes the Steering Data and clears the bloom filter. + * + * @param[in] aLength The Steering Data length (in bytes) - MUST be smaller than or equal to `kMaxLength`. + * + */ + void Init(uint8_t aLength = kMaxLength); + + /** + * This method clears the bloom filter (all bits are cleared and no Joiner Id is accepted).. + * + * The Steering Data length (bloom filter length) is set to one byte with all bits cleared. + * + */ + void Clear(void) { Init(1); } + + /** + * This method sets the bloom filter to permit all Joiner IDs. + * + * To permit all Joiner IDs, The Steering Data length (bloom filter length) is set to one byte with all bits set. + * + */ + void SetToPermitAllJoiners(void); + + /** + * This method returns the Steering Data length (in bytes). + * + * @returns The Steering Data length (in bytes). + * + */ + uint8_t GetLength(void) const { return mLength; } + + /** + * This method gets the Steering Data buffer (bloom filter). + * + * @returns A pointer to the Steering Data buffer. + * + */ + const uint8_t *GetData(void) const { return m8; } + + /** + * This method gets the Steering Data buffer (bloom filter). + * + * @returns A pointer to the Steering Data buffer. + * + */ + uint8_t *GetData(void) { return m8; } + + /** + * This method updates the bloom filter adding the given Joiner ID. + * + * @param[in] aJoinerId The Joiner ID to add to bloom filter. + * + */ + void UpdateBloomFilter(const Mac::ExtAddress &aJoinerId); + + /** + * This method indicates whether the bloom filter is empty (all the bits are cleared). + * + * @returns TRUE if the bloom filter is empty, FALSE otherwise. + * + */ + bool IsEmpty(void) const { return DoesAllMatch(0); } + + /** + * This method indicates whether the bloom filter permits all Joiner IDs (all the bits are set). + * + * @returns TRUE if the bloom filter permits all Joiners IDs, FALSE otherwise. + * + */ + bool PermitsAllJoiners(void) const { return (mLength > 0) && DoesAllMatch(kPermitAll); } + + /** + * This method indicates whether the bloom filter contains a given Joiner ID. + * + * @param[in] aJoinderId A Joiner ID. + * + * @returns TRUE if the bloom filter contains @p aJoinerId, FALSE otherwise. + * + */ + bool Contains(const Mac::ExtAddress &aJoinerId) const; + + /** + * This method indicates whether the bloom filter contains the hash bit indexes (derived from a Joiner ID). + * + * @param[in] aIndexes A hash bit index structure (derived from a Joiner ID). + * + * @returns TRUE if the bloom filter contains the Joiner ID mapping to @p aIndexes, FALSE otherwise. + * + */ + bool Contains(const HashBitIndexes &aIndexes) const; + + /** + * This static method calculates the bloom filter hash bit indexes from a given Joiner ID. + * + * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI. + * + * @param[in] aJoinerId The Joiner ID to calculate the hash bit indexes. + * @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values. + * + */ + static void CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes); + +private: + enum + { + kPermitAll = 0xff, + }; + + uint8_t GetNumBits(void) const { return (mLength * CHAR_BIT); } + + uint8_t BitIndex(uint8_t aBit) const { return (mLength - 1 - (aBit / CHAR_BIT)); } + uint8_t BitFlag(uint8_t aBit) const { return static_cast(1U << (aBit % CHAR_BIT)); }; + + bool GetBit(uint8_t aBit) const { return (m8[BitIndex(aBit)] & BitFlag(aBit)) != 0; } + void SetBit(uint8_t aBit) { m8[BitIndex(aBit)] |= BitFlag(aBit); } + void ClearBit(uint8_t aBit) { m8[BitIndex(aBit)] &= ~BitFlag(aBit); } + + bool DoesAllMatch(uint8_t aMatch) const; +}; + /** * This function creates Message for MeshCoP. * diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index 357d8cf4d..7481d75a3 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -34,6 +34,7 @@ #include "meshcop_tlvs.hpp" #include "common/debug.hpp" +#include "meshcop/meshcop.hpp" namespace ot { namespace MeshCoP { @@ -128,36 +129,10 @@ void NetworkNameTlv::SetNetworkName(const Mac::NameData &aNameData) SetLength(len); } -bool SteeringDataTlv::IsCleared(void) const +void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) { - bool rval = true; - - for (uint8_t i = 0; i < GetLength(); i++) - { - if (mSteeringData[i] != 0) - { - rval = false; - break; - } - } - - return rval; -} - -void SteeringDataTlv::ComputeBloomFilter(const otExtAddress &aJoinerId) -{ - Crc16 ccitt(Crc16::kCcitt); - Crc16 ansi(Crc16::kAnsi); - - for (size_t j = 0; j < sizeof(otExtAddress); j++) - { - uint8_t byte = aJoinerId.m8[j]; - ccitt.Update(byte); - ansi.Update(byte); - } - - SetBit(ccitt.Get() % GetNumBits()); - SetBit(ansi.Get() % GetNumBits()); + aSteeringData.Init(GetSteeringDataLength()); + memcpy(aSteeringData.GetData(), mSteeringData, GetSteeringDataLength()); } bool ChannelTlv::IsValid(void) const diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 2e7924537..497f81dbb 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -41,7 +41,6 @@ #include #include -#include "common/crc16.hpp" #include "common/encoding.hpp" #include "common/message.hpp" #include "common/string.hpp" @@ -724,6 +723,8 @@ private: Mle::MeshLocalPrefix mMeshLocalPrefix; } OT_TOOL_PACKED_END; +class SteeringData; + /** * This class implements Steering Data TLV generation and parsing. * @@ -775,88 +776,12 @@ public: void Clear(void) { memset(mSteeringData, 0, GetSteeringDataLength()); } /** - * Ths method sets all bits in the Bloom Filter to one. + * This method copies the Steering Data from the TLV into a given `SteeringData` variable. + * + * @param[out] aSteeringData A reference to a `SteeringData` to copy into. * */ - void Set(void) { memset(mSteeringData, 0xff, GetSteeringDataLength()); } - - /** - * Ths method indicates whether or not the SteeringData allows all Joiners. - * - * @retval TRUE If the SteeringData allows all Joiners. - * @retval FALSE If the SteeringData doesn't allow any Joiner. - * - */ - bool DoesAllowAny(void) - { - bool rval = true; - - for (uint8_t i = 0; i < GetSteeringDataLength(); i++) - { - if (mSteeringData[i] != 0xff) - { - rval = false; - break; - } - } - - return rval; - } - - /** - * This method returns the number of bits in the Bloom Filter. - * - * @returns The number of bits in the Bloom Filter. - * - */ - uint8_t GetNumBits(void) const { return GetSteeringDataLength() * 8; } - - /** - * This method indicates whether or not bit @p aBit is set. - * - * @param[in] aBit The bit offset. - * - * @retval TRUE If bit @p aBit is set. - * @retval FALSE If bit @p aBit is not set. - * - */ - bool GetBit(uint8_t aBit) const - { - return (mSteeringData[GetSteeringDataLength() - 1 - (aBit / 8)] & (1 << (aBit % 8))) != 0; - } - - /** - * This method clears bit @p aBit. - * - * @param[in] aBit The bit offset. - * - */ - void ClearBit(uint8_t aBit) { mSteeringData[GetSteeringDataLength() - 1 - (aBit / 8)] &= ~(1 << (aBit % 8)); } - - /** - * This method sets bit @p aBit. - * - * @param[in] aBit The bit offset. - * - */ - void SetBit(uint8_t aBit) { mSteeringData[GetSteeringDataLength() - 1 - (aBit / 8)] |= 1 << (aBit % 8); } - - /** - * Ths method indicates whether or not the SteeringData is all zeros. - * - * @retval TRUE If the SteeringData is all zeros. - * @retval FALSE If the SteeringData isn't all zeros. - * - */ - bool IsCleared(void) const; - - /** - * This method computes the Bloom Filter. - * - * @param[in] aJoinerId The Joiner ID. - * - */ - void ComputeBloomFilter(const otExtAddress &aJoinerId); + void CopyTo(SteeringData &aSteeringData); private: uint8_t mSteeringData[OT_STEERING_DATA_MAX_LENGTH]; diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 71e177bcf..eb7715b0a 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -92,8 +92,6 @@ Mle::Mle(Instance &aInstance) , mTimeout(kMleEndDeviceTimeout) , mDiscoverHandler(NULL) , mDiscoverContext(NULL) - , mDiscoverCcittIndex(0) - , mDiscoverAnsiIndex(0) , mDiscoverInProgress(false) , mDiscoverEnableFiltering(false) #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH @@ -525,21 +523,11 @@ otError Mle::Discover(const Mac::ChannelMask &aScanChannels, if (mDiscoverEnableFiltering) { Mac::ExtAddress extAddress; - Crc16 ccitt(Crc16::kCcitt); - Crc16 ansi(Crc16::kAnsi); Get().GetIeeeEui64(extAddress); MeshCoP::ComputeJoinerId(extAddress, extAddress); - // Compute bloom filter (for steering data) - for (size_t i = 0; i < sizeof(extAddress.m8); i++) - { - ccitt.Update(extAddress.m8[i]); - ansi.Update(extAddress.m8[i]); - } - - mDiscoverCcittIndex = ccitt.Get(); - mDiscoverAnsiIndex = ansi.Get(); + MeshCoP::SteeringData::CalculateHashBitIndexes(extAddress, mDiscoverFilterIndexes); } mDiscoverHandler = aCallback; @@ -3860,7 +3848,6 @@ void Mle::HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInf MeshCoP::Tlv meshcopTlv; MeshCoP::DiscoveryResponseTlv discoveryResponse; MeshCoP::NetworkNameTlv networkName; - MeshCoP::SteeringDataTlv steeringData; otActiveScanResult result; uint16_t offset; uint16_t end; @@ -3908,20 +3895,27 @@ void Mle::HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInf break; case MeshCoP::Tlv::kSteeringData: - aMessage.Read(offset, sizeof(steeringData), &steeringData); - VerifyOrExit(steeringData.IsValid(), error = OT_ERROR_PARSE); - - if (mDiscoverEnableFiltering) + if (meshcopTlv.GetLength() > 0) { - VerifyOrExit((steeringData.GetBit(mDiscoverCcittIndex % steeringData.GetNumBits()) && - steeringData.GetBit(mDiscoverAnsiIndex % steeringData.GetNumBits())), - OT_NOOP); + MeshCoP::SteeringData &steeringData = static_cast(result.mSteeringData); + uint8_t dataLength = MeshCoP::SteeringData::kMaxLength; + + if (meshcopTlv.GetLength() < dataLength) + { + dataLength = meshcopTlv.GetLength(); + } + + steeringData.Init(dataLength); + + SuccessOrExit(error = Tlv::ReadTlv(aMessage, offset, steeringData.GetData(), dataLength)); + + if (mDiscoverEnableFiltering) + { + VerifyOrExit(steeringData.Contains(mDiscoverFilterIndexes), OT_NOOP); + } + + didCheckSteeringData = true; } - - didCheckSteeringData = true; - result.mSteeringData.mLength = steeringData.GetSteeringDataLength(); - memcpy(result.mSteeringData.m8, steeringData.GetValue(), result.mSteeringData.mLength); - break; case MeshCoP::Tlv::kJoinerUdpPort: diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index bf7860bfb..1579976d8 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -41,6 +41,7 @@ #include "common/timer.hpp" #include "mac/mac.hpp" #include "meshcop/joiner_router.hpp" +#include "meshcop/meshcop.hpp" #include "net/udp6.hpp" #include "thread/mle_tlvs.hpp" #include "thread/mle_types.hpp" @@ -1787,12 +1788,11 @@ private: Ip6::UdpSocket mSocket; uint32_t mTimeout; - DiscoverHandler mDiscoverHandler; - void * mDiscoverContext; - uint16_t mDiscoverCcittIndex; - uint16_t mDiscoverAnsiIndex; - bool mDiscoverInProgress; - bool mDiscoverEnableFiltering; + DiscoverHandler mDiscoverHandler; + void * mDiscoverContext; + MeshCoP::SteeringData::HashBitIndexes mDiscoverFilterIndexes; + bool mDiscoverInProgress; + bool mDiscoverEnableFiltering; #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH uint16_t mPreviousParentRloc; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index f06423de7..4498c7d02 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -92,6 +92,10 @@ MleRouter::MleRouter(Instance &aInstance) mDeviceMode.Set(mDeviceMode.Get() | DeviceMode::kModeFullThreadDevice | DeviceMode::kModeFullNetworkData); SetRouterId(kInvalidRouterId); + +#if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE + mSteeringData.Clear(); +#endif } void MleRouter::HandlePartitionChange(void) @@ -2756,27 +2760,21 @@ void MleRouter::SetSteeringData(const Mac::ExtAddress *aExtAddress) nullExtAddr.Clear(); allowAnyExtAddr.Fill(0xff); - mSteeringData.Init(); - if ((aExtAddress == NULL) || (*aExtAddress == nullExtAddr)) { - // Clear steering data mSteeringData.Clear(); } else if (*aExtAddress == allowAnyExtAddr) { - // Set steering data to 0xFF - mSteeringData.SetLength(1); - mSteeringData.Set(); + mSteeringData.SetToPermitAllJoiners(); } else { Mac::ExtAddress joinerId; - // compute Joiner ID + mSteeringData.Init(); MeshCoP::ComputeJoinerId(*aExtAddress, joinerId); - // compute Bloom Filter - mSteeringData.ComputeBloomFilter(joinerId); + mSteeringData.UpdateBloomFilter(joinerId); } } #endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE @@ -2816,13 +2814,12 @@ void MleRouter::HandleDiscoveryRequest(const Message &aMessage, const Ip6::Messa if (discoveryRequest.IsJoiner()) { #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE - - if (!mSteeringData.IsCleared()) + if (!mSteeringData.IsEmpty()) { break; } else // if steering data is not set out of band, fall back to network data -#endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE +#endif { VerifyOrExit(Get().IsJoiningEnabled(), error = OT_ERROR_SECURITY); } @@ -2861,7 +2858,6 @@ otError MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, uint1 Tlv tlv; MeshCoP::DiscoveryResponseTlv discoveryResponse; MeshCoP::NetworkNameTlv networkName; - const MeshCoP::Tlv * steeringData; uint16_t delay; VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS); @@ -2903,17 +2899,18 @@ otError MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, uint1 SuccessOrExit(error = networkName.AppendTo(*message)); #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE - // If steering data is set out of band, use that value. // Otherwise use the one from commissioning data. - if (!mSteeringData.IsCleared()) + if (!mSteeringData.IsEmpty()) { - SuccessOrExit(error = mSteeringData.AppendTo(*message)); + SuccessOrExit(error = Tlv::AppendTlv(*message, MeshCoP::Tlv::kSteeringData, mSteeringData.GetData(), + mSteeringData.GetLength())); } else -#endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE +#endif { - // Steering Data TLV + const MeshCoP::Tlv *steeringData; + steeringData = Get().GetCommissioningDataSubTlv(MeshCoP::Tlv::kSteeringData); if (steeringData != NULL) diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 593f1cb45..90b9fca98 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -569,7 +569,7 @@ public: * */ void SetSteeringData(const Mac::ExtAddress *aExtAddress); -#endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE +#endif /** * This method gets the assigned parent priority. @@ -856,8 +856,8 @@ private: #endif #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE - MeshCoP::SteeringDataTlv mSteeringData; -#endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE + MeshCoP::SteeringData mSteeringData; +#endif }; #endif // OPENTHREAD_FTD diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 29f0f0d69..ee77cdbb6 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -425,6 +425,28 @@ target_link_libraries(test-pskc add_test(NAME test-pskc COMMAND test-pskc) +add_executable(test-steering-data + ${COMMON_SOURCES} + test_steering_data.cpp +) + +target_include_directories(test-steering-data + PRIVATE + ${COMMON_INCLUDES} +) + +target_compile_options(test-steering-data + PRIVATE + ${COMMON_COMPILE_OPTIONS} +) + +target_link_libraries(test-steering-data + PRIVATE + ${COMMON_LIBS} +) + +add_test(NAME test-steering-data COMMAND test-steering-data) + add_executable(test-string ${COMMON_SOURCES} test_string.cpp diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 99c186e26..0e3e9b1b9 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -123,6 +123,7 @@ check_PROGRAMS += \ test-network-data \ test-priority-queue \ test-pskc \ + test-steering-data \ test-string \ test-timer \ $(NULL) @@ -222,6 +223,9 @@ test_priority_queue_SOURCES = $(COMMON_SOURCES) test_priority_queue.cpp test_pskc_LDADD = $(COMMON_LDADD) test_pskc_SOURCES = $(COMMON_SOURCES) test_pskc.cpp +test_steering_data_LDADD = $(COMMON_LDADD) +test_steering_data_SOURCES = $(COMMON_SOURCES) test_steering_data.cpp + test_string_LDADD = $(COMMON_LDADD) test_string_SOURCES = $(COMMON_SOURCES) test_string.cpp diff --git a/tests/unit/test_steering_data.cpp b/tests/unit/test_steering_data.cpp new file mode 100644 index 000000000..50c75117c --- /dev/null +++ b/tests/unit/test_steering_data.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test_platform.h" + +#include + +#include "test_util.hpp" +#include "meshcop/meshcop.hpp" + +namespace ot { + +void TestSteeringData(void) +{ + MeshCoP::SteeringData steeringData; + MeshCoP::SteeringData::HashBitIndexes indexes; + Mac::ExtAddress joinerId1; + Mac::ExtAddress joinerId2; + + const uint8_t kAddress1[sizeof(Mac::ExtAddress)] = {0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x16}; + const uint8_t kAddress2[sizeof(Mac::ExtAddress)] = {0xbe, 0xef, 0xca, 0xfe, 0xde, 0xad, 0xba, 0xbe}; + + joinerId1.Set(kAddress1); + joinerId2.Set(kAddress2); + + MeshCoP::SteeringData::CalculateHashBitIndexes(joinerId2, indexes); + + steeringData.SetToPermitAllJoiners(); + + DumpBuffer("After SetToPermitAllJoiners()", steeringData.GetData(), steeringData.GetLength()); + VerifyOrQuit(steeringData.GetLength() == 1, "GetLength is incorrect after SetToPermitAllJoiners()"); + VerifyOrQuit(steeringData.PermitsAllJoiners(), "PermitsAllJoiners() failed after SetToPermitAllJoiners()"); + VerifyOrQuit(!steeringData.IsEmpty(), "IsEmpty() failed after SetToPermitAllJoiners()"); + VerifyOrQuit(steeringData.Contains(joinerId1), "Contains(joinerId1) failed after SetToPermitAllJoiners()"); + VerifyOrQuit(steeringData.Contains(joinerId2), "Contains(joinerId2) failed after SetToPermitAllJoiners()"); + VerifyOrQuit(steeringData.Contains(indexes), "Contains(indexes) failed after SetToPermitAllJoiners()"); + + steeringData.Clear(); + + DumpBuffer("After Clear()", steeringData.GetData(), steeringData.GetLength()); + VerifyOrQuit(steeringData.GetLength() == 1, "GetLength is incorrect after Clear()"); + VerifyOrQuit(!steeringData.PermitsAllJoiners(), "PermitsAllJoiners() failed after Clear()"); + VerifyOrQuit(steeringData.IsEmpty(), "IsEmpty() failed after Clear()"); + VerifyOrQuit(!steeringData.Contains(joinerId1), "Contains(joinerId1) failed after Clear()"); + VerifyOrQuit(!steeringData.Contains(joinerId2), "Contains(joinerId2) failed after Clear()"); + VerifyOrQuit(!steeringData.Contains(indexes), "Contains(indexes) failed after Clear()"); + + for (uint8_t len = 1; len <= MeshCoP::SteeringData::kMaxLength; len++) + { + printf("\n--------------------------------------------"); + + steeringData.Init(len); + + VerifyOrQuit(steeringData.GetLength() == len, "GetLength is incorrect after Init()"); + VerifyOrQuit(steeringData.IsEmpty(), "IsEmpy() failed after Init()"); + VerifyOrQuit(!steeringData.PermitsAllJoiners(), "PermitsAllJoiners() failed after Init()"); + VerifyOrQuit(!steeringData.Contains(joinerId1), "Contains(joinerId1) failed after Init()"); + VerifyOrQuit(!steeringData.Contains(joinerId2), "Contains(joinerId2) failed after Init()"); + VerifyOrQuit(!steeringData.Contains(indexes), "Contains(indexes) failed after Init()"); + + steeringData.UpdateBloomFilter(joinerId1); + DumpBuffer("After UpdateBloomFilter(joinerId1)", steeringData.GetData(), steeringData.GetLength()); + VerifyOrQuit(steeringData.GetLength() == len, "GetLength is incorrect after UpdateBloomFilter()"); + VerifyOrQuit(!steeringData.IsEmpty(), "IsEmpy() failed after UpdateBloomFilter()"); + VerifyOrQuit(!steeringData.PermitsAllJoiners(), "PermitsAllJoiners() failed after UpdateBloomFilter"); + VerifyOrQuit(steeringData.Contains(joinerId1), "Contains(joinerId1) failed after UpdateBloomFilter"); + + steeringData.UpdateBloomFilter(joinerId2); + DumpBuffer("After UpdateBloomFilter(joinerId2)", steeringData.GetData(), steeringData.GetLength()); + VerifyOrQuit(steeringData.GetLength() == len, "GetLength is incorrect after UpdateBloomFilter()"); + VerifyOrQuit(!steeringData.IsEmpty(), "IsEmpy() failed after UpdateBloomFilter()"); + VerifyOrQuit(!steeringData.PermitsAllJoiners(), "PermitsAllJoiners() failed after UpdateBloomFilter"); + VerifyOrQuit(steeringData.Contains(joinerId1), "Contains(joinerId1) failed after UpdateBloomFilter"); + VerifyOrQuit(steeringData.Contains(joinerId2), "Contains(joinerId2) failed after UpdateBloomFilter"); + VerifyOrQuit(steeringData.Contains(indexes), "Contains(joinerId2) failed after UpdateBloomFilter"); + } + + steeringData.Init(0); + + VerifyOrQuit(steeringData.GetLength() == 0, "GetLength is incorrect after Init()"); + VerifyOrQuit(steeringData.IsEmpty(), "IsEmpy() failed after Init()"); + VerifyOrQuit(!steeringData.PermitsAllJoiners(), "PermitsAllJoiners() failed after Init()"); + VerifyOrQuit(!steeringData.Contains(joinerId1), "Contains(joinerId1) failed after Init()"); + VerifyOrQuit(!steeringData.Contains(joinerId2), "Contains(joinerId2) failed after Init()"); + VerifyOrQuit(!steeringData.Contains(indexes), "Contains(indexes) failed after Init()"); +} + +} // namespace ot + +int main(void) +{ + ot::TestSteeringData(); + printf("\nAll tests passed.\n"); + return 0; +}