3 * Copyright (c) 2020-2021 Project CHIP Authors
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 * Implements utility methods for working with some complex BDX messages.
24 #include <protocols/bdx/BdxMessages.h>
26 #include <support/BufferReader.h>
27 #include <support/BufferWriter.h>
28 #include <support/CodeUtils.h>
34 constexpr uint8_t kVersionMask = 0x0F;
38 using namespace chip::bdx;
39 using namespace chip::Encoding::LittleEndian;
41 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
42 // the size of the message (even if the message is incomplete or filled out incorrectly).
43 BufferWriter & TransferInit::WriteToBuffer(BufferWriter & aBuffer) const
45 uint8_t proposedTransferCtl = 0;
46 bool widerange = (StartOffset > std::numeric_limits<uint32_t>::max()) || (MaxLength > std::numeric_limits<uint32_t>::max());
48 proposedTransferCtl |= Version & kVersionMask;
49 proposedTransferCtl = proposedTransferCtl | TransferCtlOptions.Raw();
51 BitFlags<uint8_t, RangeControlFlags> rangeCtlFlags;
52 rangeCtlFlags.Set(kRange_DefLen, MaxLength > 0);
53 rangeCtlFlags.Set(kRange_StartOffset, StartOffset > 0);
54 rangeCtlFlags.Set(kRange_Widerange, widerange);
56 aBuffer.Put(proposedTransferCtl);
57 aBuffer.Put(rangeCtlFlags.Raw());
58 aBuffer.Put16(MaxBlockSize);
64 aBuffer.Put64(StartOffset);
68 aBuffer.Put32(static_cast<uint32_t>(StartOffset));
76 aBuffer.Put64(MaxLength);
80 aBuffer.Put32(static_cast<uint32_t>(MaxLength));
84 aBuffer.Put16(FileDesLength);
85 if (FileDesignator != nullptr)
87 aBuffer.Put(FileDesignator, static_cast<size_t>(FileDesLength));
90 if (Metadata != nullptr)
92 aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
97 CHIP_ERROR TransferInit::Parse(System::PacketBufferHandle aBuffer)
99 CHIP_ERROR err = CHIP_NO_ERROR;
100 uint8_t proposedTransferCtl;
102 uint32_t tmpUint32Value = 0; // Used for reading non-wide length and offset fields
103 uint8_t * bufStart = aBuffer->Start();
104 Reader bufReader(bufStart, aBuffer->DataLength());
105 BitFlags<uint8_t, RangeControlFlags> rangeCtlFlags;
107 SuccessOrExit(bufReader.Read8(&proposedTransferCtl).Read8(&rangeCtl).Read16(&MaxBlockSize).StatusCode());
109 Version = proposedTransferCtl & kVersionMask;
110 TransferCtlOptions.SetRaw(static_cast<uint8_t>(proposedTransferCtl & ~kVersionMask));
111 rangeCtlFlags.SetRaw(rangeCtl);
114 if (rangeCtlFlags.Has(kRange_StartOffset))
116 if (rangeCtlFlags.Has(kRange_Widerange))
118 SuccessOrExit(bufReader.Read64(&StartOffset).StatusCode());
122 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
123 StartOffset = tmpUint32Value;
128 if (rangeCtlFlags.Has(kRange_DefLen))
130 if (rangeCtlFlags.Has(kRange_Widerange))
132 SuccessOrExit(bufReader.Read64(&MaxLength).StatusCode());
136 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
137 MaxLength = tmpUint32Value;
141 SuccessOrExit(bufReader.Read16(&FileDesLength).StatusCode());
143 VerifyOrExit(bufReader.HasAtLeast(FileDesLength), err = CHIP_ERROR_MESSAGE_INCOMPLETE);
144 FileDesignator = &bufStart[bufReader.OctetsRead()];
146 // Rest of message is metadata (could be empty)
149 if (bufReader.Remaining() > FileDesLength)
151 uint16_t metadataStartIndex = static_cast<uint16_t>(bufReader.OctetsRead() + FileDesLength);
152 Metadata = &bufStart[metadataStartIndex];
153 MetadataLength = static_cast<uint16_t>(aBuffer->DataLength() - metadataStartIndex);
156 // Retain ownership of the packet buffer so that the FileDesignator and Metadata pointers remain valid.
157 Buffer = std::move(aBuffer);
160 if (bufReader.StatusCode() != CHIP_NO_ERROR)
162 err = bufReader.StatusCode();
167 size_t TransferInit::MessageSize() const
169 BufferWriter emptyBuf(nullptr, 0);
170 return WriteToBuffer(emptyBuf).Needed();
173 bool TransferInit::operator==(const TransferInit & another) const
175 if ((MetadataLength != another.MetadataLength) || (FileDesLength != another.FileDesLength))
180 bool fileDesMatches = true;
181 if (FileDesLength > 0)
183 fileDesMatches = (memcmp(FileDesignator, another.FileDesignator, FileDesLength) == 0);
186 bool metadataMatches = true;
187 if (MetadataLength > 0)
189 metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
192 return ((Version == another.Version) && (TransferCtlOptions.Raw() == another.TransferCtlOptions.Raw()) &&
193 (StartOffset == another.StartOffset) && (MaxLength == another.MaxLength) && (MaxBlockSize == another.MaxBlockSize) &&
194 fileDesMatches && metadataMatches);
197 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
198 // the size of the message (even if the message is incomplete or filled out incorrectly).
199 Encoding::LittleEndian::BufferWriter & SendAccept::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
201 uint8_t transferCtl = 0;
203 transferCtl |= Version & kVersionMask;
204 transferCtl = transferCtl | TransferCtlFlags.Raw();
206 aBuffer.Put(transferCtl);
207 aBuffer.Put16(MaxBlockSize);
209 if (Metadata != nullptr)
211 aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
216 CHIP_ERROR SendAccept::Parse(System::PacketBufferHandle aBuffer)
218 CHIP_ERROR err = CHIP_NO_ERROR;
219 uint8_t transferCtl = 0;
220 uint8_t * bufStart = aBuffer->Start();
221 Reader bufReader(bufStart, aBuffer->DataLength());
223 SuccessOrExit(bufReader.Read8(&transferCtl).Read16(&MaxBlockSize).StatusCode());
225 Version = transferCtl & kVersionMask;
227 // Only one of these values should be set. It is up to the caller to verify this.
228 TransferCtlFlags.SetRaw(static_cast<uint8_t>(transferCtl & ~kVersionMask));
230 // Rest of message is metadata (could be empty)
233 if (bufReader.Remaining() > 0)
235 Metadata = &bufStart[bufReader.OctetsRead()];
236 MetadataLength = bufReader.Remaining();
239 // Retain ownership of the packet buffer so that the Metadata pointer remains valid.
240 Buffer = std::move(aBuffer);
243 if (bufReader.StatusCode() != CHIP_NO_ERROR)
245 err = bufReader.StatusCode();
250 size_t SendAccept::MessageSize() const
252 BufferWriter emptyBuf(nullptr, 0);
253 return WriteToBuffer(emptyBuf).Needed();
256 bool SendAccept::operator==(const SendAccept & another) const
258 if (MetadataLength != another.MetadataLength)
263 bool metadataMatches = true;
264 if (MetadataLength > 0)
266 metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
269 return ((Version == another.Version) && (TransferCtlFlags.Raw() == another.TransferCtlFlags.Raw()) &&
270 (MaxBlockSize == another.MaxBlockSize) && metadataMatches);
273 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
274 // the size of the message (even if the message is incomplete or filled out incorrectly).
275 Encoding::LittleEndian::BufferWriter & ReceiveAccept::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
277 uint8_t transferCtl = 0;
278 bool widerange = (StartOffset > std::numeric_limits<uint32_t>::max()) || (Length > std::numeric_limits<uint32_t>::max());
280 transferCtl |= Version & kVersionMask;
281 transferCtl = transferCtl | TransferCtlFlags.Raw();
283 BitFlags<uint8_t, RangeControlFlags> rangeCtlFlags;
284 rangeCtlFlags.Set(kRange_DefLen, Length > 0);
285 rangeCtlFlags.Set(kRange_StartOffset, StartOffset > 0);
286 rangeCtlFlags.Set(kRange_Widerange, widerange);
288 aBuffer.Put(transferCtl);
289 aBuffer.Put(rangeCtlFlags.Raw());
290 aBuffer.Put16(MaxBlockSize);
296 aBuffer.Put64(StartOffset);
300 aBuffer.Put32(static_cast<uint32_t>(StartOffset));
308 aBuffer.Put64(Length);
312 aBuffer.Put32(static_cast<uint32_t>(Length));
316 if (Metadata != nullptr)
318 aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
323 CHIP_ERROR ReceiveAccept::Parse(System::PacketBufferHandle aBuffer)
325 CHIP_ERROR err = CHIP_NO_ERROR;
326 uint8_t transferCtl = 0;
327 uint8_t rangeCtl = 0;
328 uint32_t tmpUint32Value = 0; // Used for reading non-wide length and offset fields
329 uint8_t * bufStart = aBuffer->Start();
330 Reader bufReader(bufStart, aBuffer->DataLength());
331 BitFlags<uint8_t, RangeControlFlags> rangeCtlFlags;
333 SuccessOrExit(bufReader.Read8(&transferCtl).Read8(&rangeCtl).Read16(&MaxBlockSize).StatusCode());
335 Version = transferCtl & kVersionMask;
337 // Only one of these values should be set. It is up to the caller to verify this.
338 TransferCtlFlags.SetRaw(static_cast<uint8_t>(transferCtl & ~kVersionMask));
340 rangeCtlFlags.SetRaw(rangeCtl);
343 if (rangeCtlFlags.Has(kRange_StartOffset))
345 if (rangeCtlFlags.Has(kRange_Widerange))
347 SuccessOrExit(bufReader.Read64(&StartOffset).StatusCode());
351 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
352 StartOffset = tmpUint32Value;
357 if (rangeCtlFlags.Has(kRange_DefLen))
359 if (rangeCtlFlags.Has(kRange_Widerange))
361 SuccessOrExit(bufReader.Read64(&Length).StatusCode());
365 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
366 Length = tmpUint32Value;
370 // Rest of message is metadata (could be empty)
373 if (bufReader.Remaining() > 0)
375 Metadata = &bufStart[bufReader.OctetsRead()];
376 MetadataLength = bufReader.Remaining();
379 // Retain ownership of the packet buffer so that the Metadata pointer remains valid.
380 Buffer = std::move(aBuffer);
383 if (bufReader.StatusCode() != CHIP_NO_ERROR)
385 err = bufReader.StatusCode();
390 size_t ReceiveAccept::MessageSize() const
392 BufferWriter emptyBuf(nullptr, 0);
393 return WriteToBuffer(emptyBuf).Needed();
396 bool ReceiveAccept::operator==(const ReceiveAccept & another) const
398 if (MetadataLength != another.MetadataLength)
403 bool metadataMatches = true;
404 if (MetadataLength > 0)
406 metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
409 return ((Version == another.Version) && (TransferCtlFlags.Raw() == another.TransferCtlFlags.Raw()) &&
410 (StartOffset == another.StartOffset) && (MaxBlockSize == another.MaxBlockSize) && (Length == another.Length) &&
414 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
415 // the size of the message (even if the message is incomplete or filled out incorrectly).
416 Encoding::LittleEndian::BufferWriter & CounterMessage::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
418 return aBuffer.Put32(BlockCounter);
421 CHIP_ERROR CounterMessage::Parse(System::PacketBufferHandle aBuffer)
423 uint8_t * bufStart = aBuffer->Start();
424 Reader bufReader(bufStart, aBuffer->DataLength());
425 return bufReader.Read32(&BlockCounter).StatusCode();
428 size_t CounterMessage::MessageSize() const
430 BufferWriter emptyBuf(nullptr, 0);
431 return WriteToBuffer(emptyBuf).Needed();
434 bool CounterMessage::operator==(const CounterMessage & another) const
436 return (BlockCounter == another.BlockCounter);
439 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
440 // the size of the message (even if the message is incomplete or filled out incorrectly).
441 Encoding::LittleEndian::BufferWriter & DataBlock::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
443 aBuffer.Put32(BlockCounter);
446 aBuffer.Put(Data, DataLength);
451 CHIP_ERROR DataBlock::Parse(System::PacketBufferHandle aBuffer)
453 CHIP_ERROR err = CHIP_NO_ERROR;
454 uint8_t * bufStart = aBuffer->Start();
455 Reader bufReader(bufStart, aBuffer->DataLength());
457 SuccessOrExit(bufReader.Read32(&BlockCounter).StatusCode());
459 // Rest of message is data
462 if (bufReader.Remaining() > 0)
464 Data = &bufStart[bufReader.OctetsRead()];
465 DataLength = bufReader.Remaining();
468 // Retain ownership of the packet buffer so that the Data pointer remains valid.
469 Buffer = std::move(aBuffer);
472 if (bufReader.StatusCode() != CHIP_NO_ERROR)
474 err = bufReader.StatusCode();
479 size_t DataBlock::MessageSize() const
481 BufferWriter emptyBuf(nullptr, 0);
482 return WriteToBuffer(emptyBuf).Needed();
485 bool DataBlock::operator==(const DataBlock & another) const
487 if (DataLength != another.DataLength)
492 bool dataMatches = true;
495 dataMatches = memcmp(Data, another.Data, DataLength) == 0;
498 return ((BlockCounter == another.BlockCounter) && dataMatches);