[mac] redesign Information Element (IE) processing and generation (#13263)

This commit redesigns IEEE 802.15.4 Information Element (IE) handling by
introducing dedicated subclass definitions (`CslIe`, `TimeIe`,
`ConnectionIe`, `RendezvousTimeIe`, `LinkMetricsProbingIe`, etc.) inheriting
from `HeaderIe` or `VendorIe`.

In addition, `Mac::Frame` is updated with generic template methods:
- `Has<IeType>()`: Checks if the frame contains a well-formed instance of
  the specified IE subclass.
- `Find<IeType>()`: Finds, validates and returns a type-safe pointer to the
  IE.

Key benefits of this redesign:

- Streamlined IE Generation: Constructing and populating IEs is significantly
  simplified. Each subclass exposes a unified `Init()` method that cleanly
  computes the exact IE content length, sets the Element ID and known content
  (e.g. vendor OUI) in a single step.

- True Encapsulation: Each IE subclass serves as the single source of truth
  for its Element ID (`kId`), content layout, and structural validation logic
  (`IsValid()`). Callers no longer pass magic ID constants or perform
  error-prone pointer arithmetic.

- By implementing `HeaderIe::ValidateAs<IeType>()` as a static polymorphic
  matcher passed to `FindHeaderIe()`, the compiler devirtualizes
  and inlines ID match and content verifications directly into MAC frame
  parsing loops.

- Scalable Integration: Adding new Information Elements is trivial. Defining
  a new subclass automatically equips MAC frame handling with type-safe
  search without bloating `Mac::Frame` with ad-hoc getter methods.
This commit is contained in:
Abtin Keshavarzian
2026-06-23 11:05:15 -07:00
committed by GitHub
parent 9b8d5b7471
commit ac689dd9a4
14 changed files with 332 additions and 430 deletions
+10 -15
View File
@@ -205,7 +205,7 @@ otError otMacFrameGenerateEnhAck(const otRadioFrame *aFrame,
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
void otMacFrameSetCslIe(otRadioFrame *aFrame, uint16_t aCslPeriod, uint16_t aCslPhase)
{
static_cast<Mac::Frame *>(aFrame)->SetCslIe(aCslPeriod, aCslPhase);
static_cast<Mac::Frame *>(aFrame)->UpdateCslIe(aCslPeriod, aCslPhase);
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -264,42 +264,37 @@ uint8_t otMacFrameGenerateCslIeTemplate(uint8_t *aDest)
{
assert(aDest != nullptr);
reinterpret_cast<Mac::HeaderIe *>(aDest)->Init(Mac::CslIe::kHeaderIeId, sizeof(Mac::CslIe));
reinterpret_cast<Mac::CslIe *>(aDest)->Init();
return sizeof(Mac::HeaderIe) + sizeof(Mac::CslIe);
return sizeof(Mac::CslIe);
}
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
uint8_t otMacFrameGenerateEnhAckProbingIe(uint8_t *aDest, const uint8_t *aIeData, uint8_t aIeDataLength)
{
uint8_t len = sizeof(Mac::VendorIeHeader) + aIeDataLength;
Mac::LinkMetricsProbingIe *probingIe = reinterpret_cast<Mac::LinkMetricsProbingIe *>(aDest);
assert(aDest != nullptr);
reinterpret_cast<Mac::HeaderIe *>(aDest)->Init(Mac::ThreadIe::kHeaderIeId, len);
aDest += sizeof(Mac::HeaderIe);
reinterpret_cast<Mac::VendorIeHeader *>(aDest)->SetVendorOui(Mac::ThreadIe::kVendorOuiThreadCompanyId);
reinterpret_cast<Mac::VendorIeHeader *>(aDest)->SetSubType(Mac::ThreadIe::kEnhAckProbingIe);
probingIe->Init(aIeDataLength);
if (aIeData != nullptr)
{
aDest += sizeof(Mac::VendorIeHeader);
memcpy(aDest, aIeData, aIeDataLength);
probingIe->WriteMetricsDataFrom(aIeData);
}
return sizeof(Mac::HeaderIe) + len;
return probingIe->GetSize();
}
void otMacFrameSetEnhAckProbingIe(otRadioFrame *aFrame, const uint8_t *aData, uint8_t aDataLen)
{
assert(aFrame != nullptr && aData != nullptr);
reinterpret_cast<Mac::Frame *>(aFrame)->SetEnhAckProbingIe(aData, aDataLen);
reinterpret_cast<Mac::Frame *>(aFrame)->UpdateEnhAckProbingIe(aData, aDataLen);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
static uint16_t ComputeCslPhase(uint32_t aRadioTime, otRadioContext *aRadioContext)
{
@@ -409,7 +404,7 @@ otError otMacFrameProcessTxSfd(otRadioFrame *aFrame, uint64_t aRadioTime, otRadi
VerifyOrExit(!otMacFrameIsSecurityEnabled(aFrame) || !aFrame->mInfo.mTxInfo.mIsSecurityProcessed);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (static_cast<Mac::Frame *>(aFrame)->HasCslIe()) // CSL IE should be filled for every transmit attempt
if (static_cast<Mac::Frame *>(aFrame)->Has<Mac::CslIe>()) // CSL IE should be filled for every transmit attempt
{
otMacFrameSetCslIe(aFrame, aRadioContext->mCslPeriod, ComputeCslPhase(aRadioTime, aRadioContext));
}