[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).
This commit is contained in:
Abtin Keshavarzian
2018-05-15 19:35:14 -07:00
committed by Jonathan Hui
parent 7f901cf9c7
commit 243642272a
4 changed files with 155 additions and 53 deletions
+5 -14
View File
@@ -144,22 +144,13 @@ void Dataset::Get(otOperationalDataset &aDataset) const
case Tlv::kChannelMask:
{
uint8_t length = cur->GetLength();
const uint8_t *entry = reinterpret_cast<const uint8_t *>(cur) + sizeof(Tlv);
const uint8_t *entryEnd = entry + length;
const ChannelMaskTlv * tlv = static_cast<const ChannelMaskTlv *>(cur);
const ChannelMask0Entry *entry = tlv->GetMask0Entry();
while (entry < entryEnd)
if (entry != NULL)
{
if (reinterpret_cast<const ChannelMaskEntry *>(entry)->GetChannelPage() == 0)
{
const ChannelMask0Tlv *tlv = static_cast<const ChannelMask0Tlv *>(cur);
aDataset.mChannelMaskPage0 = tlv->GetMask();
aDataset.mIsChannelMaskPage0Set = true;
break;
}
entry +=
(reinterpret_cast<const ChannelMaskEntry *>(entry)->GetMaskLength() + sizeof(ChannelMaskEntry));
aDataset.mChannelMaskPage0 = entry->GetMask();
aDataset.mIsChannelMaskPage0Set = true;
}
break;
+44
View File
@@ -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<const uint8_t *>(this) + GetSize();
const uint8_t *end = aChannelMaskTlv->GetValue() + aChannelMaskTlv->GetSize();
return (entry < end) ? reinterpret_cast<const ChannelMaskEntry *>(entry) : NULL;
}
const ChannelMaskEntry *ChannelMaskTlv::GetFirstEntry(void) const
{
const ChannelMaskEntry *entry = NULL;
VerifyOrExit(GetLength() >= sizeof(ChannelMaskEntry));
entry = reinterpret_cast<const ChannelMaskEntry *>(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<const ChannelMask0Entry *>(entry);
if (page0Entry->IsValid())
{
ExitNow();
}
}
}
page0Entry = NULL;
exit:
return page0Entry;
}
} // namespace MeshCoP
} // namespace ot
+85 -26
View File
@@ -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;
/**
+21 -13
View File
@@ -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<const MeshCoP::ChannelMask0Tlv *>(dataset.Get(MeshCoP::Tlv::kChannelMask));
VerifyOrExit(channelMask != NULL);
channelMaskTlv = static_cast<const MeshCoP::ChannelMaskTlv *>(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<const MeshCoP::ChannelMask0Tlv *>(dataset.Get(MeshCoP::Tlv::kChannelMask));
VerifyOrExit(channelMask != NULL, error = OT_ERROR_NOT_FOUND);
channelMaskTlv = static_cast<const MeshCoP::ChannelMaskTlv *>(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);