[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));
}
+3 -3
View File
@@ -245,7 +245,7 @@ void DataPollSender::HandlePollSent(Mac::TxFrame &aFrame, Error aError)
mPollTxFailureCounter++;
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
maxRetxAttempts = aFrame.HasCslIe() ? kMaxCslPollRetxAttempts : kMaxPollRetxAttempts;
maxRetxAttempts = aFrame.Has<Mac::CslIe>() ? kMaxCslPollRetxAttempts : kMaxPollRetxAttempts;
#else
maxRetxAttempts = kMaxPollRetxAttempts;
#endif
@@ -329,7 +329,7 @@ void DataPollSender::ProcessTxDone(const Mac::TxFrame &aFrame, const Mac::RxFram
VerifyOrExit(aFrame.GetSecurityEnabled());
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (aFrame.mInfo.mTxInfo.mIsARetx && aFrame.HasCslIe())
if (aFrame.mInfo.mTxInfo.mIsARetx && aFrame.Has<Mac::CslIe>())
{
// For retransmission frame, use a data poll to resync its parent with correct CSL phase
sendDataPoll = true;
@@ -571,7 +571,7 @@ Mac::TxFrame *DataPollSender::PrepareDataRequest(Mac::TxFrames &aTxFrames)
Get<MessageFramer>().PrepareMacHeaders(*frame, frameInfo, nullptr);
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (frame->HasCslIe())
if (frame->Has<Mac::CslIe>())
{
// Disable frame retransmission when the data poll has CSL IE included
aTxFrames.SetMaxFrameRetries(0);
+21 -38
View File
@@ -900,7 +900,7 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame)
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
// Transmit security will be processed after time IE content is updated.
VerifyOrExit(aFrame.GetTimeIeOffset() == 0);
VerifyOrExit(!aFrame.Has<TimeIe>());
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -1017,12 +1017,17 @@ void Mac::BeginTransmit(void)
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
{
uint8_t timeIeOffset = GetTimeIeOffset(*frame);
TimeIe *timeIe = frame->Find<TimeIe>();
frame->SetTimeIeOffset(timeIeOffset);
if (timeIeOffset != 0)
if (timeIe == nullptr)
{
frame->SetTimeIeOffset(0);
}
else
{
uint8_t offset = static_cast<uint8_t>(timeIe->GetData() - frame->GetPsdu());
frame->SetTimeIeOffset(offset);
frame->SetTimeSyncSeq(Get<TimeSync>().GetTimeSyncSeq());
frame->SetNetworkTimeOffset(Get<TimeSync>().GetNetworkTimeOffset());
}
@@ -1303,7 +1308,7 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
ProcessCsl(*aAckFrame, dstAddr);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (!mRxOnWhenIdle && aFrame.HasCslIe())
if (!mRxOnWhenIdle && aFrame.Has<CslIe>())
{
Get<DataPollSender>().ResetKeepAliveTimer();
}
@@ -2352,24 +2357,6 @@ void Mac::LogFrameTxFailure(const TxFrame &, Error, uint8_t, bool) const {}
// LCOV_EXCL_STOP
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
uint8_t Mac::GetTimeIeOffset(const Frame &aFrame)
{
uint8_t offset = 0;
const uint8_t *base = aFrame.GetPsdu();
const uint8_t *cur = nullptr;
cur = reinterpret_cast<const uint8_t *>(aFrame.GetTimeIe());
VerifyOrExit(cur != nullptr);
cur += sizeof(VendorIeHeader);
offset = static_cast<uint8_t>(cur - base);
exit:
return offset;
}
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
void Mac::SetCslCapable(bool aIsCslCapable)
{
@@ -2492,7 +2479,7 @@ void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr)
VerifyOrExit(aFrame.IsVersion2015());
VerifyOrExit(aFrame.IsSecuredWith(RxFrame::kAllowKeyIdMode1));
csl = aFrame.GetCslIe();
csl = aFrame.Find<CslIe>();
VerifyOrExit(csl != nullptr);
#if OPENTHREAD_FTD
@@ -2526,24 +2513,20 @@ exit:
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
void Mac::ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor)
{
constexpr uint8_t kEnhAckProbingIeMaxLen = 2;
const LinkMetricsProbingIe *probingIe = aFrame.Find<LinkMetricsProbingIe>();
uint8_t dataLen;
const HeaderIe *enhAckProbingIe =
reinterpret_cast<const HeaderIe *>(aFrame.GetThreadIe(ThreadIe::kEnhAckProbingIe));
uint8_t dataLen;
VerifyOrExit(probingIe != nullptr);
VerifyOrExit(enhAckProbingIe != nullptr);
dataLen = probingIe->GetMetricsDataLen();
VerifyOrExit(dataLen <= LinkMetricsProbingIe::kMaxMetricsDataLen);
dataLen = enhAckProbingIe->GetLength() - sizeof(VendorIeHeader);
VerifyOrExit(dataLen <= kEnhAckProbingIeMaxLen);
Get<LinkMetrics::Initiator>().ProcessEnhAckIeData(probingIe->GetMetricsData(), dataLen, aNeighbor);
Get<LinkMetrics::Initiator>().ProcessEnhAckIeData(reinterpret_cast<const uint8_t *>(enhAckProbingIe) +
sizeof(HeaderIe) + sizeof(VendorIeHeader),
dataLen, aNeighbor);
exit:
return;
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
#endif
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
void Mac::SetRadioFilterEnabled(bool aFilterEnabled)
@@ -2649,13 +2632,13 @@ Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
VerifyOrExit(srcAddress.IsExtended(), error = kErrorDrop);
wakeupInfo.mExtAddress = srcAddress.GetExtended();
connectionIe = aFrame.GetConnectionIe();
connectionIe = aFrame.Find<ConnectionIe>();
wakeupInfo.mRetryInterval = connectionIe->GetRetryInterval();
wakeupInfo.mRetryCount = connectionIe->GetRetryCount();
VerifyOrExit(wakeupInfo.mRetryInterval > 0 && wakeupInfo.mRetryCount > 0, error = kErrorInvalidArgs);
radioNowUs = otPlatRadioGetNow(&GetInstance());
rvTimeUs = aFrame.GetRendezvousTimeIe()->GetRendezvousTime() * kUsPerTenSymbols;
rvTimeUs = aFrame.Find<RendezvousTimeIe>()->GetRendezvousTime() * kUsPerTenSymbols;
rvTimestampUs = aFrame.GetTimestamp() + kRadioHeaderPhrDuration + aFrame.GetLength() * kOctetDuration + rvTimeUs;
if (rvTimestampUs > radioNowUs + kCslRequestAhead)
-4
View File
@@ -853,10 +853,6 @@ private:
void LogFrameTxFailure(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx) const;
void LogBeacon(const char *aActionText) const;
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
uint8_t GetTimeIeOffset(const Frame &aFrame);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr);
#endif
+27 -115
View File
@@ -223,7 +223,6 @@ void TxFrame::Info::PrepareHeadersIn(TxFrame &aTxFrame) const
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
if (mAppendTimeIe)
{
builder.Append<HeaderIe>()->Init(TimeIe::kHeaderIeId, sizeof(TimeIe));
builder.Append<TimeIe>()->Init();
}
#endif
@@ -231,15 +230,14 @@ void TxFrame::Info::PrepareHeadersIn(TxFrame &aTxFrame) const
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (mAppendCslIe)
{
builder.Append<HeaderIe>()->Init(CslIe::kHeaderIeId, sizeof(CslIe));
builder.Append<CslIe>();
builder.Append<CslIe>()->Init();
aTxFrame.SetCslIePresent(true);
}
#endif
if ((fcf & kFcfIePresent) && ((mType == kTypeMacCmd) || !mEmptyPayload))
{
builder.Append<HeaderIe>()->Init(Termination2Ie::kHeaderIeId, Termination2Ie::kIeContentSize);
builder.Append<Termination2Ie>()->Init();
}
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
@@ -320,14 +318,12 @@ bool Frame::IsWakeupFrame(void) const
VerifyOrExit(keyIdMode == kKeyIdMode2);
// ... that has Rendezvous Time IE and Connection IE...
VerifyOrExit(GetRendezvousTimeIe() != nullptr);
VerifyOrExit((connectionIe = GetConnectionIe()) != nullptr);
VerifyOrExit(Has<RendezvousTimeIe>());
VerifyOrExit((connectionIe = Find<ConnectionIe>()) != nullptr);
// ... but no other IEs nor payload.
firstIeIndex = FindHeaderIeIndex();
VerifyOrExit(mPsdu + firstIeIndex + sizeof(HeaderIe) + RendezvousTimeIe::kIeContentSize + sizeof(HeaderIe) +
connectionIe->GetHeaderIe()->GetLength() ==
GetFooter());
VerifyOrExit(mPsdu + firstIeIndex + sizeof(RendezvousTimeIe) + connectionIe->GetSize() == GetFooter());
result = true;
@@ -1090,7 +1086,7 @@ uint8_t Frame::FindPayloadIndex(void) const
VerifyOrExit(index + footerLength <= mLength, index = kInvalidIndex);
if (ie->GetId() == Termination2Ie::kHeaderIeId)
if (ie->GetId() == Termination2Ie::kId)
{
break;
}
@@ -1141,6 +1137,7 @@ exit:
const uint8_t *Frame::GetFooter(void) const { return mPsdu + mLength - GetFooterLength(); }
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
uint8_t Frame::FindHeaderIeIndex(void) const
{
uint8_t index;
@@ -1153,11 +1150,11 @@ exit:
return index;
}
const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
const HeaderIe *Frame::FindHeaderIe(HeaderIeMatcher aMatcher) const
{
uint16_t index = FindHeaderIeIndex();
uint16_t payloadIndex = FindPayloadIndex();
const uint8_t *header = nullptr;
uint16_t index = FindHeaderIeIndex();
uint16_t payloadIndex = FindPayloadIndex();
const HeaderIe *matchedIe = nullptr;
// `FindPayloadIndex()` verifies that Header IE(s) in frame (if present)
// are well-formed.
@@ -1168,9 +1165,9 @@ const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
{
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
if (ie->GetId() == aIeId)
if (aMatcher(*ie))
{
header = &mPsdu[index];
matchedIe = ie;
ExitNow();
}
@@ -1178,123 +1175,40 @@ const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
}
exit:
return header;
return matchedIe;
}
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE || \
OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
const uint8_t *Frame::GetThreadIe(uint8_t aSubType) const
{
uint16_t index = FindHeaderIeIndex();
uint16_t payloadIndex = FindPayloadIndex();
const uint8_t *header = nullptr;
// `FindPayloadIndex()` verifies that Header IE(s) in frame (if present)
// are well-formed.
VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
while (index < payloadIndex)
{
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
if ((ie->GetId() == VendorIeHeader::kHeaderIeId) && (ie->GetLength() >= VendorIeHeader::kIeContentSize))
{
const VendorIeHeader *vendorIe = reinterpret_cast<const VendorIeHeader *>(ie->GetContent());
if (vendorIe->GetVendorOui() == ThreadIe::kVendorOuiThreadCompanyId && vendorIe->GetSubType() == aSubType)
{
header = &mPsdu[index];
ExitNow();
}
}
index += ie->GetSize();
}
exit:
return header;
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE ||
// OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
void Frame::SetCslIe(uint16_t aCslPeriod, uint16_t aCslPhase)
void Frame::UpdateCslIe(uint16_t aCslPeriod, uint16_t aCslPhase)
{
CslIe *csl = GetCslIe();
CslIe *csl = Find<CslIe>();
VerifyOrExit(csl != nullptr);
csl->SetPeriod(aCslPeriod);
csl->SetPhase(aCslPhase);
exit:
return;
}
bool Frame::HasCslIe(void) const { return GetCslIe() != nullptr; }
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
const CslIe *Frame::GetCslIe(void) const
{
const uint8_t *cur;
const CslIe *csl = nullptr;
cur = GetHeaderIe(CslIe::kHeaderIeId);
VerifyOrExit(cur != nullptr);
VerifyOrExit(reinterpret_cast<const HeaderIe *>(cur)->GetLength() >= CslIe::kIeContentSize);
csl = reinterpret_cast<const CslIe *>(cur + sizeof(HeaderIe));
exit:
return csl;
}
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
void Frame::SetEnhAckProbingIe(const uint8_t *aValue, uint8_t aLen)
void Frame::UpdateEnhAckProbingIe(const uint8_t *aData, uint8_t aLen)
{
uint8_t *cur = GetThreadIe(ThreadIe::kEnhAckProbingIe);
LinkMetricsProbingIe *probingIe = Find<LinkMetricsProbingIe>();
VerifyOrExit(cur != nullptr);
memcpy(cur + sizeof(HeaderIe) + sizeof(VendorIeHeader), aValue, aLen);
VerifyOrExit(probingIe != nullptr);
VerifyOrExit(aLen >= probingIe->GetMetricsDataLen());
probingIe->WriteMetricsDataFrom(aData);
exit:
return;
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
#endif
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
const TimeIe *Frame::GetTimeIe(void) const
{
uint16_t index = FindHeaderIeIndex();
uint16_t payloadIndex = FindPayloadIndex();
const TimeIe *timeIe = nullptr;
VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
while (index < payloadIndex)
{
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
if ((ie->GetId() == VendorIeHeader::kHeaderIeId) && (ie->GetLength() >= TimeIe::kIeContentSize))
{
const TimeIe *vendorIe = reinterpret_cast<const TimeIe *>(ie->GetContent());
if (vendorIe->GetVendorOui() == TimeIe::kVendorOuiNest && vendorIe->GetSubType() == TimeIe::kVendorIeTime)
{
timeIe = vendorIe;
ExitNow();
}
}
index += ie->GetSize();
}
exit:
return timeIe;
}
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
#if OPENTHREAD_CONFIG_MULTI_RADIO
uint16_t Frame::GetMtu(void) const
@@ -1590,11 +1504,9 @@ Error TxFrame::GenerateWakeupFrame(PanId aPanId, const WakeupRequest &aWakeupReq
IgnoreError(builder.AppendUint8(secCtl));
builder.AppendLength(CalculateSecurityHeaderSize(secCtl) - sizeof(secCtl));
builder.Append<HeaderIe>()->Init(RendezvousTimeIe::kHeaderIeId, sizeof(RendezvousTimeIe));
builder.Append<RendezvousTimeIe>();
builder.Append<RendezvousTimeIe>()->Init();
builder.Append<HeaderIe>()->Init(ConnectionIe::kHeaderIeId, sizeof(ConnectionIe) + wakeupIdLength);
builder.Append<ConnectionIe>()->Init();
builder.Append<ConnectionIe>()->Init(wakeupIdLength);
builder.AppendLength(wakeupIdLength);
builder.AppendLength(CalculateMicSize(secCtl) + GetFcsSize());
+42 -137
View File
@@ -194,50 +194,7 @@ public:
* @retval FALSE If this is not a Wake-up frame.
*/
bool IsWakeupFrame(void) const;
/**
* This method returns the Rendezvous Time IE of a wake-up frame.
*
* @returns Pointer to the Rendezvous Time IE.
*/
RendezvousTimeIe *GetRendezvousTimeIe(void) { return AsNonConst(AsConst(this)->GetRendezvousTimeIe()); }
/**
* This method returns the Rendezvous Time IE of a wake-up frame.
*
* @returns Const pointer to the Rendezvous Time IE.
*/
const RendezvousTimeIe *GetRendezvousTimeIe(void) const
{
const uint8_t *ie = GetHeaderIe(RendezvousTimeIe::kHeaderIeId);
return (ie != nullptr &&
reinterpret_cast<const HeaderIe *>(ie)->GetLength() >= RendezvousTimeIe::kIeContentSize)
? reinterpret_cast<const RendezvousTimeIe *>(ie + sizeof(HeaderIe))
: nullptr;
}
/**
* This method returns the Connection IE of a wake-up frame.
*
* @returns Pointer to the Connection IE.
*/
ConnectionIe *GetConnectionIe(void) { return AsNonConst(AsConst(this)->GetConnectionIe()); }
/**
* This method returns the Connection IE of a wake-up frame.
*
* @returns Const pointer to the Connection IE.
*/
const ConnectionIe *GetConnectionIe(void) const
{
const uint8_t *ie = GetThreadIe(ConnectionIe::kThreadIeSubtype);
return (ie != nullptr && reinterpret_cast<const HeaderIe *>(ie)->GetLength() >= ConnectionIe::kIeContentSize)
? reinterpret_cast<const ConnectionIe *>(ie + sizeof(HeaderIe))
: nullptr;
}
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
#endif
/**
* Returns the IEEE 802.15.4 Frame Version.
@@ -613,23 +570,6 @@ public:
*/
const uint8_t *GetFooter(void) const;
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
/**
* Returns a pointer to the vendor specific Time IE.
*
* @returns A pointer to the Time IE, `nullptr` if not found.
*/
TimeIe *GetTimeIe(void) { return AsNonConst(AsConst(this)->GetTimeIe()); }
/**
* Returns a pointer to the vendor specific Time IE.
*
* @returns A pointer to the Time IE, `nullptr` if not found.
*/
const TimeIe *GetTimeIe(void) const;
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
/**
* Indicates whether the frame contains header IEs.
@@ -637,91 +577,67 @@ public:
* @retval TRUE The frame contains header IEs.
* @retval FALSE The frame contains no header IEs.
*/
bool HasHeaderIe(void) const { return FindHeaderIeIndex() != kInvalidIndex; }
bool HasAnyHeaderIe(void) const { return FindHeaderIeIndex() != kInvalidIndex; }
/**
* Returns a pointer to the Header IE.
* Finds a specific Information Element (IE) in the frame.
*
* @param[in] aIeId The Element Id of the Header IE.
* This method searches the frame for a Header IE matching the Element ID of @p IeType and also validates that
* the content of the IE is well-formed according to @p IeType.
*
* @returns A pointer to the Header IE, `nullptr` if not found.
* @tparam IeType The IE subclass type to find.
*
* @returns A pointer to the IE, or `nullptr` if not found or if the IE content is malformed.
*/
uint8_t *GetHeaderIe(uint8_t aIeId) { return AsNonConst(AsConst(this)->GetHeaderIe(aIeId)); }
template <typename IeType> const IeType *Find(void) const
{
return static_cast<const IeType *>(FindHeaderIe(HeaderIe::ValidateAs<IeType>));
}
/**
* Returns a pointer to the Header IE.
* Finds a specific Information Element (IE) in the frame.
*
* @param[in] aIeId The Element Id of the Header IE.
* This method searches the frame for a Header IE matching the Element ID of @p IeType and also validates that
* the content of the IE is well-formed according to @p IeType.
*
* @returns A pointer to the Header IE, `nullptr` if not found.
* @tparam IeType The IE subclass type to find.
*
* @returns A pointer to the IE, or `nullptr` if not found or if the IE content is malformed.
*/
const uint8_t *GetHeaderIe(uint8_t aIeId) const;
template <typename IeType> IeType *Find(void) { return AsNonConst(AsConst(this)->Find<IeType>()); }
/**
* Returns a pointer to a specific Thread IE.
* Indicates whether or not the frame contains a specific Information Element (IE).
*
* A Thread IE is a vendor specific IE with Vendor OUI as `kVendorOuiThreadCompanyId`.
* This method checks whether the frame contains a Header IE matching the Element ID of @p IeType with valid
* content according to @p IeType.
*
* @param[in] aSubType The sub type of the Thread IE.
* @tparam IeType The IE subclass type to check.
*
* @returns A pointer to the Thread IE, `nullptr` if not found.
* @retval TRUE The frame contains a valid instance of the IE.
* @retval FALSE The frame does not contain the IE or its content is malformed.
*/
uint8_t *GetThreadIe(uint8_t aSubType) { return AsNonConst(AsConst(this)->GetThreadIe(aSubType)); }
/**
* Returns a pointer to a specific Thread IE.
*
* A Thread IE is a vendor specific IE with Vendor OUI as `kVendorOuiThreadCompanyId`.
*
* @param[in] aSubType The sub type of the Thread IE.
*
* @returns A pointer to the Thread IE, `nullptr` if not found.
*/
const uint8_t *GetThreadIe(uint8_t aSubType) const;
template <typename IeType> bool Has(void) const { return Find<IeType>() != nullptr; }
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
/**
* Finds CSL IE in the frame and modify its content.
* Updates CSL IE content in the frame.
*
* @param[in] aCslPeriod CSL Period in CSL IE.
* @param[in] aCslPhase CSL Phase in CSL IE.
*/
void SetCslIe(uint16_t aCslPeriod, uint16_t aCslPhase);
/**
* Indicates whether or not the frame contains CSL IE.
*
* @retval TRUE If the frame contains CSL IE.
* @retval FALSE If the frame doesn't contain CSL IE.
*/
bool HasCslIe(void) const;
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
/**
* Returns a pointer to a CSL IE.
*
* @returns A pointer to the CSL IE, `nullptr` if not found.
*/
const CslIe *GetCslIe(void) const;
/**
* Returns a pointer to a CSL IE.
*
* @returns A pointer to the CSL IE, `nullptr` if not found.
*/
CslIe *GetCslIe(void) { return AsNonConst(AsConst(this)->GetCslIe()); }
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void UpdateCslIe(uint16_t aCslPeriod, uint16_t aCslPhase);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
/**
* Finds Enhanced ACK Probing (Vendor Specific) IE and set its value.
* Finds Enhanced ACK Probing (Vendor Specific) IE and updates its Link Metrics Data content.
*
* @param[in] aValue A pointer to the value to set.
* @param[in] aLen The length of @p aValue.
* @param[in] aData A pointer to the data to write.
* @param[in] aLen The length of @p aData.
*/
void SetEnhAckProbingIe(const uint8_t *aValue, uint8_t aLen);
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
void UpdateEnhAckProbingIe(const uint8_t *aData, uint8_t aLen);
#endif
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
@@ -936,6 +852,14 @@ protected:
static uint8_t CalculateSecurityHeaderSize(uint8_t aSecurityControl);
static uint8_t CalculateKeySourceSize(uint8_t aSecurityControl);
static uint8_t CalculateMicSize(uint8_t aSecurityControl);
private:
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
typedef bool (&HeaderIeMatcher)(const HeaderIe &aHeaderIe);
const HeaderIe *FindHeaderIe(HeaderIeMatcher aMatcher) const;
HeaderIe *FindHeaderIe(HeaderIeMatcher aMatcher) { return AsNonConst(AsConst(this)->FindHeaderIe(aMatcher)); }
#endif
};
/**
@@ -1034,25 +958,6 @@ public:
* @retval kErrorSecurity Received frame MIC check failed.
*/
Error ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey);
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
/**
* Gets the offset to network time.
*
* @returns The offset to network time.
*/
int64_t ComputeNetworkTimeOffset(void) const
{
return static_cast<int64_t>(GetTimeIe()->GetTime() - GetTimestamp());
}
/**
* Gets the time sync sequence.
*
* @returns The time sync sequence.
*/
uint8_t ReadTimeSyncSeq(void) const { return GetTimeIe()->GetSequence(); }
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
};
/**
+13 -12
View File
@@ -44,16 +44,17 @@ void HeaderIe::Init(uint8_t aId, uint8_t aLen)
}
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
Error ConnectionIe::SetWakeupId(WakeupId aWakeupId)
{
Error error = kErrorNone;
const HeaderIe *headerIe = GetHeaderIe();
uint8_t wakeupIdLength = GetWakeupIdLength(aWakeupId);
Error error = kErrorNone;
uint8_t wakeupIdLength = GetWakeupIdLength(aWakeupId);
VerifyOrExit(GetSize() >= sizeof(ConnectionIe), error = kErrorParse);
VerifyOrExit(GetSize() - sizeof(ConnectionIe) == wakeupIdLength, error = kErrorParse);
VerifyOrExit(headerIe->GetLength() > sizeof(ConnectionIe), error = kErrorParse);
VerifyOrExit(headerIe->GetLength() - sizeof(ConnectionIe) == wakeupIdLength, error = kErrorParse);
aWakeupId = LittleEndian::HostSwap64(aWakeupId);
memcpy(GetWakeupIdData(), reinterpret_cast<uint8_t *>(&aWakeupId), wakeupIdLength);
memcpy(GetBytes() + sizeof(ConnectionIe), reinterpret_cast<uint8_t *>(&aWakeupId), wakeupIdLength);
exit:
return error;
@@ -61,22 +62,22 @@ exit:
Error ConnectionIe::GetWakeupId(WakeupId &aWakeupId) const
{
Error error = kErrorNone;
const HeaderIe *headerIe = GetHeaderIe();
uint8_t wakeupIdLength;
Error error = kErrorNone;
uint8_t wakeupIdLength;
VerifyOrExit(headerIe->GetLength() > sizeof(ConnectionIe), error = kErrorParse);
VerifyOrExit(GetSize() > sizeof(ConnectionIe), error = kErrorParse);
wakeupIdLength = headerIe->GetLength() - sizeof(ConnectionIe);
wakeupIdLength = GetSize() - sizeof(ConnectionIe);
VerifyOrExit(wakeupIdLength <= sizeof(WakeupId), error = kErrorParse);
aWakeupId = 0;
memcpy(reinterpret_cast<uint8_t *>(&aWakeupId), GetWakeupIdData(), wakeupIdLength);
memcpy(reinterpret_cast<uint8_t *>(&aWakeupId), GetBytes() + sizeof(ConnectionIe), wakeupIdLength);
aWakeupId = LittleEndian::HostSwap64(aWakeupId);
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
} // namespace Mac
+188 -84
View File
@@ -40,6 +40,7 @@
#include "common/bit_utils.hpp"
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/num_utils.hpp"
#include "common/numeric_limits.hpp"
#include "mac/mac_types.hpp"
@@ -59,14 +60,6 @@ OT_TOOL_PACKED_BEGIN
class HeaderIe
{
public:
/**
* Initializes the Header IE with a given ID and Length.
*
* @param[in] aId The IE Element ID.
* @param[in] aLen The IE content length.
*/
void Init(uint8_t aId, uint8_t aLen);
/**
* Returns the IE Element ID.
*
@@ -104,6 +97,29 @@ public:
*/
uint8_t *GetContent(void) { return AsNonConst(AsConst(this)->GetContent()); }
/**
* Validates whether a given Header IE matches a specific IE subclass.
*
* This method checks whether @p aIe matches the Element ID of @p IeType (`IeType::kId`) and also casts @p aIe
* to @p IeType to validate its content structure via `IeType::IsValid()`.
*
* @tparam IeType The IE subclass type to validate against.
*
* @param[in] aIe The Header IE to validate.
*
* @retval TRUE @p aIe matches @p IeType and its content is well-formed.
* @retval FALSE @p aIe does not match @p IeType or its content is malformed.
*/
template <typename IeType> static bool ValidateAs(const HeaderIe &aIe)
{
return (aIe.GetId() == IeType::kId) && static_cast<const IeType *>(&aIe)->IsValid();
}
protected:
void Init(uint8_t aId, uint8_t aLen);
uint8_t *GetBytes(void) { return reinterpret_cast<uint8_t *>(this); }
const uint8_t *GetBytes(void) const { return reinterpret_cast<const uint8_t *>(this); }
private:
// IEEE 802.15.4 Header IE descriptor (2 bytes, little-endian):
//
@@ -117,20 +133,24 @@ private:
void SetId(uint8_t aId) { mLenIdType = UpdateBitsLittleEndian<uint16_t, kIdMask>(mLenIdType, aId); }
void SetLength(uint8_t aLength) { mLenIdType = UpdateBitsLittleEndian<uint16_t, kLenMask>(mLenIdType, aLength); }
const uint8_t *GetBytes(void) const { return reinterpret_cast<const uint8_t *>(this); }
uint16_t mLenIdType;
} OT_TOOL_PACKED_END;
/**
* Implements CSL IE data structure.
* Represents a CSL IE.
*/
OT_TOOL_PACKED_BEGIN
class CslIe
class CslIe : public HeaderIe
{
friend class HeaderIe;
public:
static constexpr uint8_t kHeaderIeId = 0x1a;
static constexpr uint8_t kIeContentSize = sizeof(uint16_t) * 2;
static constexpr uint8_t kId = 0x1a; ///< The CSL IE Element ID.
/**
* Initializes the CSL IE.
*/
void Init(void) { HeaderIe::Init(kId, sizeof(CslIe) - sizeof(HeaderIe)); }
/**
* Returns the CSL Period.
@@ -161,31 +181,40 @@ public:
void SetPhase(uint16_t aPhase) { mPhase = LittleEndian::HostSwap16(aPhase); }
private:
bool IsValid(void) const { return GetSize() >= sizeof(CslIe); }
uint16_t mPhase;
uint16_t mPeriod;
} OT_TOOL_PACKED_END;
/**
* Implements Termination2 IE.
*
* Is empty for template specialization.
*/
class Termination2Ie
{
public:
static constexpr uint8_t kHeaderIeId = 0x7f;
static constexpr uint8_t kIeContentSize = 0;
};
/**
* Implements vendor specific Header IE generation and parsing.
* Represents a Termination2 IE.
*/
OT_TOOL_PACKED_BEGIN
class VendorIeHeader
class Termination2Ie : public HeaderIe
{
friend class HeaderIe;
public:
static constexpr uint8_t kId = 0x7f; ///< The Termination2 IE Element ID.
/**
* Initializes the Termination2 IE.
*/
void Init(void) { HeaderIe::Init(kId, sizeof(Termination2Ie) - sizeof(HeaderIe)); }
private:
bool IsValid(void) const { return true; }
} OT_TOOL_PACKED_END;
/**
* Represents a Vendor Header IE.
*/
OT_TOOL_PACKED_BEGIN
class VendorIe : public HeaderIe
{
public:
static constexpr uint8_t kHeaderIeId = 0x00;
static constexpr uint8_t kIeContentSize = sizeof(uint8_t) * 4;
static constexpr uint8_t kId = 0x00; ///< The Vendor Specific IE Element ID.
/**
* Returns the Vendor OUI.
@@ -194,13 +223,6 @@ public:
*/
uint32_t GetVendorOui(void) const { return LittleEndian::ReadUint24(mOui); }
/**
* Sets the Vendor OUI.
*
* @param[in] aVendorOui A Vendor OUI.
*/
void SetVendorOui(uint32_t aVendorOui) { LittleEndian::WriteUint24(aVendorOui, mOui); }
/**
* Returns the Vendor IE sub-type.
*
@@ -208,11 +230,8 @@ public:
*/
uint8_t GetSubType(void) const { return mSubType; }
/**
* Sets the Vendor IE sub-type.
*
* @param[in] aSubType The Vendor IE sub-type.
*/
protected:
void SetVendorOui(uint32_t aVendorOui) { LittleEndian::WriteUint24(aVendorOui, mOui); }
void SetSubType(uint8_t aSubType) { mSubType = aSubType; }
private:
@@ -224,24 +243,25 @@ private:
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
/**
* Implements Time Header IE generation and parsing.
* Represents a Time Header IE.
*
* This IE is not specified in the Thread specification and is a custom feature in OpenThread (using Vendor IE
* with Nest OUI).
*/
OT_TOOL_PACKED_BEGIN
class TimeIe : public VendorIeHeader
class TimeIe : public VendorIe
{
public:
static constexpr uint32_t kVendorOuiNest = 0x18b430;
static constexpr uint8_t kVendorIeTime = 0x01;
static constexpr uint8_t kHeaderIeId = VendorIeHeader::kHeaderIeId;
static constexpr uint8_t kIeContentSize = VendorIeHeader::kIeContentSize + sizeof(uint8_t) + sizeof(uint64_t);
friend class HeaderIe;
public:
/**
* Initializes the time IE.
* Initializes the Time IE.
*/
void Init(void)
{
HeaderIe::Init(kId, sizeof(TimeIe) - sizeof(HeaderIe));
SetVendorOui(kVendorOuiNest);
SetSubType(kVendorIeTime);
SetSubType(kSubType);
}
/**
@@ -272,22 +292,100 @@ public:
*/
void SetTime(uint64_t aTime) { mTime = LittleEndian::HostSwap64(aTime); }
/**
* Returns a pointer to the start of Time IE specific data content (i.e., sequence field).
*
* @returns A pointer to the Time IE data content bytes.
*/
const uint8_t *GetData(void) const { return &mSequence; }
private:
bool IsValid(void) const
{
return (GetSize() >= sizeof(TimeIe)) && (GetVendorOui() == kVendorOuiNest) && (GetSubType() == kSubType);
}
static constexpr uint32_t kVendorOuiNest = 0x18b430;
static constexpr uint8_t kSubType = 0x01;
uint8_t mSequence;
uint64_t mTime;
} OT_TOOL_PACKED_END;
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
class ThreadIe
/**
* Represents a Thread Vendor IE.
*/
OT_TOOL_PACKED_BEGIN
class ThreadVendorIe : public VendorIe
{
protected:
static constexpr uint32_t kVendorOuiThread = 0xeab89b;
} OT_TOOL_PACKED_END;
/**
* Represents a Link Metrics Probing IE (using in Enhanced Ack).
*/
OT_TOOL_PACKED_BEGIN
class LinkMetricsProbingIe : public ThreadVendorIe
{
friend class HeaderIe;
public:
static constexpr uint8_t kHeaderIeId = VendorIeHeader::kHeaderIeId;
static constexpr uint8_t kIeContentSize = VendorIeHeader::kIeContentSize;
static constexpr uint32_t kVendorOuiThreadCompanyId = 0xeab89b;
static constexpr uint8_t kEnhAckProbingIe = 0x00;
};
/**
* The maximum length of Link Metrics Data in bytes (Thread specification limits metrics to 2).
*/
static constexpr uint8_t kMaxMetricsDataLen = 2;
/**
* Initializes the Link Metrics Probing IE.
*
* @param[in] aMetricsDataLen The requested length of Link Metrics Data. If greater than `kMaxMetricsDataLen`,
* then `kMaxMetricsDataLen` is used instead.
*/
void Init(uint8_t aMetricsDataLen)
{
HeaderIe::Init(kId, sizeof(LinkMetricsProbingIe) - sizeof(HeaderIe) + Min(aMetricsDataLen, kMaxMetricsDataLen));
SetVendorOui(kVendorOuiThread);
SetSubType(kSubType);
}
/**
* Returns the length of Link Metrics Data in bytes.
*
* @returns The length of Link Metrics Data in bytes.
*/
uint8_t GetMetricsDataLen(void) const { return GetSize() - sizeof(LinkMetricsProbingIe); }
/**
* Returns a pointer to the Link Metrics Data bytes.
*
* @returns A pointer to the Link Metrics Data bytes.
*/
const uint8_t *GetMetricsData(void) const { return GetBytes() + sizeof(LinkMetricsProbingIe); }
/**
* Writes Link Metrics Data content from a given buffer.
*
* @param[in] aData A pointer to a buffer containing the data to write. The caller must ensure that at least
* `GetMetricsDataLen()` bytes are available in @p aData.
*/
void WriteMetricsDataFrom(const uint8_t *aData)
{
memcpy(AsNonConst(GetMetricsData()), aData, GetMetricsDataLen());
}
private:
static constexpr uint8_t kSubType = 0x00;
bool IsValid(void) const
{
return (GetSize() >= sizeof(LinkMetricsProbingIe)) && (GetVendorOui() == kVendorOuiThread) &&
(GetSubType() == kSubType);
}
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* This class implements Rendezvous Time IE data structure.
*
@@ -296,11 +394,17 @@ public:
* not included in this class.
*/
OT_TOOL_PACKED_BEGIN
class RendezvousTimeIe
class RendezvousTimeIe : public HeaderIe
{
friend class HeaderIe;
public:
static constexpr uint8_t kHeaderIeId = 0x1d;
static constexpr uint8_t kIeContentSize = sizeof(uint16_t);
static constexpr uint8_t kId = 0x1d; ///< The Rendezvous Time IE Element ID.
/**
* Initializes the Rendezvous Time IE.
*/
void Init(void) { HeaderIe::Init(kId, sizeof(RendezvousTimeIe) - sizeof(HeaderIe)); }
/**
* This method returns the Rendezvous Time.
@@ -317,27 +421,32 @@ public:
void SetRendezvousTime(uint16_t aRendezvousTime) { mRendezvousTime = LittleEndian::HostSwap16(aRendezvousTime); }
private:
bool IsValid(void) const { return GetSize() >= sizeof(RendezvousTimeIe); }
uint16_t mRendezvousTime;
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Implements Connection IE data structure.
*/
OT_TOOL_PACKED_BEGIN
class ConnectionIe : public VendorIeHeader
class ConnectionIe : public ThreadVendorIe
{
public:
static constexpr uint8_t kHeaderIeId = ThreadIe::kHeaderIeId;
static constexpr uint8_t kIeContentSize = ThreadIe::kIeContentSize + sizeof(uint8_t);
static constexpr uint8_t kThreadIeSubtype = 0x01;
friend class HeaderIe;
public:
/**
* Initializes the Connection IE.
*
* @param[in] aWakeupIdLength The length of the Wakeup ID field in bytes.
*/
void Init(void)
void Init(uint8_t aWakeupIdLength)
{
SetVendorOui(ThreadIe::kVendorOuiThreadCompanyId);
SetSubType(kThreadIeSubtype);
HeaderIe::Init(kId, sizeof(ConnectionIe) - sizeof(HeaderIe) + aWakeupIdLength);
SetVendorOui(kVendorOuiThread);
SetSubType(kSubType);
mConnectionWindow = 0;
}
@@ -398,25 +507,20 @@ public:
*/
Error GetWakeupId(WakeupId &aWakeupId) const;
/**
* Gets the pointer to the HeaderIe of this ConnectionIe.
*
* @returns A pointer to the HeaderIe.
*/
const HeaderIe *GetHeaderIe(void) const
private:
static constexpr uint8_t kSubType = 0x01;
static constexpr uint8_t kRetryIntervalMask = 0x3 << 4;
static constexpr uint8_t kRetryCountMask = 0xf << 0;
bool IsValid(void) const
{
return reinterpret_cast<const HeaderIe *>(reinterpret_cast<const uint8_t *>(this) - sizeof(HeaderIe));
return (GetSize() >= sizeof(ConnectionIe)) && (GetVendorOui() == kVendorOuiThread) &&
(GetSubType() == kSubType);
}
private:
static constexpr uint8_t kRetryIntervalOffset = 4;
static constexpr uint8_t kRetryIntervalMask = 0x3 << kRetryIntervalOffset;
static constexpr uint8_t kRetryCountMask = 0xf;
const uint8_t *GetWakeupIdData(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); }
uint8_t *GetWakeupIdData(void) { return reinterpret_cast<uint8_t *>(this) + sizeof(*this); }
uint8_t mConnectionWindow;
// Followed by variable length Wakeup ID
} OT_TOOL_PACKED_END;
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
+2 -2
View File
@@ -413,7 +413,7 @@ void SubMac::ProcessTransmitSecurity(void)
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
// Transmit security will be processed after time IE content is updated.
VerifyOrExit(mTransmitFrame.GetTimeIeOffset() == 0);
VerifyOrExit(!mTransmitFrame.Has<TimeIe>());
#endif
mTransmitFrame.ProcessTransmitAesCcm(*extAddress);
@@ -606,7 +606,7 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
aFrame.SetIsARetransmission(true);
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
if (aFrame.GetSecurityEnabled() && aFrame.IsSecurityProcessed() && aFrame.HasHeaderIe())
if (aFrame.GetSecurityEnabled() && aFrame.IsSecurityProcessed() && aFrame.HasAnyHeaderIe())
{
aFrame.DecryptTransmitAesCcm(GetExtAddress());
}
+1 -1
View File
@@ -77,7 +77,7 @@ void SubMac::UpdateCslLastSyncTimestamp(TxFrame &aFrame, RxFrame *aAckFrame)
{
// Actual synchronization timestamp should be from the sent frame instead of the current time.
// Assuming the error here since it is bounded and has very small effect on the final window duration.
if (aAckFrame != nullptr && aFrame.HasCslIe())
if (aAckFrame != nullptr && aFrame.Has<CslIe>())
{
mCslLastSync = TimeMicro(GetLocalTime());
}
+2 -2
View File
@@ -112,9 +112,9 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
rendezvousTimeUs = mIntervalUs;
rendezvousTimeUs += (mIntervalUs - (kWakeupFrameLength + kParentRequestLength) * kOctetDuration) / 2;
frame->GetRendezvousTimeIe()->SetRendezvousTime(ClampToUint16(rendezvousTimeUs / kUsPerTenSymbols));
frame->Find<Mac::RendezvousTimeIe>()->SetRendezvousTime(ClampToUint16(rendezvousTimeUs / kUsPerTenSymbols));
connectionIe = frame->GetConnectionIe();
connectionIe = frame->Find<Mac::ConnectionIe>();
connectionIe->SetRetryInterval(kConnectionRetryInterval);
connectionIe->SetRetryCount(kConnectionRetryCount);
+1 -1
View File
@@ -766,7 +766,7 @@ Neighbor *MeshForwarder::UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame,
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (aFrame.HasCslIe() && aIsDataPoll)
if (aFrame.Has<Mac::CslIe>() && aIsDataPoll)
{
failLimit = kFailedCslDataPollTransmissions;
}
+9 -3
View File
@@ -59,13 +59,19 @@ void ThreadLinkInfo::SetFrom(const Mac::RxFrame &aFrame)
mChannel = aFrame.GetChannel();
mRss = aFrame.GetRssi();
mLqi = aFrame.GetLqi();
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
if (aFrame.GetTimeIe() != nullptr)
{
mNetworkTimeOffset = aFrame.ComputeNetworkTimeOffset();
mTimeSyncSeq = aFrame.ReadTimeSyncSeq();
const Mac::TimeIe *timeIe = aFrame.Find<Mac::TimeIe>();
if (timeIe != nullptr)
{
mNetworkTimeOffset = static_cast<int64_t>(timeIe->GetTime() - aFrame.GetTimestamp());
mTimeSyncSeq = timeIe->GetSequence();
}
}
#endif
#if OPENTHREAD_CONFIG_MULTI_RADIO
mRadioType = static_cast<uint8_t>(aFrame.GetRadioType());
#endif
+13 -13
View File
@@ -761,7 +761,7 @@ void TestMacFrameAckGeneration(void)
SuccessOrQuit(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data)));
csl = reinterpret_cast<Mac::CslIe *>(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe));
csl = ackFrame.Find<Mac::CslIe>();
VerifyOrQuit(ackFrame.mLength == 25);
VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
VerifyOrQuit(ackFrame.GetSecurityEnabled());
@@ -775,8 +775,8 @@ void TestMacFrameAckGeneration(void)
VerifyOrQuit(csl->GetPeriod() == 3125 && csl->GetPhase() == 3105);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
ackFrame.SetCslIe(123, 456);
csl = reinterpret_cast<Mac::CslIe *>(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe));
ackFrame.UpdateCslIe(123, 456);
csl = ackFrame.Find<Mac::CslIe>();
VerifyOrQuit(csl->GetPeriod() == 123 && csl->GetPhase() == 456);
#endif
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
@@ -860,8 +860,8 @@ void TestMacWakeupFrameGeneration(void)
// Validate that the frame satisfies the wake-up frame definition
VerifyOrQuit(txFrame.GetType() == Mac::Frame::kTypeMultipurpose);
VerifyOrQuit(!txFrame.GetAckRequest());
VerifyOrQuit(txFrame.GetRendezvousTimeIe() != nullptr);
VerifyOrQuit(txFrame.GetConnectionIe() != nullptr);
VerifyOrQuit(txFrame.Has<Mac::RendezvousTimeIe>());
VerifyOrQuit(txFrame.Has<Mac::ConnectionIe>());
VerifyOrQuit(txFrame.GetPayloadLength() == 0);
SuccessOrQuit(txFrame.GetSrcAddr(addr));
VerifyOrQuit(CompareAddresses(src, addr));
@@ -872,13 +872,13 @@ void TestMacWakeupFrameGeneration(void)
txFrame.SetFrameCounter(0xfcfcfcfc);
txFrame.SetKeySource(kKeySource);
txFrame.SetKeyId(0x1d);
txFrame.GetRendezvousTimeIe()->SetRendezvousTime(0xabcd);
connectionIe = txFrame.GetConnectionIe();
txFrame.Find<Mac::RendezvousTimeIe>()->SetRendezvousTime(0xabcd);
connectionIe = txFrame.Find<Mac::ConnectionIe>();
connectionIe->SetRetryInterval(1);
connectionIe->SetRetryCount(12);
VerifyOrQuit(connectionIe->SetWakeupId(kWakeupId) == kErrorParse);
VerifyOrQuit(txFrame.GetRendezvousTimeIe()->GetRendezvousTime() == 0xabcd);
VerifyOrQuit(txFrame.Find<Mac::RendezvousTimeIe>()->GetRendezvousTime() == 0xabcd);
VerifyOrQuit(connectionIe->GetRetryInterval() == 1);
VerifyOrQuit(connectionIe->GetRetryCount() == 12);
VerifyOrQuit(connectionIe->GetWakeupId(wakeupId) == kErrorParse);
@@ -905,8 +905,8 @@ void TestMacWakeupFrameGeneration(void)
// Validate that the frame satisfies the wake-up frame definition
VerifyOrQuit(txFrame.GetType() == Mac::Frame::kTypeMultipurpose);
VerifyOrQuit(!txFrame.GetAckRequest());
VerifyOrQuit(txFrame.GetRendezvousTimeIe() != nullptr);
VerifyOrQuit(txFrame.GetConnectionIe() != nullptr);
VerifyOrQuit(txFrame.Has<Mac::RendezvousTimeIe>());
VerifyOrQuit(txFrame.Has<Mac::ConnectionIe>());
VerifyOrQuit(txFrame.GetPayloadLength() == 0);
SuccessOrQuit(txFrame.GetSrcAddr(addr));
VerifyOrQuit(CompareAddresses(src, addr));
@@ -917,13 +917,13 @@ void TestMacWakeupFrameGeneration(void)
txFrame.SetFrameCounter(0xfcfcfcfc);
txFrame.SetKeySource(kKeySource);
txFrame.SetKeyId(0x1d);
txFrame.GetRendezvousTimeIe()->SetRendezvousTime(0xabcd);
connectionIe = txFrame.GetConnectionIe();
txFrame.Find<Mac::RendezvousTimeIe>()->SetRendezvousTime(0xabcd);
connectionIe = txFrame.Find<Mac::ConnectionIe>();
connectionIe->SetRetryInterval(1);
connectionIe->SetRetryCount(12);
SuccessOrQuit(connectionIe->SetWakeupId(kWakeupId));
VerifyOrQuit(txFrame.GetRendezvousTimeIe()->GetRendezvousTime() == 0xabcd);
VerifyOrQuit(txFrame.Find<Mac::RendezvousTimeIe>()->GetRendezvousTime() == 0xabcd);
VerifyOrQuit(connectionIe->GetRetryInterval() == 1);
VerifyOrQuit(connectionIe->GetRetryCount() == 12);
SuccessOrQuit(connectionIe->GetWakeupId(wakeupId));