From 243642272a891fbd92bd30b8f5325d380d1bf9d4 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 15 May 2018 19:35:14 -0700 Subject: [PATCH] [meshcop-tlvs] new methods for parsing Channel Mask Entry (#2705) This commit adds new methods/classes related to parsing of Channel Mask Entries in a Channel Mask TLV. A new class `ChannelMask0Entry` is added for a Channel Mask Entry with Channel Page 0. `ChannelMaskTlv::GetFirstEntry()` and`ChannelMaskEntry:GetNext()` methods are added and can be used to iterate through all the entries in a Channel Mask TLV. New method `ChannelMaskTlv::GetMask0Entry()` can be used to search among all entries to find the one with Channel Page 0 (if one exist). --- src/core/meshcop/dataset.cpp | 19 ++--- src/core/meshcop/meshcop_tlvs.cpp | 44 ++++++++++++ src/core/meshcop/meshcop_tlvs.hpp | 111 +++++++++++++++++++++++------- src/core/thread/mle.cpp | 34 +++++---- 4 files changed, 155 insertions(+), 53 deletions(-) diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index b85a0550e..79602d507 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -144,22 +144,13 @@ void Dataset::Get(otOperationalDataset &aDataset) const case Tlv::kChannelMask: { - uint8_t length = cur->GetLength(); - const uint8_t *entry = reinterpret_cast(cur) + sizeof(Tlv); - const uint8_t *entryEnd = entry + length; + const ChannelMaskTlv * tlv = static_cast(cur); + const ChannelMask0Entry *entry = tlv->GetMask0Entry(); - while (entry < entryEnd) + if (entry != NULL) { - if (reinterpret_cast(entry)->GetChannelPage() == 0) - { - const ChannelMask0Tlv *tlv = static_cast(cur); - aDataset.mChannelMaskPage0 = tlv->GetMask(); - aDataset.mIsChannelMaskPage0Set = true; - break; - } - - entry += - (reinterpret_cast(entry)->GetMaskLength() + sizeof(ChannelMaskEntry)); + aDataset.mChannelMaskPage0 = entry->GetMask(); + aDataset.mIsChannelMaskPage0Set = true; } break; diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index 46d095db8..75a36b8cf 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -113,5 +113,49 @@ void SteeringDataTlv::ComputeBloomFilter(const otExtAddress &aJoinerId) SetBit(ansi.Get() % GetNumBits()); } +const ChannelMaskEntry *ChannelMaskEntry::GetNext(const Tlv *aChannelMaskTlv) const +{ + const uint8_t *entry = reinterpret_cast(this) + GetSize(); + const uint8_t *end = aChannelMaskTlv->GetValue() + aChannelMaskTlv->GetSize(); + + return (entry < end) ? reinterpret_cast(entry) : NULL; +} + +const ChannelMaskEntry *ChannelMaskTlv::GetFirstEntry(void) const +{ + const ChannelMaskEntry *entry = NULL; + + VerifyOrExit(GetLength() >= sizeof(ChannelMaskEntry)); + + entry = reinterpret_cast(GetValue()); + VerifyOrExit(GetLength() >= entry->GetSize(), entry = NULL); + +exit: + return entry; +} + +const ChannelMask0Entry *ChannelMaskTlv::GetMask0Entry(void) const +{ + const ChannelMask0Entry *page0Entry = NULL; + + for (const ChannelMaskEntry *entry = GetFirstEntry(); entry != NULL; entry = entry->GetNext(this)) + { + if (entry->GetChannelPage() == 0) + { + page0Entry = static_cast(entry); + + if (page0Entry->IsValid()) + { + ExitNow(); + } + } + } + + page0Entry = NULL; + +exit: + return page0Entry; +} + } // namespace MeshCoP } // namespace ot diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 508d58373..07673be78 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -1330,6 +1330,14 @@ public: */ void SetMaskLength(uint8_t aMaskLength) { mMaskLength = aMaskLength; } + /** + * This method returns the total size of this Channel Mask Entry including the mask. + * + * @returns The total size of this entry (number of bytes). + * + */ + uint8_t GetSize(void) const { return sizeof(ChannelMaskEntry) + mMaskLength; } + /** * This method clears the bit corresponding to @p aChannel in ChannelMask. * @@ -1366,11 +1374,68 @@ public: return (aChannel < (mMaskLength * 8)) ? ((mask[aChannel / 8] & (0x80 >> (aChannel % 8))) != 0) : false; } + /** + * This method gets the next Channel Mask Entry in a Channel Mask TLV. + * + * @param[in] aChannelMaskTlv A pointer to the Channel Mask TLV to which this entry belongs. + * + * @returns A pointer to next Channel Mask Entry or NULL if none found. + * + */ + const ChannelMaskEntry *GetNext(const Tlv *aChannelMaskTlv) const; + private: uint8_t mChannelPage; uint8_t mMaskLength; } OT_TOOL_PACKED_END; +/** + * This class implements Channel Mask Entry Page 0 generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class ChannelMask0Entry : public ChannelMaskEntry +{ +public: + /** + * This method initializes the entry. + * + */ + void Init(void) + { + SetChannelPage(0); + SetMaskLength(sizeof(mMask)); + } + + /** + * This method indicates whether or not the entry appears to be well-formed. + * + * @retval TRUE If the entry appears to be well-formed. + * @retval FALSE If the entry does not appear to be well-formed. + * + */ + bool IsValid(void) const { return GetChannelPage() == 0 && GetMaskLength() == sizeof(mMask); } + + /** + * This method returns the Channel Mask value as a `uint32_t` bit mask. + * + * @returns The Channel Mask value. + * + */ + uint32_t GetMask(void) const { return Reverse32(HostSwap32(mMask)); } + + /** + * This method sets the Channel Mask value. + * + * @param[in] aMask The Channel Mask value. + * + */ + void SetMask(uint32_t aMask) { mMask = HostSwap32(Reverse32(aMask)); } + +private: + uint32_t mMask; +} OT_TOOL_PACKED_END; + /** * This class implements Channel Mask TLV generation and parsing. * @@ -1397,6 +1462,23 @@ public: * */ bool IsValid(void) const { return true; } + + /** + * This method gets the first Channel Mask Entry in the Channel Mask TLV. + * + * @returns A pointer to first Channel Mask Entry or NULL if not found. + * + */ + const ChannelMaskEntry *GetFirstEntry(void) const; + + /** + * This method gets the Page 0 Channel Mask Entry in the Channel Mask TLV. + * + * @returns A pointer to Page 0 Channel Mask Entry or NULL if not found. + * + */ + const ChannelMask0Entry *GetMask0Entry(void) const; + } OT_TOOL_PACKED_END; /** @@ -1404,7 +1486,7 @@ public: * */ OT_TOOL_PACKED_BEGIN -class ChannelMask0Tlv : public ChannelMaskTlv, public ChannelMaskEntry +class ChannelMask0Tlv : public ChannelMaskTlv, public ChannelMask0Entry { public: /** @@ -1415,8 +1497,7 @@ public: { SetType(kChannelMask); SetLength(sizeof(*this) - sizeof(Tlv)); - SetChannelPage(0); - SetMaskLength(sizeof(mMask)); + ChannelMask0Entry::Init(); } /** @@ -1426,29 +1507,7 @@ public: * @retval FALSE If the TLV does not appear to be well-formed. * */ - bool IsValid(void) const - { - return GetLength() == sizeof(*this) - sizeof(Tlv) && GetChannelPage() == 0 && GetMaskLength() == sizeof(mMask); - } - - /** - * This method returns the Channel Mask value. - * - * @returns The Channel Mask value. - * - */ - uint32_t GetMask(void) const { return Reverse32(HostSwap32(mMask)); } - - /** - * This method sets the Channel Mask value. - * - * @param[in] aMask The Channel Mask value. - * - */ - void SetMask(uint32_t aMask) { mMask = HostSwap32(Reverse32(aMask)); } - -private: - uint32_t mMask; + bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv) && ChannelMask0Entry::IsValid(); } } OT_TOOL_PACKED_END; /** diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 61956cdbf..470d9894b 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1547,22 +1547,26 @@ exit: bool Mle::PrepareAnnounceState(void) { - bool shouldAnnounce = false; - uint16_t numChannels = 0; - const MeshCoP::ChannelMask0Tlv *channelMask; - MeshCoP::Dataset dataset(MeshCoP::Tlv::kActiveTimestamp); + bool shouldAnnounce = false; + uint16_t numChannels = 0; + const MeshCoP::ChannelMaskTlv * channelMaskTlv; + const MeshCoP::ChannelMask0Entry *channelMaskEntry; + MeshCoP::Dataset dataset(MeshCoP::Tlv::kActiveTimestamp); VerifyOrExit((mRole != OT_DEVICE_ROLE_CHILD) && ((mDeviceMode & ModeTlv::kModeFFD) == 0) && (mReattachState == kReattachStop)); SuccessOrExit(GetNetif().GetActiveDataset().Get(dataset)); - channelMask = static_cast(dataset.Get(MeshCoP::Tlv::kChannelMask)); - VerifyOrExit(channelMask != NULL); + channelMaskTlv = static_cast(dataset.Get(MeshCoP::Tlv::kChannelMask)); + VerifyOrExit(channelMaskTlv != NULL); + + channelMaskEntry = channelMaskTlv->GetMask0Entry(); + VerifyOrExit(channelMaskEntry != NULL); for (uint8_t channel = OT_RADIO_CHANNEL_MIN; channel <= OT_RADIO_CHANNEL_MAX; channel++) { - if (channelMask->IsChannelSet(channel)) + if (channelMaskEntry->IsChannelSet(channel)) { numChannels++; } @@ -2127,18 +2131,22 @@ exit: otError Mle::SendOrphanAnnounce(void) { - otError error = OT_ERROR_NONE; - const MeshCoP::ChannelMask0Tlv *channelMask; - MeshCoP::Dataset dataset(MeshCoP::Tlv::kActiveTimestamp); + otError error = OT_ERROR_NONE; + const MeshCoP::ChannelMaskTlv * channelMaskTlv; + const MeshCoP::ChannelMask0Entry *channelMaskEntry; + MeshCoP::Dataset dataset(MeshCoP::Tlv::kActiveTimestamp); SuccessOrExit(error = GetNetif().GetActiveDataset().Get(dataset)); - channelMask = static_cast(dataset.Get(MeshCoP::Tlv::kChannelMask)); - VerifyOrExit(channelMask != NULL, error = OT_ERROR_NOT_FOUND); + channelMaskTlv = static_cast(dataset.Get(MeshCoP::Tlv::kChannelMask)); + VerifyOrExit(channelMaskTlv != NULL, error = OT_ERROR_NOT_FOUND); + + channelMaskEntry = channelMaskTlv->GetMask0Entry(); + VerifyOrExit(channelMaskEntry != NULL, error = OT_ERROR_NOT_FOUND); VerifyOrExit(mAnnounceChannel <= OT_RADIO_CHANNEL_MAX, error = OT_ERROR_NOT_FOUND); - while (!channelMask->IsChannelSet(mAnnounceChannel)) + while (!channelMaskEntry->IsChannelSet(mAnnounceChannel)) { mAnnounceChannel++; VerifyOrExit(mAnnounceChannel <= OT_RADIO_CHANNEL_MAX, error = OT_ERROR_NOT_FOUND);