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 const BitFlags<TransferControlFlags> proposedTransferCtl(Version & kVersionMask, TransferCtlOptions);
46 const bool widerange =
47 (StartOffset > std::numeric_limits<uint32_t>::max()) || (MaxLength > std::numeric_limits<uint32_t>::max());
49 BitFlags<RangeControlFlags> rangeCtlFlags;
50 rangeCtlFlags.Set(RangeControlFlags::kDefLen, MaxLength > 0);
51 rangeCtlFlags.Set(RangeControlFlags::kStartOffset, StartOffset > 0);
52 rangeCtlFlags.Set(RangeControlFlags::kWiderange, widerange);
54 aBuffer.Put(proposedTransferCtl.Raw());
55 aBuffer.Put(rangeCtlFlags.Raw());
56 aBuffer.Put16(MaxBlockSize);
62 aBuffer.Put64(StartOffset);
66 aBuffer.Put32(static_cast<uint32_t>(StartOffset));
74 aBuffer.Put64(MaxLength);
78 aBuffer.Put32(static_cast<uint32_t>(MaxLength));
82 aBuffer.Put16(FileDesLength);
83 if (FileDesignator != nullptr)
85 aBuffer.Put(FileDesignator, static_cast<size_t>(FileDesLength));
88 if (Metadata != nullptr)
90 aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
95 CHIP_ERROR TransferInit::Parse(System::PacketBufferHandle aBuffer)
97 CHIP_ERROR err = CHIP_NO_ERROR;
98 uint8_t proposedTransferCtl;
99 uint32_t tmpUint32Value = 0; // Used for reading non-wide length and offset fields
100 uint8_t * bufStart = aBuffer->Start();
101 Reader bufReader(bufStart, aBuffer->DataLength());
102 BitFlags<RangeControlFlags> rangeCtlFlags;
104 SuccessOrExit(bufReader.Read8(&proposedTransferCtl).Read8(rangeCtlFlags.RawStorage()).Read16(&MaxBlockSize).StatusCode());
106 Version = proposedTransferCtl & kVersionMask;
107 TransferCtlOptions.SetRaw(static_cast<uint8_t>(proposedTransferCtl & ~kVersionMask));
110 if (rangeCtlFlags.Has(RangeControlFlags::kStartOffset))
112 if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
114 SuccessOrExit(bufReader.Read64(&StartOffset).StatusCode());
118 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
119 StartOffset = tmpUint32Value;
124 if (rangeCtlFlags.Has(RangeControlFlags::kDefLen))
126 if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
128 SuccessOrExit(bufReader.Read64(&MaxLength).StatusCode());
132 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
133 MaxLength = tmpUint32Value;
137 SuccessOrExit(bufReader.Read16(&FileDesLength).StatusCode());
139 VerifyOrExit(bufReader.HasAtLeast(FileDesLength), err = CHIP_ERROR_MESSAGE_INCOMPLETE);
140 FileDesignator = &bufStart[bufReader.OctetsRead()];
142 // Rest of message is metadata (could be empty)
145 if (bufReader.Remaining() > FileDesLength)
147 uint16_t metadataStartIndex = static_cast<uint16_t>(bufReader.OctetsRead() + FileDesLength);
148 Metadata = &bufStart[metadataStartIndex];
149 MetadataLength = static_cast<uint16_t>(aBuffer->DataLength() - metadataStartIndex);
152 // Retain ownership of the packet buffer so that the FileDesignator and Metadata pointers remain valid.
153 Buffer = std::move(aBuffer);
156 if (bufReader.StatusCode() != CHIP_NO_ERROR)
158 err = bufReader.StatusCode();
163 size_t TransferInit::MessageSize() const
165 BufferWriter emptyBuf(nullptr, 0);
166 return WriteToBuffer(emptyBuf).Needed();
169 bool TransferInit::operator==(const TransferInit & another) const
171 if ((MetadataLength != another.MetadataLength) || (FileDesLength != another.FileDesLength))
176 bool fileDesMatches = true;
177 if (FileDesLength > 0)
179 fileDesMatches = (memcmp(FileDesignator, another.FileDesignator, FileDesLength) == 0);
182 bool metadataMatches = true;
183 if (MetadataLength > 0)
185 metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
188 return ((Version == another.Version) && (TransferCtlOptions == another.TransferCtlOptions) &&
189 (StartOffset == another.StartOffset) && (MaxLength == another.MaxLength) && (MaxBlockSize == another.MaxBlockSize) &&
190 fileDesMatches && metadataMatches);
193 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
194 // the size of the message (even if the message is incomplete or filled out incorrectly).
195 Encoding::LittleEndian::BufferWriter & SendAccept::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
197 const BitFlags<TransferControlFlags> transferCtl(Version & kVersionMask, TransferCtlFlags);
199 aBuffer.Put(transferCtl.Raw());
200 aBuffer.Put16(MaxBlockSize);
202 if (Metadata != nullptr)
204 aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
209 CHIP_ERROR SendAccept::Parse(System::PacketBufferHandle aBuffer)
211 CHIP_ERROR err = CHIP_NO_ERROR;
212 uint8_t transferCtl = 0;
213 uint8_t * bufStart = aBuffer->Start();
214 Reader bufReader(bufStart, aBuffer->DataLength());
216 SuccessOrExit(bufReader.Read8(&transferCtl).Read16(&MaxBlockSize).StatusCode());
218 Version = transferCtl & kVersionMask;
220 // Only one of these values should be set. It is up to the caller to verify this.
221 TransferCtlFlags.SetRaw(static_cast<uint8_t>(transferCtl & ~kVersionMask));
223 // Rest of message is metadata (could be empty)
226 if (bufReader.Remaining() > 0)
228 Metadata = &bufStart[bufReader.OctetsRead()];
229 MetadataLength = bufReader.Remaining();
232 // Retain ownership of the packet buffer so that the Metadata pointer remains valid.
233 Buffer = std::move(aBuffer);
236 if (bufReader.StatusCode() != CHIP_NO_ERROR)
238 err = bufReader.StatusCode();
243 size_t SendAccept::MessageSize() const
245 BufferWriter emptyBuf(nullptr, 0);
246 return WriteToBuffer(emptyBuf).Needed();
249 bool SendAccept::operator==(const SendAccept & another) const
251 if (MetadataLength != another.MetadataLength)
256 bool metadataMatches = true;
257 if (MetadataLength > 0)
259 metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
262 return ((Version == another.Version) && (TransferCtlFlags == another.TransferCtlFlags) &&
263 (MaxBlockSize == another.MaxBlockSize) && metadataMatches);
266 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
267 // the size of the message (even if the message is incomplete or filled out incorrectly).
268 Encoding::LittleEndian::BufferWriter & ReceiveAccept::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
270 const BitFlags<TransferControlFlags> transferCtlFlags(Version & kVersionMask, TransferCtlFlags);
271 const bool widerange = (StartOffset > std::numeric_limits<uint32_t>::max()) || (Length > std::numeric_limits<uint32_t>::max());
273 BitFlags<RangeControlFlags> rangeCtlFlags;
274 rangeCtlFlags.Set(RangeControlFlags::kDefLen, Length > 0);
275 rangeCtlFlags.Set(RangeControlFlags::kStartOffset, StartOffset > 0);
276 rangeCtlFlags.Set(RangeControlFlags::kWiderange, widerange);
278 aBuffer.Put(transferCtlFlags.Raw());
279 aBuffer.Put(rangeCtlFlags.Raw());
280 aBuffer.Put16(MaxBlockSize);
286 aBuffer.Put64(StartOffset);
290 aBuffer.Put32(static_cast<uint32_t>(StartOffset));
298 aBuffer.Put64(Length);
302 aBuffer.Put32(static_cast<uint32_t>(Length));
306 if (Metadata != nullptr)
308 aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
313 CHIP_ERROR ReceiveAccept::Parse(System::PacketBufferHandle aBuffer)
315 CHIP_ERROR err = CHIP_NO_ERROR;
316 uint8_t transferCtl = 0;
317 uint32_t tmpUint32Value = 0; // Used for reading non-wide length and offset fields
318 uint8_t * bufStart = aBuffer->Start();
319 Reader bufReader(bufStart, aBuffer->DataLength());
320 BitFlags<RangeControlFlags> rangeCtlFlags;
322 SuccessOrExit(bufReader.Read8(&transferCtl).Read8(rangeCtlFlags.RawStorage()).Read16(&MaxBlockSize).StatusCode());
324 Version = transferCtl & kVersionMask;
326 // Only one of these values should be set. It is up to the caller to verify this.
327 TransferCtlFlags.SetRaw(static_cast<uint8_t>(transferCtl & ~kVersionMask));
330 if (rangeCtlFlags.Has(RangeControlFlags::kStartOffset))
332 if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
334 SuccessOrExit(bufReader.Read64(&StartOffset).StatusCode());
338 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
339 StartOffset = tmpUint32Value;
344 if (rangeCtlFlags.Has(RangeControlFlags::kDefLen))
346 if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
348 SuccessOrExit(bufReader.Read64(&Length).StatusCode());
352 SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
353 Length = tmpUint32Value;
357 // Rest of message is metadata (could be empty)
360 if (bufReader.Remaining() > 0)
362 Metadata = &bufStart[bufReader.OctetsRead()];
363 MetadataLength = bufReader.Remaining();
366 // Retain ownership of the packet buffer so that the Metadata pointer remains valid.
367 Buffer = std::move(aBuffer);
370 if (bufReader.StatusCode() != CHIP_NO_ERROR)
372 err = bufReader.StatusCode();
377 size_t ReceiveAccept::MessageSize() const
379 BufferWriter emptyBuf(nullptr, 0);
380 return WriteToBuffer(emptyBuf).Needed();
383 bool ReceiveAccept::operator==(const ReceiveAccept & another) const
385 if (MetadataLength != another.MetadataLength)
390 bool metadataMatches = true;
391 if (MetadataLength > 0)
393 metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
396 return ((Version == another.Version) && (TransferCtlFlags == another.TransferCtlFlags) &&
397 (StartOffset == another.StartOffset) && (MaxBlockSize == another.MaxBlockSize) && (Length == another.Length) &&
401 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
402 // the size of the message (even if the message is incomplete or filled out incorrectly).
403 Encoding::LittleEndian::BufferWriter & CounterMessage::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
405 return aBuffer.Put32(BlockCounter);
408 CHIP_ERROR CounterMessage::Parse(System::PacketBufferHandle aBuffer)
410 uint8_t * bufStart = aBuffer->Start();
411 Reader bufReader(bufStart, aBuffer->DataLength());
412 return bufReader.Read32(&BlockCounter).StatusCode();
415 size_t CounterMessage::MessageSize() const
417 BufferWriter emptyBuf(nullptr, 0);
418 return WriteToBuffer(emptyBuf).Needed();
421 bool CounterMessage::operator==(const CounterMessage & another) const
423 return (BlockCounter == another.BlockCounter);
426 // WARNING: this function should never return early, since MessageSize() relies on it to calculate
427 // the size of the message (even if the message is incomplete or filled out incorrectly).
428 Encoding::LittleEndian::BufferWriter & DataBlock::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const
430 aBuffer.Put32(BlockCounter);
433 aBuffer.Put(Data, DataLength);
438 CHIP_ERROR DataBlock::Parse(System::PacketBufferHandle aBuffer)
440 CHIP_ERROR err = CHIP_NO_ERROR;
441 uint8_t * bufStart = aBuffer->Start();
442 Reader bufReader(bufStart, aBuffer->DataLength());
444 SuccessOrExit(bufReader.Read32(&BlockCounter).StatusCode());
446 // Rest of message is data
449 if (bufReader.Remaining() > 0)
451 Data = &bufStart[bufReader.OctetsRead()];
452 DataLength = bufReader.Remaining();
455 // Retain ownership of the packet buffer so that the Data pointer remains valid.
456 Buffer = std::move(aBuffer);
459 if (bufReader.StatusCode() != CHIP_NO_ERROR)
461 err = bufReader.StatusCode();
466 size_t DataBlock::MessageSize() const
468 BufferWriter emptyBuf(nullptr, 0);
469 return WriteToBuffer(emptyBuf).Needed();
472 bool DataBlock::operator==(const DataBlock & another) const
474 if (DataLength != another.DataLength)
479 bool dataMatches = true;
482 dataMatches = memcmp(Data, another.Data, DataLength) == 0;
485 return ((BlockCounter == another.BlockCounter) && dataMatches);