diff --git a/src/core/common/array.hpp b/src/core/common/array.hpp index 2afb4fda5..3c7537a70 100644 --- a/src/core/common/array.hpp +++ b/src/core/common/array.hpp @@ -186,6 +186,30 @@ public: */ IndexType GetLength(void) const { return mLength; } + /** + * This methods sets the current length (number of elements) of the array. + * + * @param[in] aLength The array length. + * + */ + void SetLength(IndexType aLength) { mLength = aLength; } + + /** + * This method returns the pointer to the start of underlying C array buffer serving as `Array` storage. + * + * @return The pointer to start of underlying C array buffer. + * + */ + Type *GetArrayBuffer(void) { return mElements; } + + /** + * This method returns the pointer to the start of underlying C array buffer serving as `Array` storage. + * + * @return The pointer to start of underlying C array buffer. + * + */ + const Type *GetArrayBuffer(void) const { return mElements; } + /** * This method overloads the `[]` operator to get the element at a given index. * diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index e07f7dc0d..65722dbe8 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2056,7 +2056,7 @@ exit: return error; } -Error Mle::SendChildUpdateResponse(const uint8_t *aTlvs, uint8_t aNumTlvs, const Challenge &aChallenge) +Error Mle::SendChildUpdateResponse(const TlvList &aTlvList, const Challenge &aChallenge) { Error error = kErrorNone; Ip6::Address destination; @@ -2067,9 +2067,9 @@ Error Mle::SendChildUpdateResponse(const uint8_t *aTlvs, uint8_t aNumTlvs, const SuccessOrExit(error = message->AppendSourceAddressTlv()); SuccessOrExit(error = message->AppendLeaderDataTlv()); - for (int i = 0; i < aNumTlvs; i++) + for (uint8_t tlvType : aTlvList) { - switch (aTlvs[i]) + switch (tlvType) { case Tlv::kTimeout: SuccessOrExit(error = message->AppendTimeoutTlv(mTimeout)); @@ -3422,14 +3422,11 @@ exit: void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo) { - static const uint8_t kMaxResponseTlvs = 6; - - Error error = kErrorNone; - uint16_t sourceAddress; - Challenge challenge; - RequestedTlvs requestedTlvs; - uint8_t tlvs[kMaxResponseTlvs]; - uint8_t numTlvs = 0; + Error error = kErrorNone; + uint16_t sourceAddress; + Challenge challenge; + TlvList requestedTlvList; + TlvList tlvList; // Source Address SuccessOrExit(error = Tlv::Find(aRxInfo.mMessage, sourceAddress)); @@ -3440,9 +3437,9 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo) switch (aRxInfo.mMessage.ReadChallengeTlv(challenge)) { case kErrorNone: - tlvs[numTlvs++] = Tlv::kResponse; - tlvs[numTlvs++] = Tlv::kMleFrameCounter; - tlvs[numTlvs++] = Tlv::kLinkFrameCounter; + tlvList.Add(Tlv::kResponse); + tlvList.Add(Tlv::kMleFrameCounter); + tlvList.Add(Tlv::kLinkFrameCounter); break; case kErrorNotFound: challenge.mLength = 0; @@ -3480,30 +3477,21 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo) if (Tlv::FindTlv(aRxInfo.mMessage, cslClockAccuracyTlv) == kErrorNone) { // MUST include CSL timeout TLV when request includes CSL accuracy - tlvs[numTlvs++] = Tlv::kCslTimeout; + tlvList.Add(Tlv::kCslTimeout); } #endif } else { // this device is not a child of the Child Update Request source - tlvs[numTlvs++] = Tlv::kStatus; + tlvList.Add(Tlv::kStatus); } // TLV Request - switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs)) + switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList)) { case kErrorNone: - for (uint8_t i = 0; i < requestedTlvs.mNumTlvs; i++) - { - if (numTlvs >= sizeof(tlvs)) - { - LogWarn("Failed to respond with TLVs: %d of %d", i, requestedTlvs.mNumTlvs); - break; - } - - tlvs[numTlvs++] = requestedTlvs.mTlvs[i]; - } + tlvList.AddElementsFrom(requestedTlvList); break; case kErrorNotFound: break; @@ -3520,7 +3508,7 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo) } #endif - SuccessOrExit(error = SendChildUpdateResponse(tlvs, numTlvs, challenge)); + SuccessOrExit(error = SendChildUpdateResponse(tlvList, challenge)); exit: LogProcessError(kTypeChildUpdateRequestOfParent, error); @@ -4400,6 +4388,30 @@ void Mle::HandleDetachGracefullyAddressReleaseResponse(void) } #endif // OPENTHREAD_FTD +//--------------------------------------------------------------------------------------------------------------------- +// TlvList + +void Mle::TlvList::Add(uint8_t aTlvType) +{ + VerifyOrExit(!Contains(aTlvType)); + + if (PushBack(aTlvType) != kErrorNone) + { + LogWarn("Failed to include TLV %d", aTlvType); + } + +exit: + return; +} + +void Mle::TlvList::AddElementsFrom(const TlvList &aTlvList) +{ + for (uint8_t tlvType : aTlvList) + { + Add(tlvType); + } +} + //--------------------------------------------------------------------------------------------------------------------- // Challenge @@ -5031,7 +5043,7 @@ exit: return error; } -Error Mle::RxMessage::ReadTlvRequestTlv(RequestedTlvs &aRequestedTlvs) const +Error Mle::RxMessage::ReadTlvRequestTlv(TlvList &aTlvList) const { Error error; uint16_t offset; @@ -5039,13 +5051,13 @@ Error Mle::RxMessage::ReadTlvRequestTlv(RequestedTlvs &aRequestedTlvs) const SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, Tlv::kTlvRequest, offset, length)); - if (length > sizeof(aRequestedTlvs.mTlvs)) + if (length > aTlvList.GetMaxSize()) { - length = sizeof(aRequestedTlvs.mTlvs); + length = aTlvList.GetMaxSize(); } - ReadBytes(offset, aRequestedTlvs.mTlvs, length); - aRequestedTlvs.mNumTlvs = static_cast(length); + ReadBytes(offset, aTlvList.GetArrayBuffer(), length); + aTlvList.SetLength(static_cast(length)); exit: return error; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index d91ad7634..accd72bd3 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -903,6 +903,40 @@ protected: #endif }; + static constexpr uint8_t kMaxTlvListSize = 16; ///< Maximum number of TLVs in a `TlvList`. + + /** + * This type represents a list of TLVs (array of TLV types). + * + */ + class TlvList : public Array + { + public: + /** + * This constructor initializes the `TlvList` as empty. + * + */ + TlvList(void) = default; + + /** + * This method checks if a given TLV type is not already present in the list and adds it in the list. + * + * If the list is full, this method logs it as a warning. + * + * @param[in] aTlvType The TLV type to add to the list. + * + */ + void Add(uint8_t aTlvType); + + /** + * This method adds elements from a given list to this TLV list (if not already present in the list). + * + * @param[in] aTlvList The TLV list to add elements from. + * + */ + void AddElementsFrom(const TlvList &aTlvList); + }; + /** * This type represents a Challenge (or Response) data. * @@ -942,18 +976,6 @@ protected: bool operator==(const Challenge &aOther) const { return Matches(aOther.mBuffer, aOther.mLength); } }; - /** - * This type represents list of requested TLVs in a TLV Request TLV. - * - */ - struct RequestedTlvs - { - static constexpr uint8_t kMaxNumTlvs = 16; ///< Maximum number of TLVs in request array. - - uint8_t mTlvs[kMaxNumTlvs]; ///< Array of requested TLVs. - uint8_t mNumTlvs; ///< Number of TLVs in the array. - }; - /** * This class represents an MLE Tx message. * @@ -1360,14 +1382,14 @@ protected: /** * This method reads TLV Request TLV from the message. * - * @param[out] aRequestedTlvs A reference to output the read list of requested TLVs. + * @param[out] aTlvList A reference to output the read list of requested TLVs. * * @retval kErrorNone Successfully read the TLV. * @retval kErrorNotFound TLV was not found in the message. * @retval kErrorParse TLV was found but could not be parsed. * */ - Error ReadTlvRequestTlv(RequestedTlvs &aRequestedTlvs) const; + Error ReadTlvRequestTlv(TlvList &aTlvList) const; /** * This method reads Leader Data TLV from a message. @@ -1538,15 +1560,14 @@ protected: /** * This method generates an MLE Child Update Response message. * - * @param[in] aTlvs A pointer to requested TLV types. - * @param[in] aNumTlvs The number of TLV types in @p aTlvs. + * @param[in] aTlvList A list of requested TLV types. * @param[in] aChallenge The Challenge for the response. * * @retval kErrorNone Successfully generated an MLE Child Update Response message. * @retval kErrorNoBufs Insufficient buffers to generate the MLE Child Update Response message. * */ - Error SendChildUpdateResponse(const uint8_t *aTlvs, uint8_t aNumTlvs, const Challenge &aChallenge); + Error SendChildUpdateResponse(const TlvList &aTlvList, const Challenge &aChallenge); /** * This method sets the RLOC16 assigned to the Thread interface. diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 7e1303c67..99faadd3a 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -631,13 +631,13 @@ exit: void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) { - Error error = kErrorNone; - Neighbor * neighbor = nullptr; - Challenge challenge; - uint16_t version; - LeaderData leaderData; - uint16_t sourceAddress; - RequestedTlvs requestedTlvs; + Error error = kErrorNone; + Neighbor * neighbor = nullptr; + Challenge challenge; + uint16_t version; + LeaderData leaderData; + uint16_t sourceAddress; + TlvList requestedTlvList; Log(kMessageReceive, kTypeLinkRequest, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -708,12 +708,10 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) } // TLV Request - switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs)) + switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList)) { case kErrorNone: - break; case kErrorNotFound: - requestedTlvs.mNumTlvs = 0; break; default: ExitNow(error = kErrorParse); @@ -735,7 +733,7 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) aRxInfo.mClass = RxInfo::kPeerMessage; - SuccessOrExit(error = SendLinkAccept(aRxInfo.mMessageInfo, neighbor, requestedTlvs, challenge)); + SuccessOrExit(error = SendLinkAccept(aRxInfo.mMessageInfo, neighbor, requestedTlvList, challenge)); exit: LogProcessError(kTypeLinkRequest, error); @@ -743,7 +741,7 @@ exit: Error MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, Neighbor * aNeighbor, - const RequestedTlvs & aRequestedTlvs, + const TlvList & aRequestedTlvList, const Challenge & aChallenge) { static const uint8_t kRouterTlvs[] = {Tlv::kLinkMargin}; @@ -773,9 +771,9 @@ Error MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, SuccessOrExit(error = message->AppendLeaderDataTlv()); } - for (uint8_t i = 0; i < aRequestedTlvs.mNumTlvs; i++) + for (uint8_t tlvType : aRequestedTlvList) { - switch (aRequestedTlvs.mTlvs[i]) + switch (tlvType) { case Tlv::kRoute: SuccessOrExit(error = message->AppendRouteTlv(aNeighbor)); @@ -1033,25 +1031,23 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) if (aRequest) { - Challenge challenge; - RequestedTlvs requestedTlvs; + Challenge challenge; + TlvList requestedTlvList; // Challenge SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge)); // TLV Request - switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs)) + switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList)) { case kErrorNone: - break; case kErrorNotFound: - requestedTlvs.mNumTlvs = 0; break; default: ExitNow(error = kErrorParse); } - SuccessOrExit(error = SendLinkAccept(aRxInfo.mMessageInfo, router, requestedTlvs, challenge)); + SuccessOrExit(error = SendLinkAccept(aRxInfo.mMessageInfo, router, requestedTlvList, challenge)); } exit: @@ -2347,7 +2343,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo) uint8_t modeBitmask; DeviceMode mode; uint32_t timeout; - RequestedTlvs requestedTlvs; + TlvList requestedTlvList; MeshCoP::Timestamp timestamp; bool needsActiveDatasetTlv; bool needsPendingDatasetTlv; @@ -2394,8 +2390,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo) SuccessOrExit(error = Tlv::Find(aRxInfo.mMessage, timeout)); // TLV Request - SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs)); - VerifyOrExit(requestedTlvs.mNumTlvs <= Child::kMaxRequestTlvs, error = kErrorParse); + SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList)); // Active Timestamp needsActiveDatasetTlv = true; @@ -2425,6 +2420,20 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo) ExitNow(error = kErrorParse); } + numTlvs = requestedTlvList.GetLength(); + + if (needsActiveDatasetTlv) + { + numTlvs++; + } + + if (needsPendingDatasetTlv) + { + numTlvs++; + } + + VerifyOrExit(numTlvs <= Child::kMaxRequestTlvs, error = kErrorParse); + if (!mode.IsFullThreadDevice()) { SuccessOrExit(error = @@ -2465,9 +2474,9 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo) child->SetNetworkDataVersion(mLeaderData.GetDataVersion(mode.GetNetworkDataType())); child->ClearRequestTlvs(); - for (numTlvs = 0; numTlvs < requestedTlvs.mNumTlvs; numTlvs++) + for (numTlvs = 0; numTlvs < requestedTlvList.GetLength(); numTlvs++) { - child->SetRequestTlv(numTlvs, requestedTlvs.mTlvs[numTlvs]); + child->SetRequestTlv(numTlvs, requestedTlvList[numTlvs]); } if (needsActiveDatasetTlv) @@ -2506,8 +2515,6 @@ exit: void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) { - static const uint8_t kMaxResponseTlvs = 10; - Error error = kErrorNone; Mac::ExtAddress extAddr; uint8_t modeBitmask; @@ -2517,9 +2524,8 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) uint32_t timeout; Child * child; DeviceMode oldMode; - RequestedTlvs requestedTlvs; - uint8_t tlvs[kMaxResponseTlvs]; - uint8_t tlvslength = 0; + TlvList requestedTlvList; + TlvList tlvList; uint16_t addressRegistrationOffset = 0; bool childDidChange = false; @@ -2533,7 +2539,7 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) switch (aRxInfo.mMessage.ReadChallengeTlv(challenge)) { case kErrorNone: - tlvs[tlvslength++] = Tlv::kResponse; + tlvList.Add(Tlv::kResponse); break; case kErrorNotFound: challenge.mLength = 0; @@ -2542,7 +2548,7 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) ExitNow(error = kErrorParse); } - tlvs[tlvslength++] = Tlv::kSourceAddress; + tlvList.Add(Tlv::kSourceAddress); aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr); child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid); @@ -2553,8 +2559,8 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) // Status TLV (error). if (mode.IsRxOnWhenIdle()) { - tlvs[tlvslength++] = Tlv::kStatus; - SendChildUpdateResponse(nullptr, aRxInfo.mMessageInfo, tlvs, tlvslength, challenge); + tlvList.Add(Tlv::kStatus); + SendChildUpdateResponse(nullptr, aRxInfo.mMessageInfo, tlvList, challenge); } ExitNow(); @@ -2571,22 +2577,22 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) oldMode = child->GetDeviceMode(); child->SetDeviceMode(mode); - tlvs[tlvslength++] = Tlv::kMode; + tlvList.Add(Tlv::kMode); // Parent MUST include Leader Data TLV in Child Update Response - tlvs[tlvslength++] = Tlv::kLeaderData; + tlvList.Add(Tlv::kLeaderData); if (challenge.mLength != 0) { - tlvs[tlvslength++] = Tlv::kMleFrameCounter; - tlvs[tlvslength++] = Tlv::kLinkFrameCounter; + tlvList.Add(Tlv::kMleFrameCounter); + tlvList.Add(Tlv::kLinkFrameCounter); } // IPv6 Address TLV if (Tlv::FindTlvOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addressRegistrationOffset) == kErrorNone) { SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addressRegistrationOffset, *child)); - tlvs[tlvslength++] = Tlv::kAddressRegistration; + tlvList.Add(Tlv::kAddressRegistration); } // Leader Data @@ -2611,7 +2617,7 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) childDidChange = true; } - tlvs[tlvslength++] = Tlv::kTimeout; + tlvList.Add(Tlv::kTimeout); break; case kErrorNotFound: @@ -2622,18 +2628,10 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) } // TLV Request - switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs)) + switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList)) { case kErrorNone: - VerifyOrExit(requestedTlvs.mNumTlvs <= (kMaxResponseTlvs - tlvslength), error = kErrorParse); - for (uint8_t i = 0; i < requestedTlvs.mNumTlvs; i++) - { - // Skip LeaderDataTlv since it is already included by default. - if (requestedTlvs.mTlvs[i] != Tlv::kLeaderData) - { - tlvs[tlvslength++] = requestedTlvs.mTlvs[i]; - } - } + tlvList.AddElementsFrom(requestedTlvList); break; case kErrorNotFound: break; @@ -2652,7 +2650,7 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) case kErrorNone: child->SetCslTimeout(cslTimeout); // MUST include CSL accuracy TLV when request includes CSL timeout - tlvs[tlvslength++] = Tlv::kCslClockAccuracy; + tlvList.Add(Tlv::kCslClockAccuracy); break; case kErrorNotFound: break; @@ -2712,7 +2710,7 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) } #endif - SendChildUpdateResponse(child, aRxInfo.mMessageInfo, tlvs, tlvslength, challenge); + SendChildUpdateResponse(child, aRxInfo.mMessageInfo, tlvList, challenge); aRxInfo.mClass = RxInfo::kPeerMessage; @@ -2858,22 +2856,15 @@ exit: void MleRouter::HandleDataRequest(RxInfo &aRxInfo) { Error error = kErrorNone; - RequestedTlvs requestedTlvs; + TlvList tlvList; MeshCoP::Timestamp timestamp; - uint8_t tlvs[4]; - uint8_t numTlvs; Log(kMessageReceive, kTypeDataRequest, aRxInfo.mMessageInfo.GetPeerAddr()); VerifyOrExit(aRxInfo.mNeighbor && aRxInfo.mNeighbor->IsStateValid(), error = kErrorSecurity); // TLV Request - SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs)); - VerifyOrExit(requestedTlvs.mNumTlvs <= sizeof(tlvs), error = kErrorParse); - - memset(tlvs, Tlv::kInvalid, sizeof(tlvs)); - memcpy(tlvs, requestedTlvs.mTlvs, requestedTlvs.mNumTlvs); - numTlvs = requestedTlvs.mNumTlvs; + SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList)); // Active Timestamp switch (Tlv::Find(aRxInfo.mMessage, timestamp)) @@ -2887,10 +2878,7 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo) OT_FALL_THROUGH; case kErrorNotFound: - if (numTlvs < sizeof(tlvs)) - { - tlvs[numTlvs++] = Tlv::kActiveDataset; - } + tlvList.Add(Tlv::kActiveDataset); break; default: @@ -2909,10 +2897,7 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo) OT_FALL_THROUGH; case kErrorNotFound: - if (numTlvs < sizeof(tlvs)) - { - tlvs[numTlvs++] = Tlv::kPendingDataset; - } + tlvList.Add(Tlv::kPendingDataset); break; default: @@ -2921,7 +2906,7 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo) aRxInfo.mClass = RxInfo::kPeerMessage; - SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvs, numTlvs, 0, &aRxInfo.mMessage); + SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvList, /* aDelay */ 0, &aRxInfo.mMessage); exit: LogProcessError(kTypeDataRequest, error); @@ -2929,17 +2914,17 @@ exit: void MleRouter::HandleNetworkDataUpdateRouter(void) { - static const uint8_t kTlvs[] = {Tlv::kNetworkData}; - Ip6::Address destination; uint16_t delay; + TlvList tlvList; VerifyOrExit(IsRouterOrLeader()); destination.SetToLinkLocalAllNodesMulticast(); + tlvList.Add(Tlv::kNetworkData); delay = IsLeader() ? 0 : Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter); - SendDataResponse(destination, kTlvs, sizeof(kTlvs), delay); + SendDataResponse(destination, tlvList, delay); SynchronizeChildNetworkData(); @@ -3329,8 +3314,7 @@ exit: void MleRouter::SendChildUpdateResponse(Child * aChild, const Ip6::MessageInfo &aMessageInfo, - const uint8_t * aTlvs, - uint8_t aTlvsLength, + const TlvList & aTlvList, const Challenge & aChallenge) { Error error = kErrorNone; @@ -3338,22 +3322,51 @@ void MleRouter::SendChildUpdateResponse(Child * aChild, VerifyOrExit((message = NewMleMessage(kCommandChildUpdateResponse)) != nullptr, error = kErrorNoBufs); - for (int i = 0; i < aTlvsLength; i++) + for (uint8_t tlvType : aTlvList) { - switch (aTlvs[i]) + // Add all TLV types that do not depend on `child` + + switch (tlvType) { case Tlv::kStatus: SuccessOrExit(error = message->AppendStatusTlv(StatusTlv::kError)); break; - case Tlv::kAddressRegistration: - SuccessOrExit(error = message->AppendAddresseRegisterationTlv(*aChild)); - break; - case Tlv::kLeaderData: SuccessOrExit(error = message->AppendLeaderDataTlv()); break; + case Tlv::kResponse: + SuccessOrExit(error = message->AppendResponseTlv(aChallenge)); + break; + + case Tlv::kSourceAddress: + SuccessOrExit(error = message->AppendSourceAddressTlv()); + break; + + case Tlv::kMleFrameCounter: + SuccessOrExit(error = message->AppendMleFrameCounterTlv()); + break; + + case Tlv::kLinkFrameCounter: + SuccessOrExit(error = message->AppendLinkFrameCounterTlv()); + break; + } + + // Make sure `child` is not null before adding TLV types + // that can depend on it. + + if (aChild == nullptr) + { + continue; + } + + switch (tlvType) + { + case Tlv::kAddressRegistration: + SuccessOrExit(error = message->AppendAddresseRegisterationTlv(*aChild)); + break; + case Tlv::kMode: SuccessOrExit(error = message->AppendModeTlv(aChild->GetDeviceMode())); break; @@ -3364,26 +3377,9 @@ void MleRouter::SendChildUpdateResponse(Child * aChild, SuccessOrExit(error = message->AppendPendingTimestampTlv()); break; - case Tlv::kResponse: - SuccessOrExit(error = message->AppendResponseTlv(aChallenge)); - break; - - case Tlv::kSourceAddress: - SuccessOrExit(error = message->AppendSourceAddressTlv()); - break; - case Tlv::kTimeout: SuccessOrExit(error = message->AppendTimeoutTlv(aChild->GetTimeout())); break; - - case Tlv::kMleFrameCounter: - SuccessOrExit(error = message->AppendMleFrameCounterTlv()); - break; - - case Tlv::kLinkFrameCounter: - SuccessOrExit(error = message->AppendLinkFrameCounterTlv()); - break; - #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE case Tlv::kCslClockAccuracy: if (!aChild->IsRxOnWhenIdle()) @@ -3411,8 +3407,7 @@ exit: } void MleRouter::SendDataResponse(const Ip6::Address &aDestination, - const uint8_t * aTlvs, - uint8_t aTlvsLength, + const TlvList & aTlvList, uint16_t aDelay, const Message * aRequestMessage) { @@ -3434,9 +3429,9 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination, SuccessOrExit(error = message->AppendActiveTimestampTlv()); SuccessOrExit(error = message->AppendPendingTimestampTlv()); - for (int i = 0; i < aTlvsLength; i++) + for (uint8_t tlvType : aTlvList) { - switch (aTlvs[i]) + switch (tlvType) { case Tlv::kNetworkData: neighbor = mNeighborTable.FindNeighbor(aDestination); diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index e0c7778c4..774827a76 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -618,19 +618,17 @@ private: void SendAdvertisement(void); Error SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, Neighbor * aNeighbor, - const RequestedTlvs & aRequestedTlvs, + const TlvList & aRequestedTlvList, const Challenge & aChallenge); void SendParentResponse(Child *aChild, const Challenge &aChallenge, bool aRoutersOnlyRequest); Error SendChildIdResponse(Child &aChild); Error SendChildUpdateRequest(Child &aChild); void SendChildUpdateResponse(Child * aChild, const Ip6::MessageInfo &aMessageInfo, - const uint8_t * aTlvs, - uint8_t aTlvsLength, + const TlvList & aTlvList, const Challenge & aChallenge); void SendDataResponse(const Ip6::Address &aDestination, - const uint8_t * aTlvs, - uint8_t aTlvsLength, + const TlvList & aTlvList, uint16_t aDelay, const Message * aRequestMessage = nullptr); Error SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage);