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
|