[mac] update HasCslIe and refactor GetTimeIe for robust IE parsing (#13224)

This commit introduces two robustness improvements to Header Information
Element (IE) parsing in Frame:

1. Aligned HasCslIe() with GetCslIe():
Previously, HasCslIe() returned true if a Header IE matching the CSL ID
was present, regardless of whether its declared content length was valid
(>= 4 bytes). Updating HasCslIe() to check GetCslIe() != nullptr ensures
that presence checks enforce the same length validation as retrieval,
preventing callers from assuming a malformed CSL IE is valid.

2. Robust Multi-Vendor IE Iteration in GetTimeIe():
GetTimeIe() previously retrieved the Vendor IE by matching ID 0x00
using GetHeaderIe(), which returns only the first matching element. If
a frame contained multiple Vendor IEs (e.g., a standard Thread Vendor IE
followed by a Nest Time Vendor IE), GetTimeIe() inspected only the
first element, failed the OUI check, and returned nullptr. GetTimeIe()
is refactored to iterate through all Header IEs until a matching Nest
OUI and Time SubType are found, ensuring correct discovery across
multi-vendor frames.
This commit is contained in:
Jonathan Hui
2026-06-08 19:33:10 -07:00
committed by GitHub
parent 2d602dcd9c
commit 44f5382330
+21 -10
View File
@@ -1231,7 +1231,7 @@ exit:
return;
}
bool Frame::HasCslIe(void) const { return GetHeaderIe(CslIe::kHeaderIeId) != nullptr; }
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
@@ -1266,18 +1266,29 @@ exit:
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
const TimeIe *Frame::GetTimeIe(void) const
{
const TimeIe *timeIe = nullptr;
const uint8_t *cur = nullptr;
uint16_t index = FindHeaderIeIndex();
uint16_t payloadIndex = FindPayloadIndex();
const TimeIe *timeIe = nullptr;
cur = GetHeaderIe(VendorIeHeader::kHeaderIeId);
VerifyOrExit(cur != nullptr);
VerifyOrExit(reinterpret_cast<const HeaderIe *>(cur)->GetLength() >= TimeIe::kIeContentSize);
VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
cur += sizeof(HeaderIe);
while (index < payloadIndex)
{
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
timeIe = reinterpret_cast<const TimeIe *>(cur);
VerifyOrExit(timeIe->GetVendorOui() == TimeIe::kVendorOuiNest, timeIe = nullptr);
VerifyOrExit(timeIe->GetSubType() == TimeIe::kVendorIeTime, timeIe = nullptr);
if ((ie->GetId() == VendorIeHeader::kHeaderIeId) && (ie->GetLength() >= TimeIe::kIeContentSize))
{
const TimeIe *vendorIe =
reinterpret_cast<const TimeIe *>(reinterpret_cast<const uint8_t *>(ie) + sizeof(HeaderIe));
if (vendorIe->GetVendorOui() == TimeIe::kVendorOuiNest && vendorIe->GetSubType() == TimeIe::kVendorIeTime)
{
timeIe = vendorIe;
ExitNow();
}
}
index += sizeof(HeaderIe) + ie->GetLength();
}
exit:
return timeIe;