Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020-2021 Project CHIP Authors 4 : * Copyright (c) 2015-2017 Nest Labs, Inc. 5 : * 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 9 : * 10 : * http://www.apache.org/licenses/LICENSE-2.0 11 : * 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. 17 : */ 18 : #include <lib/core/TLVUpdater.h> 19 : 20 : #include <stdint.h> 21 : #include <string.h> 22 : 23 : #include <lib/core/CHIPConfig.h> 24 : #include <lib/core/CHIPError.h> 25 : #include <lib/core/TLVCommon.h> 26 : #include <lib/core/TLVReader.h> 27 : #include <lib/core/TLVTags.h> 28 : #include <lib/core/TLVTypes.h> 29 : #include <lib/core/TLVWriter.h> 30 : #include <lib/support/BufferWriter.h> 31 : #include <lib/support/CodeUtils.h> 32 : #include <lib/support/logging/Constants.h> 33 : #include <lib/support/logging/TextOnlyLogging.h> 34 : 35 : namespace chip { 36 : namespace TLV { 37 : 38 : using namespace chip::Encoding; 39 : 40 4 : CHIP_ERROR TLVUpdater::Init(uint8_t * buf, uint32_t dataLen, uint32_t maxLen) 41 : { 42 : uint32_t freeLen; 43 : 44 4 : VerifyOrReturnError(buf != nullptr, CHIP_ERROR_INVALID_ARGUMENT); 45 : 46 4 : VerifyOrReturnError(maxLen >= dataLen, CHIP_ERROR_BUFFER_TOO_SMALL); 47 : 48 : // memmove the buffer data to end of the buffer 49 4 : freeLen = maxLen - dataLen; 50 4 : memmove(buf + freeLen, buf, dataLen); 51 : 52 : // Init reader 53 4 : mUpdaterReader.Init(buf + freeLen, dataLen); 54 : 55 : // Init writer 56 4 : mUpdaterWriter.Init(buf, freeLen); 57 4 : mUpdaterWriter.SetCloseContainerReserved(false); 58 4 : mElementStartAddr = buf + freeLen; 59 : 60 4 : return CHIP_NO_ERROR; 61 : } 62 : 63 2 : CHIP_ERROR TLVUpdater::Init(TLVReader & aReader, uint32_t freeLen) 64 : { 65 2 : uint8_t * buf = const_cast<uint8_t *>(aReader.GetReadPoint()); 66 2 : uint32_t remainingDataLen = aReader.GetRemainingLength(); 67 2 : uint32_t readDataLen = aReader.GetLengthRead(); 68 : 69 : // TLVUpdater does not support backing stores yet 70 2 : VerifyOrReturnError(aReader.mBackingStore == nullptr, CHIP_ERROR_NOT_IMPLEMENTED); 71 : 72 : // TLVReader should point to a non-NULL buffer 73 2 : VerifyOrReturnError(buf != nullptr, CHIP_ERROR_INVALID_ARGUMENT); 74 : 75 : // If reader is already on an element, reset it to start of element 76 2 : if (aReader.ElementType() != TLVElementType::NotSpecified) 77 : { 78 : uint8_t elemHeadLen; 79 : 80 2 : ReturnErrorOnFailure(aReader.GetElementHeadLength(elemHeadLen)); 81 : 82 2 : buf -= elemHeadLen; 83 2 : remainingDataLen += elemHeadLen; 84 2 : readDataLen -= elemHeadLen; 85 : } 86 : 87 : // memmove the buffer data to end of the buffer 88 2 : memmove(buf + freeLen, buf, remainingDataLen); 89 : 90 : // Initialize the internal reader object 91 2 : mUpdaterReader.mBackingStore = nullptr; 92 2 : mUpdaterReader.mReadPoint = buf + freeLen; 93 2 : mUpdaterReader.mBufEnd = buf + freeLen + remainingDataLen; 94 2 : mUpdaterReader.mLenRead = readDataLen; 95 2 : mUpdaterReader.mMaxLen = aReader.mMaxLen; 96 2 : mUpdaterReader.mControlByte = kTLVControlByte_NotSpecified; 97 2 : mUpdaterReader.mElemTag = AnonymousTag(); 98 2 : mUpdaterReader.mElemLenOrVal = 0; 99 2 : mUpdaterReader.mContainerType = aReader.mContainerType; 100 2 : mUpdaterReader.SetContainerOpen(false); 101 : 102 2 : mUpdaterReader.ImplicitProfileId = aReader.ImplicitProfileId; 103 2 : mUpdaterReader.AppData = aReader.AppData; 104 : 105 : // TODO(#30825): Need to ensure we use TLVWriter public API rather than touch the innards. 106 : 107 : // Initialize the internal writer object 108 2 : mUpdaterWriter.mBackingStore = nullptr; 109 2 : mUpdaterWriter.mBufStart = buf - readDataLen; 110 2 : mUpdaterWriter.mWritePoint = buf; 111 2 : mUpdaterWriter.mRemainingLen = freeLen; 112 2 : mUpdaterWriter.mLenWritten = readDataLen; 113 2 : mUpdaterWriter.mMaxLen = readDataLen + freeLen; 114 2 : mUpdaterWriter.mContainerType = aReader.mContainerType; 115 2 : mUpdaterWriter.SetContainerOpen(false); 116 2 : mUpdaterWriter.SetCloseContainerReserved(false); 117 : 118 2 : mUpdaterWriter.ImplicitProfileId = aReader.ImplicitProfileId; 119 2 : mUpdaterWriter.mInitializationCookie = TLVWriter::kExpectedInitializationCookie; 120 : 121 : // Cache element start address for internal use 122 2 : mElementStartAddr = buf + freeLen; 123 : 124 : // Clear the input reader object before returning. The user can no longer 125 : // use the original TLVReader object anymore. 126 2 : aReader.Init(static_cast<const uint8_t *>(nullptr), 0); 127 : 128 2 : return CHIP_NO_ERROR; 129 : } 130 : 131 4 : void TLVUpdater::SetImplicitProfileId(uint32_t profileId) 132 : { 133 4 : mUpdaterReader.ImplicitProfileId = profileId; 134 4 : mUpdaterWriter.ImplicitProfileId = profileId; 135 4 : } 136 : 137 23 : CHIP_ERROR TLVUpdater::Next() 138 : { 139 : // Skip current element if the reader is already positioned on an element 140 23 : ReturnErrorOnFailure(mUpdaterReader.Skip()); 141 : 142 22 : AdjustInternalWriterFreeSpace(); 143 : 144 : // Move the reader to next element 145 22 : ReturnErrorOnFailure(mUpdaterReader.Next()); 146 : 147 14 : return CHIP_NO_ERROR; 148 : } 149 : 150 6 : CHIP_ERROR TLVUpdater::Move() 151 : { 152 6 : VerifyOrReturnError(mUpdaterWriter.IsInitialized(), CHIP_ERROR_INCORRECT_STATE); 153 : 154 : const uint8_t * elementEnd; 155 : uint32_t copyLen; 156 : 157 6 : VerifyOrReturnError(static_cast<TLVElementType>((mUpdaterReader.mControlByte & kTLVTypeMask)) != TLVElementType::EndOfContainer, 158 : CHIP_END_OF_TLV); 159 : 160 6 : VerifyOrReturnError(mUpdaterReader.GetType() != kTLVType_NotSpecified, CHIP_ERROR_INVALID_TLV_ELEMENT); 161 : 162 : // Skip to the end of the element 163 6 : ReturnErrorOnFailure(mUpdaterReader.Skip()); 164 : 165 6 : elementEnd = mUpdaterReader.mReadPoint; 166 : 167 6 : copyLen = static_cast<uint32_t>(elementEnd - mElementStartAddr); 168 : 169 : // Move the element to output TLV 170 6 : memmove(mUpdaterWriter.mWritePoint, mElementStartAddr, copyLen); 171 : 172 : // Adjust the updater state 173 6 : mElementStartAddr += copyLen; 174 6 : mUpdaterWriter.mWritePoint += copyLen; 175 6 : mUpdaterWriter.mLenWritten += copyLen; 176 6 : mUpdaterWriter.mMaxLen += copyLen; 177 : 178 6 : return CHIP_NO_ERROR; 179 : } 180 : 181 3 : void TLVUpdater::MoveUntilEnd() 182 : { 183 3 : VerifyOrDie(mUpdaterWriter.IsInitialized()); 184 : 185 3 : const uint8_t * buffEnd = mUpdaterReader.GetReadPoint() + mUpdaterReader.GetRemainingLength(); 186 : 187 3 : uint32_t copyLen = static_cast<uint32_t>(buffEnd - mElementStartAddr); 188 : 189 : // Move all elements till end to output TLV 190 3 : memmove(mUpdaterWriter.mWritePoint, mElementStartAddr, copyLen); 191 : 192 : // TODO(#30825): Need to ensure public API is used rather than touching the innards. 193 : // Adjust the updater state 194 3 : mElementStartAddr += copyLen; 195 3 : mUpdaterWriter.mWritePoint += copyLen; 196 3 : mUpdaterWriter.mLenWritten += copyLen; 197 3 : mUpdaterWriter.mMaxLen += copyLen; 198 3 : mUpdaterWriter.mContainerType = kTLVType_NotSpecified; 199 3 : mUpdaterWriter.SetContainerOpen(false); 200 3 : mUpdaterWriter.SetCloseContainerReserved(false); 201 3 : mUpdaterReader.mReadPoint += copyLen; 202 3 : mUpdaterReader.mLenRead += copyLen; 203 3 : mUpdaterReader.mControlByte = kTLVControlByte_NotSpecified; 204 3 : mUpdaterReader.mElemTag = AnonymousTag(); 205 3 : mUpdaterReader.mElemLenOrVal = 0; 206 3 : mUpdaterReader.mContainerType = kTLVType_NotSpecified; 207 3 : mUpdaterReader.SetContainerOpen(false); 208 3 : } 209 : 210 3 : CHIP_ERROR TLVUpdater::EnterContainer(TLVType & outerContainerType) 211 : { 212 3 : VerifyOrReturnError(mUpdaterWriter.IsInitialized(), CHIP_ERROR_INCORRECT_STATE); 213 : 214 : TLVType containerType; 215 : 216 3 : VerifyOrReturnError(TLVTypeIsContainer(static_cast<TLVType>(mUpdaterReader.mControlByte & kTLVTypeMask)), 217 : CHIP_ERROR_INCORRECT_STATE); 218 : 219 : // Change the updater state 220 3 : AdjustInternalWriterFreeSpace(); 221 : 222 3 : ReturnErrorOnFailure(mUpdaterWriter.StartContainer(mUpdaterReader.GetTag(), mUpdaterReader.GetType(), containerType)); 223 : 224 3 : ReturnErrorOnFailure(mUpdaterReader.EnterContainer(containerType)); 225 : 226 3 : outerContainerType = containerType; 227 : 228 3 : return CHIP_NO_ERROR; 229 : } 230 : 231 3 : CHIP_ERROR TLVUpdater::ExitContainer(TLVType outerContainerType) 232 : { 233 3 : ReturnErrorOnFailure(mUpdaterReader.ExitContainer(outerContainerType)); 234 : 235 : // Change the updater's state 236 3 : AdjustInternalWriterFreeSpace(); 237 : 238 3 : ReturnErrorOnFailure(mUpdaterWriter.EndContainer(outerContainerType)); 239 : 240 3 : return CHIP_NO_ERROR; 241 : } 242 : 243 : /** 244 : * This is a private method that adjusts the TLVUpdater's free space count by 245 : * accounting for the freespace from mElementStartAddr to current read point. 246 : */ 247 28 : void TLVUpdater::AdjustInternalWriterFreeSpace() 248 : { 249 28 : VerifyOrDie(mUpdaterWriter.IsInitialized()); 250 : 251 28 : const uint8_t * nextElementStart = mUpdaterReader.mReadPoint; 252 : 253 28 : if (nextElementStart != mElementStartAddr) 254 : { 255 : // Increase the internal writer's free space state variables 256 11 : uint32_t spaceIncrease = static_cast<uint32_t>(nextElementStart - mElementStartAddr); 257 11 : mUpdaterWriter.mRemainingLen += spaceIncrease; 258 11 : mUpdaterWriter.mMaxLen += spaceIncrease; 259 : 260 : // Cache the start address of the next element 261 11 : mElementStartAddr = nextElementStart; 262 : } 263 28 : } 264 : 265 : } // namespace TLV 266 : } // namespace chip