3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2013-2017 Nest Labs, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * This file implements a parser for the CHIP TLV (Tag-Length-Value) encoding format.
27 #include <core/CHIPCore.h>
28 #include <core/CHIPEncoding.h>
29 #include <core/CHIPTLV.h>
30 #include <support/CHIPMem.h>
31 #include <support/CodeUtils.h>
32 #include <support/SafeInt.h>
37 using namespace chip::Encoding;
39 static const uint8_t sTagSizes[] = { 0, 1, 2, 4, 2, 4, 6, 8 };
41 void TLVReader::Init(const uint8_t * data, uint32_t dataLen)
43 mBackingStore = nullptr;
45 mBufEnd = data + dataLen;
49 mContainerType = kTLVType_NotSpecified;
50 SetContainerOpen(false);
52 ImplicitProfileId = kProfileIdNotSpecified;
55 CHIP_ERROR TLVReader::Init(TLVBackingStore & backingStore, uint32_t maxLen)
57 mBackingStore = &backingStore;
60 CHIP_ERROR err = mBackingStore->OnInit(*this, mReadPoint, bufLen);
61 if (err != CHIP_NO_ERROR)
64 mBufEnd = mReadPoint + bufLen;
68 mContainerType = kTLVType_NotSpecified;
69 SetContainerOpen(false);
71 ImplicitProfileId = kProfileIdNotSpecified;
76 void TLVReader::Init(const TLVReader & aReader)
78 // Initialize private data members
80 mElemTag = aReader.mElemTag;
81 mElemLenOrVal = aReader.mElemLenOrVal;
82 mBackingStore = aReader.mBackingStore;
83 mReadPoint = aReader.mReadPoint;
84 mBufEnd = aReader.mBufEnd;
85 mLenRead = aReader.mLenRead;
86 mMaxLen = aReader.mMaxLen;
87 mControlByte = aReader.mControlByte;
88 mContainerType = aReader.mContainerType;
89 SetContainerOpen(aReader.IsContainerOpen());
91 // Initialize public data members
93 ImplicitProfileId = aReader.ImplicitProfileId;
94 AppData = aReader.AppData;
97 TLVType TLVReader::GetType() const
99 TLVElementType elemType = ElementType();
100 if (elemType == TLVElementType::EndOfContainer)
101 return kTLVType_NotSpecified;
102 if (elemType == TLVElementType::FloatingPointNumber32 || elemType == TLVElementType::FloatingPointNumber64)
103 return kTLVType_FloatingPointNumber;
104 if (elemType == TLVElementType::NotSpecified || elemType >= TLVElementType::Null)
105 return static_cast<TLVType>(elemType);
106 return static_cast<TLVType>(static_cast<uint8_t>(elemType) & ~kTLVTypeSizeMask);
109 uint32_t TLVReader::GetLength() const
111 if (TLVTypeHasLength(ElementType()))
112 return static_cast<uint32_t>(mElemLenOrVal);
116 CHIP_ERROR TLVReader::Get(bool & v)
118 TLVElementType elemType = ElementType();
119 if (elemType == TLVElementType::BooleanFalse)
121 else if (elemType == TLVElementType::BooleanTrue)
124 return CHIP_ERROR_WRONG_TLV_TYPE;
125 return CHIP_NO_ERROR;
128 CHIP_ERROR TLVReader::Get(int8_t & v)
131 CHIP_ERROR err = Get(v64);
132 v = CastToSigned(static_cast<uint8_t>(v64));
136 CHIP_ERROR TLVReader::Get(int16_t & v)
139 CHIP_ERROR err = Get(v64);
140 v = CastToSigned(static_cast<uint16_t>(v64));
144 CHIP_ERROR TLVReader::Get(int32_t & v)
147 CHIP_ERROR err = Get(v64);
148 v = CastToSigned(static_cast<uint32_t>(v64));
152 CHIP_ERROR TLVReader::Get(int64_t & v)
155 CHIP_ERROR err = Get(v64);
156 v = CastToSigned(v64);
160 CHIP_ERROR TLVReader::Get(uint8_t & v)
163 CHIP_ERROR err = Get(v64);
164 v = static_cast<uint8_t>(v64);
168 CHIP_ERROR TLVReader::Get(uint16_t & v)
171 CHIP_ERROR err = Get(v64);
172 v = static_cast<uint16_t>(v64);
176 CHIP_ERROR TLVReader::Get(uint32_t & v)
179 CHIP_ERROR err = Get(v64);
180 v = static_cast<uint32_t>(v64);
184 CHIP_ERROR TLVReader::Get(uint64_t & v)
186 switch (ElementType())
188 case TLVElementType::Int8:
189 v = static_cast<uint64_t>(static_cast<int64_t>(CastToSigned(static_cast<uint8_t>(mElemLenOrVal))));
191 case TLVElementType::Int16:
192 v = static_cast<uint64_t>(static_cast<int64_t>(CastToSigned(static_cast<uint16_t>(mElemLenOrVal))));
194 case TLVElementType::Int32:
195 v = static_cast<uint64_t>(static_cast<int64_t>(CastToSigned(static_cast<uint32_t>(mElemLenOrVal))));
197 case TLVElementType::Int64:
198 case TLVElementType::UInt8:
199 case TLVElementType::UInt16:
200 case TLVElementType::UInt32:
201 case TLVElementType::UInt64:
205 return CHIP_ERROR_WRONG_TLV_TYPE;
207 return CHIP_NO_ERROR;
210 CHIP_ERROR TLVReader::Get(double & v)
212 switch (ElementType())
214 case TLVElementType::FloatingPointNumber32: {
220 cvt.u32 = static_cast<uint32_t>(mElemLenOrVal);
224 case TLVElementType::FloatingPointNumber64: {
230 cvt.u64 = mElemLenOrVal;
235 return CHIP_ERROR_WRONG_TLV_TYPE;
237 return CHIP_NO_ERROR;
240 CHIP_ERROR TLVReader::GetBytes(uint8_t * buf, uint32_t bufSize)
242 if (!TLVTypeIsString(ElementType()))
243 return CHIP_ERROR_WRONG_TLV_TYPE;
245 if (mElemLenOrVal > bufSize)
246 return CHIP_ERROR_BUFFER_TOO_SMALL;
248 CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
249 if (err != CHIP_NO_ERROR)
254 return CHIP_NO_ERROR;
257 CHIP_ERROR TLVReader::GetString(char * buf, uint32_t bufSize)
259 if (!TLVTypeIsString(ElementType()))
260 return CHIP_ERROR_WRONG_TLV_TYPE;
262 if ((mElemLenOrVal + 1) > bufSize)
263 return CHIP_ERROR_BUFFER_TOO_SMALL;
265 buf[mElemLenOrVal] = 0;
267 return GetBytes(reinterpret_cast<uint8_t *>(buf), bufSize - 1);
270 CHIP_ERROR TLVReader::DupBytes(uint8_t *& buf, uint32_t & dataLen)
272 if (!TLVTypeIsString(ElementType()))
273 return CHIP_ERROR_WRONG_TLV_TYPE;
275 buf = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal)));
277 return CHIP_ERROR_NO_MEMORY;
279 CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
280 if (err != CHIP_NO_ERROR)
282 chip::Platform::MemoryFree(buf);
287 dataLen = static_cast<uint32_t>(mElemLenOrVal);
290 return CHIP_NO_ERROR;
293 CHIP_ERROR TLVReader::DupString(char *& buf)
295 if (!TLVTypeIsString(ElementType()))
296 return CHIP_ERROR_WRONG_TLV_TYPE;
298 if (mElemLenOrVal > UINT32_MAX - 1)
299 return CHIP_ERROR_NO_MEMORY;
301 buf = static_cast<char *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal + 1)));
303 return CHIP_ERROR_NO_MEMORY;
305 CHIP_ERROR err = ReadData(reinterpret_cast<uint8_t *>(buf), static_cast<uint32_t>(mElemLenOrVal));
306 if (err != CHIP_NO_ERROR)
308 chip::Platform::MemoryFree(buf);
313 buf[mElemLenOrVal] = 0;
319 CHIP_ERROR TLVReader::GetDataPtr(const uint8_t *& data)
323 if (!TLVTypeIsString(ElementType()))
324 return CHIP_ERROR_WRONG_TLV_TYPE;
326 err = EnsureData(CHIP_ERROR_TLV_UNDERRUN);
327 if (err != CHIP_NO_ERROR)
330 uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
332 // Verify that the entirety of the data is available in the buffer.
333 // Note that this may not be possible if the reader is reading from a chain of buffers.
334 if (remainingLen < static_cast<uint32_t>(mElemLenOrVal))
335 return CHIP_ERROR_TLV_UNDERRUN;
339 return CHIP_NO_ERROR;
342 CHIP_ERROR TLVReader::OpenContainer(TLVReader & containerReader)
344 TLVElementType elemType = ElementType();
345 if (!TLVTypeIsContainer(elemType))
346 return CHIP_ERROR_INCORRECT_STATE;
348 containerReader.mBackingStore = mBackingStore;
349 containerReader.mReadPoint = mReadPoint;
350 containerReader.mBufEnd = mBufEnd;
351 containerReader.mLenRead = mLenRead;
352 containerReader.mMaxLen = mMaxLen;
353 containerReader.ClearElementState();
354 containerReader.mContainerType = static_cast<TLVType>(elemType);
355 containerReader.SetContainerOpen(false);
356 containerReader.ImplicitProfileId = ImplicitProfileId;
357 containerReader.AppData = AppData;
359 SetContainerOpen(true);
361 return CHIP_NO_ERROR;
364 CHIP_ERROR TLVReader::CloseContainer(TLVReader & containerReader)
368 if (!IsContainerOpen())
369 return CHIP_ERROR_INCORRECT_STATE;
371 if (static_cast<TLVElementType>(containerReader.mContainerType) != ElementType())
372 return CHIP_ERROR_INCORRECT_STATE;
374 err = containerReader.SkipToEndOfContainer();
375 if (err != CHIP_NO_ERROR)
378 mBackingStore = containerReader.mBackingStore;
379 mReadPoint = containerReader.mReadPoint;
380 mBufEnd = containerReader.mBufEnd;
381 mLenRead = containerReader.mLenRead;
382 mMaxLen = containerReader.mMaxLen;
385 return CHIP_NO_ERROR;
388 CHIP_ERROR TLVReader::EnterContainer(TLVType & outerContainerType)
390 TLVElementType elemType = ElementType();
391 if (!TLVTypeIsContainer(elemType))
392 return CHIP_ERROR_INCORRECT_STATE;
394 outerContainerType = mContainerType;
395 mContainerType = static_cast<TLVType>(elemType);
398 SetContainerOpen(false);
400 return CHIP_NO_ERROR;
403 CHIP_ERROR TLVReader::ExitContainer(TLVType outerContainerType)
407 err = SkipToEndOfContainer();
408 if (err != CHIP_NO_ERROR)
411 mContainerType = outerContainerType;
414 return CHIP_NO_ERROR;
417 CHIP_ERROR TLVReader::VerifyEndOfContainer()
419 CHIP_ERROR err = Next();
420 if (err == CHIP_END_OF_TLV)
421 return CHIP_NO_ERROR;
422 if (err == CHIP_NO_ERROR)
423 return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
427 CHIP_ERROR TLVReader::Next()
430 TLVElementType elemType = ElementType();
433 if (err != CHIP_NO_ERROR)
437 if (err != CHIP_NO_ERROR)
440 elemType = ElementType();
441 if (elemType == TLVElementType::EndOfContainer)
442 return CHIP_END_OF_TLV;
444 return CHIP_NO_ERROR;
447 CHIP_ERROR TLVReader::Next(TLVType expectedType, uint64_t expectedTag)
449 CHIP_ERROR err = Next();
450 if (err != CHIP_NO_ERROR)
452 if (GetType() != expectedType)
453 return CHIP_ERROR_WRONG_TLV_TYPE;
454 if (mElemTag != expectedTag)
455 return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
456 return CHIP_NO_ERROR;
459 CHIP_ERROR TLVReader::Skip()
462 TLVElementType elemType = ElementType();
464 if (elemType == TLVElementType::EndOfContainer)
465 return CHIP_END_OF_TLV;
467 if (TLVTypeIsContainer(elemType))
469 TLVType outerContainerType;
470 err = EnterContainer(outerContainerType);
471 if (err != CHIP_NO_ERROR)
473 err = ExitContainer(outerContainerType);
474 if (err != CHIP_NO_ERROR)
481 if (err != CHIP_NO_ERROR)
487 return CHIP_NO_ERROR;
491 * Clear the state of the TLVReader.
492 * This method is used to position the reader before the first TLV,
493 * between TLVs or after the last TLV.
495 void TLVReader::ClearElementState()
497 mElemTag = AnonymousTag;
498 mControlByte = kTLVControlByte_NotSpecified;
503 * Skip any data contained in the current TLV by reading over it without
504 * a destination buffer.
506 * @retval #CHIP_NO_ERROR If the reader was successfully positioned at the end of the
508 * @retval other Other CHIP or platform error codes returned by the configured
511 CHIP_ERROR TLVReader::SkipData()
513 CHIP_ERROR err = CHIP_NO_ERROR;
514 TLVElementType elemType = ElementType();
516 if (TLVTypeHasLength(elemType))
518 err = ReadData(nullptr, static_cast<uint32_t>(mElemLenOrVal));
519 if (err != CHIP_NO_ERROR)
526 CHIP_ERROR TLVReader::SkipToEndOfContainer()
529 TLVType outerContainerType = mContainerType;
530 uint32_t nestLevel = 0;
532 // If the user calls Next() after having called OpenContainer() but before calling
533 // CloseContainer() they're effectively doing a close container by skipping over
534 // the container element. So reset the 'container open' flag here to prevent them
535 // from calling CloseContainer() with the now orphaned container reader.
536 SetContainerOpen(false);
540 TLVElementType elemType = ElementType();
542 if (elemType == TLVElementType::EndOfContainer)
545 return CHIP_NO_ERROR;
548 mContainerType = (nestLevel == 0) ? outerContainerType : kTLVType_UnknownContainer;
551 else if (TLVTypeIsContainer(elemType))
554 mContainerType = static_cast<TLVType>(elemType);
558 if (err != CHIP_NO_ERROR)
562 if (err != CHIP_NO_ERROR)
567 CHIP_ERROR TLVReader::ReadElement()
570 uint8_t stagingBuf[17]; // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes
572 TLVElementType elemType;
574 // Make sure we have input data. Return CHIP_END_OF_TLV if no more data is available.
575 err = EnsureData(CHIP_END_OF_TLV);
576 if (err != CHIP_NO_ERROR)
579 // Get the element's control byte.
580 mControlByte = *mReadPoint;
582 // Extract the element type from the control byte. Fail if it's invalid.
583 elemType = ElementType();
584 if (!IsValidTLVType(elemType))
585 return CHIP_ERROR_INVALID_TLV_ELEMENT;
587 // Extract the tag control from the control byte.
588 TLVTagControl tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
590 // Determine the number of bytes in the element's tag, if any.
591 uint8_t tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
593 // Extract the size of length/value field from the control byte.
594 TLVFieldSize lenOrValFieldSize = GetTLVFieldSize(elemType);
596 // Determine the number of bytes in the length/value field.
597 uint8_t valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
599 // Determine the number of bytes in the element's 'head'. This includes: the control byte, the tag bytes (if present), the
600 // length bytes (if present), and for elements that don't have a length (e.g. integers), the value bytes.
601 uint8_t elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
603 // If the head of the element overlaps the end of the input buffer, read the bytes into the staging buffer
604 // and arrange to parse them from there. Otherwise read them directly from the input buffer.
605 if (elemHeadBytes > (mBufEnd - mReadPoint))
607 err = ReadData(stagingBuf, elemHeadBytes);
608 if (err != CHIP_NO_ERROR)
615 mReadPoint += elemHeadBytes;
616 mLenRead += elemHeadBytes;
619 // Skip over the control byte.
622 // Read the tag field, if present.
623 mElemTag = ReadTag(tagControl, p);
625 // Read the length/value field, if present.
626 switch (lenOrValFieldSize)
628 case kTLVFieldSize_0Byte:
631 case kTLVFieldSize_1Byte:
632 mElemLenOrVal = Read8(p);
634 case kTLVFieldSize_2Byte:
635 mElemLenOrVal = LittleEndian::Read16(p);
637 case kTLVFieldSize_4Byte:
638 mElemLenOrVal = LittleEndian::Read32(p);
640 case kTLVFieldSize_8Byte:
641 mElemLenOrVal = LittleEndian::Read64(p);
645 return VerifyElement();
648 CHIP_ERROR TLVReader::VerifyElement()
650 if (ElementType() == TLVElementType::EndOfContainer)
652 if (mContainerType == kTLVType_NotSpecified)
653 return CHIP_ERROR_INVALID_TLV_ELEMENT;
654 if (mElemTag != AnonymousTag)
655 return CHIP_ERROR_INVALID_TLV_TAG;
659 if (mElemTag == UnknownImplicitTag)
660 return CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG;
661 switch (mContainerType)
663 case kTLVType_NotSpecified:
664 if (IsContextTag(mElemTag))
665 return CHIP_ERROR_INVALID_TLV_TAG;
667 case kTLVType_Structure:
668 if (mElemTag == AnonymousTag)
669 return CHIP_ERROR_INVALID_TLV_TAG;
672 if (mElemTag != AnonymousTag)
673 return CHIP_ERROR_INVALID_TLV_TAG;
675 case kTLVType_UnknownContainer:
679 return CHIP_ERROR_INCORRECT_STATE;
683 // If the current element encodes a specific length (e.g. a UTF8 string or a byte string), verify
684 // that the purported length fits within the remaining bytes of the encoding (as delineated by mMaxLen).
686 // Note that this check is not strictly necessary to prevent runtime errors, as any attempt to access
687 // the data of an element with an invalid length will result in an error. However checking the length
688 // here catches the error earlier, and ensures that the application will never see the erroneous length
691 if (TLVTypeHasLength(ElementType()))
693 uint32_t overallLenRemaining = mMaxLen - mLenRead;
694 if (overallLenRemaining < static_cast<uint32_t>(mElemLenOrVal))
695 return CHIP_ERROR_TLV_UNDERRUN;
698 return CHIP_NO_ERROR;
701 uint64_t TLVReader::ReadTag(TLVTagControl tagControl, const uint8_t *& p)
708 case TLVTagControl::ContextSpecific:
709 return ContextTag(Read8(p));
710 case TLVTagControl::CommonProfile_2Bytes:
711 return CommonTag(LittleEndian::Read16(p));
712 case TLVTagControl::CommonProfile_4Bytes:
713 return CommonTag(LittleEndian::Read32(p));
714 case TLVTagControl::ImplicitProfile_2Bytes:
715 if (ImplicitProfileId == kProfileIdNotSpecified)
716 return UnknownImplicitTag;
717 return ProfileTag(ImplicitProfileId, LittleEndian::Read16(p));
718 case TLVTagControl::ImplicitProfile_4Bytes:
719 if (ImplicitProfileId == kProfileIdNotSpecified)
720 return UnknownImplicitTag;
721 return ProfileTag(ImplicitProfileId, LittleEndian::Read32(p));
722 case TLVTagControl::FullyQualified_6Bytes:
723 vendorId = LittleEndian::Read16(p);
724 profileNum = LittleEndian::Read16(p);
725 return ProfileTag(vendorId, profileNum, LittleEndian::Read16(p));
726 case TLVTagControl::FullyQualified_8Bytes:
727 vendorId = LittleEndian::Read16(p);
728 profileNum = LittleEndian::Read16(p);
729 return ProfileTag(vendorId, profileNum, LittleEndian::Read32(p));
730 case TLVTagControl::Anonymous:
736 CHIP_ERROR TLVReader::ReadData(uint8_t * buf, uint32_t len)
742 err = EnsureData(CHIP_ERROR_TLV_UNDERRUN);
743 if (err != CHIP_NO_ERROR)
746 uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
748 uint32_t readLen = len;
749 if (readLen > remainingLen)
750 readLen = remainingLen;
754 memcpy(buf, mReadPoint, readLen);
757 mReadPoint += readLen;
762 return CHIP_NO_ERROR;
765 CHIP_ERROR TLVReader::EnsureData(CHIP_ERROR noDataErr)
769 if (mReadPoint == mBufEnd)
771 if (mLenRead == mMaxLen)
774 if (mBackingStore == nullptr)
778 err = mBackingStore->GetNextBuffer(*this, mReadPoint, bufLen);
779 if (err != CHIP_NO_ERROR)
784 // Cap mBufEnd so that we don't read beyond the user's specified maximum length, even
785 // if the underlying buffer is larger.
786 uint32_t overallLenRemaining = mMaxLen - mLenRead;
787 if (overallLenRemaining < bufLen)
788 bufLen = overallLenRemaining;
790 mBufEnd = mReadPoint + bufLen;
793 return CHIP_NO_ERROR;
797 * This is a private method used to compute the length of a TLV element head.
799 CHIP_ERROR TLVReader::GetElementHeadLength(uint8_t & elemHeadBytes) const
802 uint8_t valOrLenBytes;
803 TLVTagControl tagControl;
804 TLVFieldSize lenOrValFieldSize;
805 TLVElementType elemType = ElementType();
807 // Verify element is of valid TLVType.
808 VerifyOrReturnError(IsValidTLVType(elemType), CHIP_ERROR_INVALID_TLV_ELEMENT);
810 // Extract the tag control from the control byte.
811 tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
813 // Determine the number of bytes in the element's tag, if any.
814 tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
816 // Extract the size of length/value field from the control byte.
817 lenOrValFieldSize = GetTLVFieldSize(elemType);
819 // Determine the number of bytes in the length/value field.
820 valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
822 // Determine the number of bytes in the element's 'head'. This includes: the
823 // control byte, the tag bytes (if present), the length bytes (if present),
824 // and for elements that don't have a length (e.g. integers), the value
826 VerifyOrReturnError(CanCastTo<uint8_t>(1 + tagBytes + valOrLenBytes), CHIP_ERROR_INTERNAL);
827 elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
829 return CHIP_NO_ERROR;
833 * This is a private method that returns the TLVElementType from mControlByte
835 TLVElementType TLVReader::ElementType() const
837 if (mControlByte == static_cast<uint16_t>(kTLVControlByte_NotSpecified))
838 return TLVElementType::NotSpecified;
839 return static_cast<TLVElementType>(mControlByte & kTLVTypeMask);
842 CHIP_ERROR TLVReader::FindElementWithTag(const uint64_t tag, TLVReader & destReader) const
844 CHIP_ERROR err = CHIP_NO_ERROR;
846 chip::TLV::TLVReader reader;
849 while (CHIP_NO_ERROR == (err = reader.Next()))
851 VerifyOrExit(chip::TLV::kTLVType_NotSpecified != reader.GetType(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
853 if (tag == reader.GetTag())
855 destReader.Init(reader);
861 ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));