[meshcop-tlvs] simplify and enhance ChannelMaskTlv (#9675)

This commit simplifies `ChannelMaskTlv` generation and parsing.
Notably, it ensures that when we read this TLV from a `Message` the
TLV value format is validated. The changes include:
- `Entry` class representing a channel page entry is now defined as
  a `private` nested class within `ChannelMaskTlv`.
- A shared `EntriesData::Parse()` method is added that validates and
  parses the entries in the TLV, whether the TLV value resides in a
  buffer (e.g., within `Dataset`) or in a `Message`.
- `ChannelMaskTlv::AppendTo()` method is added to construct entries
  from a given combined channel mask (for all pages) and append the
  `ChannelMaskTlv` to a given `Message`.
- `Radio::kSupportedChannelPages` is changed to an array
  (containing all supported pages) instead of mask.
- Helper functions added in `Radio`, `SupportsChannelPage()` to
  verify if a channel page is supported by the radio, and
  `ChannelMaskForPage()` to obtain the supported channel mask for
  a given page.
This commit is contained in:
Abtin Keshavarzian
2023-12-05 10:54:17 -08:00
committed by GitHub
parent 4ed44bc7d5
commit 3754174c54
15 changed files with 310 additions and 448 deletions
+4 -7
View File
@@ -60,10 +60,9 @@ Error AnnounceBeginClient::SendRequest(uint32_t aChannelMask,
uint16_t aPeriod,
const Ip6::Address &aAddress)
{
Error error = kErrorNone;
MeshCoP::ChannelMaskTlv channelMask;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message = nullptr;
Error error = kErrorNone;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message = nullptr;
VerifyOrExit(Get<MeshCoP::Commissioner>().IsActive(), error = kErrorInvalidState);
VerifyOrExit((message = Get<Tmf::Agent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
@@ -74,9 +73,7 @@ Error AnnounceBeginClient::SendRequest(uint32_t aChannelMask,
SuccessOrExit(
error = Tlv::Append<MeshCoP::CommissionerSessionIdTlv>(*message, Get<MeshCoP::Commissioner>().GetSessionId()));
channelMask.Init();
channelMask.SetChannelMask(aChannelMask);
SuccessOrExit(error = channelMask.AppendTo(*message));
SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, aChannelMask));
SuccessOrExit(error = Tlv::Append<MeshCoP::CountTlv>(*message, aCount));
SuccessOrExit(error = Tlv::Append<MeshCoP::PeriodTlv>(*message, aPeriod));
+6 -6
View File
@@ -199,9 +199,9 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const
case Tlv::kChannelMask:
{
uint32_t mask = As<ChannelMaskTlv>(cur)->GetChannelMask();
uint32_t mask;
if (mask != 0)
if (As<ChannelMaskTlv>(cur)->ReadChannelMask(mask) == kErrorNone)
{
aDatasetInfo.SetChannelMask(mask);
}
@@ -312,10 +312,10 @@ Error Dataset::SetFrom(const Info &aDatasetInfo)
if (aDatasetInfo.IsChannelMaskPresent())
{
ChannelMaskTlv tlv;
tlv.Init();
tlv.SetChannelMask(aDatasetInfo.GetChannelMask());
IgnoreError(WriteTlv(tlv));
ChannelMaskTlv::Value value;
ChannelMaskTlv::PrepareValue(value, aDatasetInfo.GetChannelMask());
IgnoreError(WriteTlv(Tlv::kChannelMask, value.mData, value.mLength));
}
if (aDatasetInfo.IsExtendedPanIdPresent())
+1 -1
View File
@@ -228,7 +228,7 @@ Error DatasetManager::GetChannelMask(Mac::ChannelMask &aChannelMask) const
channelMaskTlv = As<ChannelMaskTlv>(dataset.FindTlv(Tlv::kChannelMask));
VerifyOrExit(channelMaskTlv != nullptr, error = kErrorNotFound);
VerifyOrExit((mask = channelMaskTlv->GetChannelMask()) != 0);
SuccessOrExit(channelMaskTlv->ReadChannelMask(mask));
aChannelMask.SetMask(mask & Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
+4 -4
View File
@@ -319,10 +319,10 @@ Error ActiveDatasetManager::GenerateLocal(void)
if (!dataset.Contains<ChannelMaskTlv>())
{
ChannelMaskTlv tlv;
tlv.Init();
tlv.SetChannelMask(Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
IgnoreError(dataset.WriteTlv(tlv));
ChannelMaskTlv::Value value;
ChannelMaskTlv::PrepareValue(value, Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
IgnoreError(dataset.WriteTlv(Tlv::kChannelMask, value.mData, value.mLength));
}
if (!dataset.Contains<ExtendedPanIdTlv>())
+5 -8
View File
@@ -66,10 +66,9 @@ Error EnergyScanClient::SendQuery(uint32_t aChannelMas
otCommissionerEnergyReportCallback aCallback,
void *aContext)
{
Error error = kErrorNone;
MeshCoP::ChannelMaskTlv channelMask;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message = nullptr;
Error error = kErrorNone;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message = nullptr;
VerifyOrExit(Get<MeshCoP::Commissioner>().IsActive(), error = kErrorInvalidState);
VerifyOrExit((message = Get<Tmf::Agent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
@@ -80,9 +79,7 @@ Error EnergyScanClient::SendQuery(uint32_t aChannelMas
SuccessOrExit(
error = Tlv::Append<MeshCoP::CommissionerSessionIdTlv>(*message, Get<MeshCoP::Commissioner>().GetSessionId()));
channelMask.Init();
channelMask.SetChannelMask(aChannelMask);
SuccessOrExit(error = channelMask.AppendTo(*message));
SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, aChannelMask));
SuccessOrExit(error = Tlv::Append<MeshCoP::CountTlv>(*message, aCount));
SuccessOrExit(error = Tlv::Append<MeshCoP::PeriodTlv>(*message, aPeriod));
@@ -110,7 +107,7 @@ void EnergyScanClient::HandleTmf<kUriEnergyReport>(Coap::Message &aMessage, cons
LogInfo("Received %s", UriToString<kUriEnergyReport>());
VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0);
SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask));
SuccessOrExit(MeshCoP::Tlv::FindTlv(aMessage, MeshCoP::Tlv::kEnergyList, sizeof(energyListTlv), energyListTlv));
+107 -158
View File
@@ -158,191 +158,140 @@ const char *StateTlv::StateToString(State aState)
return aState == kReject ? kStateStrings[2] : kStateStrings[aState];
}
bool ChannelMaskBaseTlv::IsValid(void) const
bool ChannelMaskTlv::IsValid(void) const
{
const ChannelMaskEntryBase *cur = GetFirstEntry();
const ChannelMaskEntryBase *end = reinterpret_cast<const ChannelMaskEntryBase *>(GetNext());
bool ret = false;
uint32_t channelMask;
VerifyOrExit(cur != nullptr);
while (cur < end)
{
uint8_t channelPage;
VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end);
channelPage = cur->GetChannelPage();
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
if (channelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE)
#else
if ((channelPage == OT_RADIO_CHANNEL_PAGE_0) || (channelPage == OT_RADIO_CHANNEL_PAGE_2))
#endif
{
VerifyOrExit(static_cast<const ChannelMaskEntry *>(cur)->IsValid());
}
cur = cur->GetNext();
}
ret = true;
exit:
return ret;
return (ReadChannelMask(channelMask) == kErrorNone);
}
const ChannelMaskEntryBase *ChannelMaskBaseTlv::GetFirstEntry(void) const
Error ChannelMaskTlv::ReadChannelMask(uint32_t &aChannelMask) const
{
const ChannelMaskEntryBase *entry = nullptr;
EntriesData entriesData;
VerifyOrExit(GetLength() >= sizeof(ChannelMaskEntryBase));
entriesData.Clear();
entriesData.mData = &mEntriesStart;
entriesData.mLength = GetLength();
entry = reinterpret_cast<const ChannelMaskEntryBase *>(GetValue());
VerifyOrExit(GetLength() >= entry->GetEntrySize(), entry = nullptr);
exit:
return entry;
return entriesData.Parse(aChannelMask);
}
ChannelMaskEntryBase *ChannelMaskBaseTlv::GetFirstEntry(void) { return AsNonConst(AsConst(this)->GetFirstEntry()); }
void ChannelMaskTlv::SetChannelMask(uint32_t aChannelMask)
Error ChannelMaskTlv::FindIn(const Message &aMessage, uint32_t &aChannelMask)
{
uint8_t length = 0;
ChannelMaskEntry *entry;
Error error;
EntriesData entriesData;
entry = static_cast<ChannelMaskEntry *>(GetFirstEntry());
entriesData.Clear();
entriesData.mMessage = &aMessage;
#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
if (aChannelMask & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK)
{
OT_ASSERT(entry != nullptr);
entry->Init();
entry->SetChannelPage(OT_RADIO_CHANNEL_PAGE_2);
entry->SetMask(aChannelMask & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK);
length += sizeof(ChannelMaskEntry);
entry = static_cast<ChannelMaskEntry *>(entry->GetNext());
}
#endif
#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
if (aChannelMask & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK)
{
OT_ASSERT(entry != nullptr);
entry->Init();
entry->SetChannelPage(OT_RADIO_CHANNEL_PAGE_0);
entry->SetMask(aChannelMask & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK);
length += sizeof(ChannelMaskEntry);
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
if (aChannelMask & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK)
{
OT_ASSERT(entry != nullptr);
entry->Init();
entry->SetChannelPage(OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE);
entry->SetMask(aChannelMask & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK);
length += sizeof(ChannelMaskEntry);
}
#endif
SetLength(length);
}
uint32_t ChannelMaskTlv::GetChannelMask(void) const
{
const ChannelMaskEntryBase *cur = GetFirstEntry();
const ChannelMaskEntryBase *end = reinterpret_cast<const ChannelMaskEntryBase *>(GetNext());
uint32_t mask = 0;
VerifyOrExit(cur != nullptr);
while (cur < end)
{
uint8_t channelPage;
VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end);
channelPage = cur->GetChannelPage();
#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
if (channelPage == OT_RADIO_CHANNEL_PAGE_2)
{
mask |= static_cast<const ChannelMaskEntry *>(cur)->GetMask() & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
}
#endif
#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
if (channelPage == OT_RADIO_CHANNEL_PAGE_0)
{
mask |= static_cast<const ChannelMaskEntry *>(cur)->GetMask() & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
if (channelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE)
{
mask |= static_cast<const ChannelMaskEntry *>(cur)->GetMask() &
OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
}
#endif
cur = cur->GetNext();
}
SuccessOrExit(error = FindTlvValueOffset(aMessage, Tlv::kChannelMask, entriesData.mOffset, entriesData.mLength));
error = entriesData.Parse(aChannelMask);
exit:
return mask;
return error;
}
uint32_t ChannelMaskTlv::GetChannelMask(const Message &aMessage)
Error ChannelMaskTlv::EntriesData::Parse(uint32_t &aChannelMask)
{
uint32_t mask = 0;
uint16_t offset;
uint16_t end;
// Validates and parses the Channel Mask TLV entries for each
// channel page and if successful updates `aChannelMask` to
// return the combined mask for all channel pages supported by
// radio. The entries can be either contained in `mMessage` from
// `mOffset` (when `mMessage` is non-null) or be in a buffer
// `mData`. `mLength` gives the number of bytes for all entries.
SuccessOrExit(FindTlvValueStartEndOffsets(aMessage, kChannelMask, offset, end));
Error error = kErrorParse;
Entry readEntry;
const Entry *entry;
uint16_t size;
while (offset + sizeof(ChannelMaskEntryBase) <= end)
aChannelMask = 0;
VerifyOrExit(mLength > 0); // At least one entry.
while (mLength > 0)
{
ChannelMaskEntry entry;
VerifyOrExit(mLength > kEntryHeaderSize);
IgnoreError(aMessage.Read(offset, entry));
VerifyOrExit(offset + entry.GetEntrySize() <= end);
switch (entry.GetChannelPage())
if (mMessage != nullptr)
{
#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
case OT_RADIO_CHANNEL_PAGE_0:
IgnoreError(aMessage.Read(offset, entry));
mask |= entry.GetMask() & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
break;
#endif
// We first read the entry's header only and after
// validating the entry and that the entry's channel page
// is supported by radio, we read the full `Entry`.
#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
case OT_RADIO_CHANNEL_PAGE_2:
IgnoreError(aMessage.Read(offset, entry));
mask |= entry.GetMask() & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
break;
#endif
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
case OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE:
IgnoreError(aMessage.Read(offset, entry));
mask |= entry.GetMask() & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
break;
#endif
mMessage->ReadBytes(mOffset, &readEntry, kEntryHeaderSize);
entry = &readEntry;
}
else
{
entry = reinterpret_cast<const Entry *>(mData);
}
size = kEntryHeaderSize + entry->GetMaskLength();
VerifyOrExit(size <= mLength);
if (Radio::SupportsChannelPage(entry->GetChannelPage()))
{
// Currently supported channel pages all use `uint32_t`
// channel mask.
VerifyOrExit(entry->GetMaskLength() == kMaskLength);
if (mMessage != nullptr)
{
IgnoreError(mMessage->Read(mOffset, readEntry));
}
aChannelMask |= (entry->GetMask() & Radio::ChannelMaskForPage(entry->GetChannelPage()));
}
mLength -= size;
if (mMessage != nullptr)
{
mOffset += size;
}
else
{
mData += size;
}
offset += entry.GetEntrySize();
}
error = kErrorNone;
exit:
return mask;
return error;
}
void ChannelMaskTlv::PrepareValue(Value &aValue, uint32_t aChannelMask)
{
Entry *entry = reinterpret_cast<Entry *>(aValue.mData);
aValue.mLength = 0;
for (uint8_t page : Radio::kSupportedChannelPages)
{
uint32_t mask = (Radio::ChannelMaskForPage(page) & aChannelMask);
if (mask != 0)
{
entry->SetChannelPage(page);
entry->SetMaskLength(kMaskLength);
entry->SetMask(mask);
aValue.mLength += sizeof(Entry);
entry++;
}
}
}
Error ChannelMaskTlv::AppendTo(Message &aMessage, uint32_t aChannelMask)
{
Value value;
PrepareValue(value, aChannelMask);
return Tlv::Append<ChannelMaskTlv>(aMessage, value.mData, value.mLength);
}
} // namespace MeshCoP
+75 -212
View File
@@ -613,258 +613,121 @@ typedef SimpleTlvInfo<Tlv::kPendingTimestamp, Timestamp> PendingTimestampTlv;
*/
typedef UintTlvInfo<Tlv::kDelayTimer, uint32_t> DelayTimerTlv;
// forward declare ChannelMaskTlv
class ChannelMaskTlv;
/**
* Implements Channel Mask Entry generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ChannelMaskEntryBase
{
public:
/**
* Gets the ChannelPage value.
*
* @returns The ChannelPage value.
*
*/
uint8_t GetChannelPage(void) const { return mChannelPage; }
/**
* Sets the ChannelPage value.
*
* @param[in] aChannelPage The ChannelPage value.
*
*/
void SetChannelPage(uint8_t aChannelPage) { mChannelPage = aChannelPage; }
/**
* Gets the MaskLength value.
*
* @returns The MaskLength value.
*
*/
uint8_t GetMaskLength(void) const { return mMaskLength; }
/**
* Sets the MaskLength value.
*
* @param[in] aMaskLength The MaskLength value.
*
*/
void SetMaskLength(uint8_t aMaskLength) { mMaskLength = aMaskLength; }
/**
* Returns the total size of this Channel Mask Entry including the mask.
*
* @returns The total size of this entry (number of bytes).
*
*/
uint16_t GetEntrySize(void) const { return sizeof(ChannelMaskEntryBase) + mMaskLength; }
/**
* Clears the bit corresponding to @p aChannel in ChannelMask.
*
* @param[in] aChannel The channel in ChannelMask to clear.
*
*/
void ClearChannel(uint8_t aChannel)
{
uint8_t *mask = reinterpret_cast<uint8_t *>(this) + sizeof(*this);
mask[aChannel / 8] &= ~(0x80 >> (aChannel % 8));
}
/**
* Sets the bit corresponding to @p aChannel in ChannelMask.
*
* @param[in] aChannel The channel in ChannelMask to set.
*
*/
void SetChannel(uint8_t aChannel)
{
uint8_t *mask = reinterpret_cast<uint8_t *>(this) + sizeof(*this);
mask[aChannel / 8] |= 0x80 >> (aChannel % 8);
}
/**
* Indicates whether or not the bit corresponding to @p aChannel in ChannelMask is set.
*
* @param[in] aChannel The channel in ChannelMask to get.
*
*/
bool IsChannelSet(uint8_t aChannel) const
{
const uint8_t *mask = reinterpret_cast<const uint8_t *>(this) + sizeof(*this);
return (aChannel < (mMaskLength * 8)) ? ((mask[aChannel / 8] & (0x80 >> (aChannel % 8))) != 0) : false;
}
/**
* Gets the next Channel Mask Entry in a Channel Mask TLV.
*
* @returns A pointer to next Channel Mask Entry.
*
*/
const ChannelMaskEntryBase *GetNext(void) const
{
return reinterpret_cast<const ChannelMaskEntryBase *>(reinterpret_cast<const uint8_t *>(this) + GetEntrySize());
}
/**
* Gets the next Channel Mask Entry in a Channel Mask TLV.
*
* @returns A pointer to next Channel Mask Entry.
*
*/
ChannelMaskEntryBase *GetNext(void) { return AsNonConst(AsConst(this)->GetNext()); }
private:
uint8_t mChannelPage;
uint8_t mMaskLength;
} OT_TOOL_PACKED_END;
/**
* Implements Channel Mask Entry Page 0 generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ChannelMaskEntry : public ChannelMaskEntryBase
{
public:
/**
* Initializes the entry.
*
*/
void Init(void)
{
SetChannelPage(0);
SetMaskLength(sizeof(mMask));
}
/**
* 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 GetMaskLength() == sizeof(mMask); }
/**
* Returns the Channel Mask value as a `uint32_t` bit mask.
*
* @returns The Channel Mask value.
*
*/
uint32_t GetMask(void) const { return Reverse32(BigEndian::HostSwap32(mMask)); }
/**
* Sets the Channel Mask value.
*
* @param[in] aMask The Channel Mask value.
*
*/
void SetMask(uint32_t aMask) { mMask = BigEndian::HostSwap32(Reverse32(aMask)); }
private:
uint32_t mMask;
} OT_TOOL_PACKED_END;
/**
* Implements Channel Mask TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ChannelMaskBaseTlv : public Tlv, public TlvInfo<Tlv::kChannelMask>
class ChannelMaskTlv : public Tlv, public TlvInfo<Tlv::kChannelMask>
{
static constexpr uint8_t kEntryHeaderSize = 2; // Two bytes: mChannelPage and mMaskLength
static constexpr uint8_t kEntrySize = kEntryHeaderSize + sizeof(uint32_t);
public:
/**
* Initializes the TLV.
* Represents Channel Mask TLV value to append.
*
*/
void Init(void)
struct Value
{
SetType(kChannelMask);
SetLength(sizeof(*this) - sizeof(Tlv));
}
static constexpr uint16_t kMaxLength = (kEntrySize * Radio::kNumChannelPages); ///< Max value length.
uint8_t mData[kMaxLength]; ///< Array to store TLV value (encoded as one or more Channel Mask TLV Entry)
uint8_t mLength; ///< Value length in bytes.
};
ChannelMaskTlv(void) = delete;
/**
* Indicates whether or not the TLV appears to be well-formed.
* Parses the Channel Mask TLV value and validates that all the included entries are well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
* @returns TRUE if the TLV is well-formed, FALSE otherwise.
*
*/
bool IsValid(void) const;
/**
* Gets the first Channel Mask Entry in the Channel Mask TLV.
* Parses and retrieves the combined channel mask for all supported channel pages from entries in the TLV.
*
* @returns A pointer to first Channel Mask Entry or `nullptr` if not found.
* @param[out] aChannelMask A reference to return the channel mask.
*
* @retval kErrorNone Successfully parsed the TLV value, @p aChannelMask is updated.
* @retval kErrorParse TLV value is not well-formed.
*
*/
const ChannelMaskEntryBase *GetFirstEntry(void) const;
Error ReadChannelMask(uint32_t &aChannelMask) const;
/**
* Gets the first Channel Mask Entry in the Channel Mask TLV.
* Searches within a given message for Channel Mask TLV, parses and validates the TLV value and returns the
* combined channel mask for all supported channel pages included in the TLV.
*
* @returns A pointer to first Channel Mask Entry or `nullptr` if not found.
* @param[in] aMessage The message to search in.
* @param[out] aChannelMask A reference to return the channel mask.
*
* @retval kErrorNone Found the TLV, successfully parsed its value, @p aChannelMask is updated.
* @retval kErrorNotFound No Channel Mask TLV found in the @p aMessage.
* @retval kErrorParse Found the TLV, but failed to parse it.
*
*/
ChannelMaskEntryBase *GetFirstEntry(void);
} OT_TOOL_PACKED_END;
/**
* Implements Channel Mask TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ChannelMaskTlv : public ChannelMaskBaseTlv
{
public:
/**
* Initializes the TLV.
*
*/
void Init(void)
{
SetType(kChannelMask);
SetLength(sizeof(*this) - sizeof(Tlv));
memset(mEntries, 0, sizeof(mEntries));
}
static Error FindIn(const Message &aMessage, uint32_t &aChannelMask);
/**
* Sets the Channel Mask Entries.
* Prepares Channel Mask TLV value for appending/writing.
*
* @param[in] aChannelMask The Channel Mask value.
* @param[out] aValue A reference to `Value` structure to populate.
* @param[in] aChannelMask The combined channel mask for all supported channel pages.
*
*/
void SetChannelMask(uint32_t aChannelMask);
static void PrepareValue(Value &aValue, uint32_t aChannelMask);
/**
* Returns the Channel Mask value as a `uint32_t` bit mask.
* Prepares a Channel Mask TLV value and appends the TLV to a given message.
*
* @returns The Channel Mask or 0 if not found.
* @param[in] aMessage The message to append to.
* @param[in] aChannelMask The combined channel mask for all supported channel pages.
*
* @retval kErrorNone Successfully prepared the Channel Mask TLV and appended it to @p aMessage.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*
*/
uint32_t GetChannelMask(void) const;
/**
* Reads message and returns the Channel Mask value as a `uint32_t` bit mask.
*
* @param[in] aMessage A reference to the message.
*
* @returns The Channel Mask or 0 if not found.
*
*/
static uint32_t GetChannelMask(const Message &aMessage);
static Error AppendTo(Message &aMessage, uint32_t aChannelMask);
private:
static constexpr uint8_t kNumMaskEntries = Radio::kNumChannelPages;
static constexpr uint8_t kMaskLength = sizeof(uint32_t);
ChannelMaskEntry mEntries[kNumMaskEntries];
} OT_TOOL_PACKED_END;
OT_TOOL_PACKED_BEGIN
class Entry
{
public:
uint8_t GetChannelPage(void) const { return mChannelPage; }
void SetChannelPage(uint8_t aChannelPage) { mChannelPage = aChannelPage; }
uint8_t GetMaskLength(void) const { return mMaskLength; }
void SetMaskLength(uint8_t aMaskLength) { mMaskLength = aMaskLength; }
uint32_t GetMask(void) const { return Reverse32(BigEndian::HostSwap32(mMask)); }
void SetMask(uint32_t aMask) { mMask = BigEndian::HostSwap32(Reverse32(aMask)); }
private:
uint8_t mChannelPage;
uint8_t mMaskLength;
uint32_t mMask;
} OT_TOOL_PACKED_END;
struct EntriesData : public Clearable<EntriesData>
{
// Represents received Channel Mask TLV Entries data which
// is either contained in `mData` buffer, or in `mMessage`
// at `mOffset`.
Error Parse(uint32_t &aChannelMask);
const uint8_t *mData;
const Message *mMessage;
uint16_t mOffset;
uint16_t mLength;
};
uint8_t mEntriesStart;
} OT_TOOL_PACKED_BEGIN;
/**
* Implements Energy List TLV generation and parsing.
+5 -8
View File
@@ -62,10 +62,9 @@ Error PanIdQueryClient::SendQuery(uint16_t aPanId,
otCommissionerPanIdConflictCallback aCallback,
void *aContext)
{
Error error = kErrorNone;
MeshCoP::ChannelMaskTlv channelMask;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message = nullptr;
Error error = kErrorNone;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message = nullptr;
VerifyOrExit(Get<MeshCoP::Commissioner>().IsActive(), error = kErrorInvalidState);
VerifyOrExit((message = Get<Tmf::Agent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
@@ -76,9 +75,7 @@ Error PanIdQueryClient::SendQuery(uint16_t aPanId,
SuccessOrExit(
error = Tlv::Append<MeshCoP::CommissionerSessionIdTlv>(*message, Get<MeshCoP::Commissioner>().GetSessionId()));
channelMask.Init();
channelMask.SetChannelMask(aChannelMask);
SuccessOrExit(error = channelMask.AppendTo(*message));
SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, aChannelMask));
SuccessOrExit(error = Tlv::Append<MeshCoP::PanIdTlv>(*message, aPanId));
@@ -106,7 +103,7 @@ void PanIdQueryClient::HandleTmf<kUriPanIdConflict>(Coap::Message &aMessage, con
SuccessOrExit(Tlv::Find<MeshCoP::PanIdTlv>(aMessage, panId));
VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0);
SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask));
mCallback.InvokeIfSet(panId, mask);
+12
View File
@@ -36,6 +36,18 @@
namespace ot {
const uint8_t Radio::kSupportedChannelPages[kNumChannelPages] = {
#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
kChannelPage0,
#endif
#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
kChannelPage2,
#endif
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE,
#endif
};
#if OPENTHREAD_RADIO
void Radio::Init(void)
{
+75 -18
View File
@@ -136,33 +136,33 @@ public:
static constexpr uint32_t kSymbolTime = OT_RADIO_SYMBOL_TIME;
static constexpr uint8_t kSymbolsPerOctet = OT_RADIO_SYMBOLS_PER_OCTET;
static constexpr uint32_t kPhyUsPerByte = kSymbolsPerOctet * kSymbolTime;
static constexpr uint8_t kChannelPage0 = OT_RADIO_CHANNEL_PAGE_0;
static constexpr uint8_t kChannelPage2 = OT_RADIO_CHANNEL_PAGE_2;
#if (OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT && OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT)
static constexpr uint16_t kNumChannelPages = 2;
static constexpr uint32_t kSupportedChannels =
OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK | OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX;
static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_0_MASK | OT_RADIO_CHANNEL_PAGE_2_MASK;
static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX;
#elif OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
static constexpr uint16_t kNumChannelPages = 1;
static constexpr uint32_t kSupportedChannels = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX;
static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_2_MASK;
static constexpr uint16_t kNumChannelPages = 1;
static constexpr uint32_t kSupportedChannels = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX;
#elif OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
static constexpr uint16_t kNumChannelPages = 1;
static constexpr uint32_t kSupportedChannels = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
static constexpr uint8_t kChannelMin = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX;
static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_0_MASK;
static constexpr uint16_t kNumChannelPages = 1;
static constexpr uint32_t kSupportedChannels = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
static constexpr uint8_t kChannelMin = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX;
#elif OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
static constexpr uint16_t kNumChannelPages = 1;
static constexpr uint32_t kSupportedChannels = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
static constexpr uint8_t kChannelMin = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX;
static constexpr uint32_t kSupportedChannelPages = (1 << OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE);
static constexpr uint16_t kNumChannelPages = 1;
static constexpr uint32_t kSupportedChannels = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
static constexpr uint8_t kChannelMin = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN;
static constexpr uint8_t kChannelMax = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX;
#endif
static const uint8_t kSupportedChannelPages[kNumChannelPages];
static constexpr int8_t kInvalidRssi = OT_RADIO_RSSI_INVALID; ///< Invalid RSSI value.
static constexpr int8_t kDefaultReceiveSensitivity = -110; ///< Default receive sensitivity (in dBm).
@@ -771,6 +771,63 @@ public:
*/
Error GetRegion(uint16_t &aRegionCode) const { return otPlatRadioGetRegion(GetInstancePtr(), &aRegionCode); }
/**
* Indicates whether a given channel page is supported based on the current configurations.
*
* @param[in] aChannelPage The channel page to check.
*
* @retval TRUE The @p aChannelPage is supported by radio.
* @retval FALASE The @p aChannelPage is not supported by radio.
*
*/
static constexpr bool SupportsChannelPage(uint8_t aChannelPage)
{
#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT && OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
return (aChannelPage == kChannelPage0) || (aChannelPage == kChannelPage2);
#elif OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
return (aChannelPage == kChannelPage0);
#elif OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
return (aChannelPage == kChannelPage2);
#elif OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
return (aChannelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE);
#endif
}
/**
* Returns the channel mask for a given channel page if supported by the radio.
*
* @param[in] aChannelPage The channel page.
*
* @returns The channel mask for @p aChannelPage if page is supported by the radio, otherwise zero.
*
*/
static uint32_t ChannelMaskForPage(uint8_t aChannelPage)
{
uint32_t mask = 0;
#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
if (aChannelPage == kChannelPage0)
{
mask = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
}
#endif
#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
if (aChannelPage == kChannelPage1)
{
mask = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
if (aChannelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE)
{
mask = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
}
#endif
return mask;
}
private:
otInstance *GetInstancePtr(void) const { return reinterpret_cast<otInstance *>(&InstanceLocator::GetInstance()); }
+1 -1
View File
@@ -71,7 +71,7 @@ void AnnounceBeginServer::HandleTmf<kUriAnnounceBegin>(Coap::Message &aMessage,
uint16_t period;
VerifyOrExit(aMessage.IsPostRequest());
VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0);
SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask));
SuccessOrExit(Tlv::Find<MeshCoP::CountTlv>(aMessage, count));
SuccessOrExit(Tlv::Find<MeshCoP::PeriodTlv>(aMessage, period));
+7 -10
View File
@@ -63,12 +63,11 @@ EnergyScanServer::EnergyScanServer(Instance &aInstance)
template <>
void EnergyScanServer::HandleTmf<kUriEnergyScan>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
uint8_t count;
uint16_t period;
uint16_t scanDuration;
uint32_t mask;
MeshCoP::Tlv tlv;
MeshCoP::ChannelMaskTlv channelMaskTlv;
uint8_t count;
uint16_t period;
uint16_t scanDuration;
uint32_t mask;
MeshCoP::Tlv tlv;
VerifyOrExit(aMessage.IsPostRequest());
@@ -76,15 +75,13 @@ void EnergyScanServer::HandleTmf<kUriEnergyScan>(Coap::Message &aMessage, const
SuccessOrExit(Tlv::Find<MeshCoP::PeriodTlv>(aMessage, period));
SuccessOrExit(Tlv::Find<MeshCoP::ScanDurationTlv>(aMessage, scanDuration));
VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0);
SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask));
FreeMessage(mReportMessage);
mReportMessage = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriEnergyReport);
VerifyOrExit(mReportMessage != nullptr);
channelMaskTlv.Init();
channelMaskTlv.SetChannelMask(mask);
SuccessOrExit(channelMaskTlv.AppendTo(*mReportMessage));
SuccessOrExit(MeshCoP::ChannelMaskTlv::AppendTo(*mReportMessage, mask));
tlv.SetType(MeshCoP::Tlv::kEnergyList);
SuccessOrExit(mReportMessage->Append(tlv));
+1 -2
View File
@@ -125,8 +125,7 @@ bool ChannelTlvValue::IsValid(void) const
bool isValid = false;
uint16_t channel;
VerifyOrExit(mChannelPage < BitSizeOf(uint32_t));
VerifyOrExit((1U << mChannelPage) & Radio::kSupportedChannelPages);
VerifyOrExit(Radio::SupportsChannelPage(mChannelPage));
channel = GetChannel();
VerifyOrExit((Radio::kChannelMin <= channel) && (channel <= Radio::kChannelMax));
+2 -5
View File
@@ -322,12 +322,9 @@ Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage)
tlv.Init();
for (uint8_t page = 0; page < static_cast<uint8_t>(BitSizeOf(Radio::kSupportedChannelPages)); page++)
for (uint8_t page : Radio::kSupportedChannelPages)
{
if (Radio::kSupportedChannelPages & (1 << page))
{
tlv.GetChannelPages()[length++] = page;
}
tlv.GetChannelPages()[length++] = page;
}
tlv.SetLength(length);
+5 -8
View File
@@ -64,7 +64,7 @@ void PanIdQueryServer::HandleTmf<kUriPanIdQuery>(Coap::Message &aMessage, const
uint32_t mask;
VerifyOrExit(aMessage.IsPostRequest());
VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0);
SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask));
SuccessOrExit(Tlv::Find<MeshCoP::PanIdTlv>(aMessage, panId));
@@ -105,17 +105,14 @@ void PanIdQueryServer::HandleScanResult(Mac::ActiveScanResult *aScanResult)
void PanIdQueryServer::SendConflict(void)
{
Error error = kErrorNone;
MeshCoP::ChannelMaskTlv channelMask;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message;
Error error = kErrorNone;
Tmf::MessageInfo messageInfo(GetInstance());
Coap::Message *message;
message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriPanIdConflict);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
channelMask.Init();
channelMask.SetChannelMask(mChannelMask);
SuccessOrExit(error = channelMask.AppendTo(*message));
SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, mChannelMask));
SuccessOrExit(error = Tlv::Append<MeshCoP::PanIdTlv>(*message, mPanId));