From 44f5382330a0480ef7b5f2b99bbcda937b471dd9 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 8 Jun 2026 19:33:10 -0700 Subject: [PATCH] [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. --- src/core/mac/mac_frame.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index d47f399b9..ce00d30b7 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -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(cur)->GetLength() >= TimeIe::kIeContentSize); + VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex)); - cur += sizeof(HeaderIe); + while (index < payloadIndex) + { + const HeaderIe *ie = reinterpret_cast(&mPsdu[index]); - timeIe = reinterpret_cast(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(reinterpret_cast(ie) + sizeof(HeaderIe)); + if (vendorIe->GetVendorOui() == TimeIe::kVendorOuiNest && vendorIe->GetSubType() == TimeIe::kVendorIeTime) + { + timeIe = vendorIe; + ExitNow(); + } + } + + index += sizeof(HeaderIe) + ie->GetLength(); + } exit: return timeIe;