Apply Upstream code (2021-03-15)
[platform/upstream/connectedhomeip.git] / src / protocols / bdx / BdxMessages.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    All rights reserved.
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
19 /**
20  *    @file
21  *      Implements utility methods for working with some complex BDX messages.
22  */
23
24 #include <protocols/bdx/BdxMessages.h>
25
26 #include <support/BufferReader.h>
27 #include <support/BufferWriter.h>
28 #include <support/CodeUtils.h>
29
30 #include <limits>
31 #include <utility>
32
33 namespace {
34 constexpr uint8_t kVersionMask = 0x0F;
35 } // namespace
36
37 using namespace chip;
38 using namespace chip::bdx;
39 using namespace chip::Encoding::LittleEndian;
40
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
44 {
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());
48
49     BitFlags<RangeControlFlags> rangeCtlFlags;
50     rangeCtlFlags.Set(RangeControlFlags::kDefLen, MaxLength > 0);
51     rangeCtlFlags.Set(RangeControlFlags::kStartOffset, StartOffset > 0);
52     rangeCtlFlags.Set(RangeControlFlags::kWiderange, widerange);
53
54     aBuffer.Put(proposedTransferCtl.Raw());
55     aBuffer.Put(rangeCtlFlags.Raw());
56     aBuffer.Put16(MaxBlockSize);
57
58     if (StartOffset > 0)
59     {
60         if (widerange)
61         {
62             aBuffer.Put64(StartOffset);
63         }
64         else
65         {
66             aBuffer.Put32(static_cast<uint32_t>(StartOffset));
67         }
68     }
69
70     if (MaxLength > 0)
71     {
72         if (widerange)
73         {
74             aBuffer.Put64(MaxLength);
75         }
76         else
77         {
78             aBuffer.Put32(static_cast<uint32_t>(MaxLength));
79         }
80     }
81
82     aBuffer.Put16(FileDesLength);
83     if (FileDesignator != nullptr)
84     {
85         aBuffer.Put(FileDesignator, static_cast<size_t>(FileDesLength));
86     }
87
88     if (Metadata != nullptr)
89     {
90         aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
91     }
92     return aBuffer;
93 }
94
95 CHIP_ERROR TransferInit::Parse(System::PacketBufferHandle aBuffer)
96 {
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;
103
104     SuccessOrExit(bufReader.Read8(&proposedTransferCtl).Read8(rangeCtlFlags.RawStorage()).Read16(&MaxBlockSize).StatusCode());
105
106     Version = proposedTransferCtl & kVersionMask;
107     TransferCtlOptions.SetRaw(static_cast<uint8_t>(proposedTransferCtl & ~kVersionMask));
108
109     StartOffset = 0;
110     if (rangeCtlFlags.Has(RangeControlFlags::kStartOffset))
111     {
112         if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
113         {
114             SuccessOrExit(bufReader.Read64(&StartOffset).StatusCode());
115         }
116         else
117         {
118             SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
119             StartOffset = tmpUint32Value;
120         }
121     }
122
123     MaxLength = 0;
124     if (rangeCtlFlags.Has(RangeControlFlags::kDefLen))
125     {
126         if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
127         {
128             SuccessOrExit(bufReader.Read64(&MaxLength).StatusCode());
129         }
130         else
131         {
132             SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
133             MaxLength = tmpUint32Value;
134         }
135     }
136
137     SuccessOrExit(bufReader.Read16(&FileDesLength).StatusCode());
138
139     VerifyOrExit(bufReader.HasAtLeast(FileDesLength), err = CHIP_ERROR_MESSAGE_INCOMPLETE);
140     FileDesignator = &bufStart[bufReader.OctetsRead()];
141
142     // Rest of message is metadata (could be empty)
143     Metadata       = nullptr;
144     MetadataLength = 0;
145     if (bufReader.Remaining() > FileDesLength)
146     {
147         uint16_t metadataStartIndex = static_cast<uint16_t>(bufReader.OctetsRead() + FileDesLength);
148         Metadata                    = &bufStart[metadataStartIndex];
149         MetadataLength              = static_cast<uint16_t>(aBuffer->DataLength() - metadataStartIndex);
150     }
151
152     // Retain ownership of the packet buffer so that the FileDesignator and Metadata pointers remain valid.
153     Buffer = std::move(aBuffer);
154
155 exit:
156     if (bufReader.StatusCode() != CHIP_NO_ERROR)
157     {
158         err = bufReader.StatusCode();
159     }
160     return err;
161 }
162
163 size_t TransferInit::MessageSize() const
164 {
165     BufferWriter emptyBuf(nullptr, 0);
166     return WriteToBuffer(emptyBuf).Needed();
167 }
168
169 bool TransferInit::operator==(const TransferInit & another) const
170 {
171     if ((MetadataLength != another.MetadataLength) || (FileDesLength != another.FileDesLength))
172     {
173         return false;
174     }
175
176     bool fileDesMatches = true;
177     if (FileDesLength > 0)
178     {
179         fileDesMatches = (memcmp(FileDesignator, another.FileDesignator, FileDesLength) == 0);
180     }
181
182     bool metadataMatches = true;
183     if (MetadataLength > 0)
184     {
185         metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
186     }
187
188     return ((Version == another.Version) && (TransferCtlOptions == another.TransferCtlOptions) &&
189             (StartOffset == another.StartOffset) && (MaxLength == another.MaxLength) && (MaxBlockSize == another.MaxBlockSize) &&
190             fileDesMatches && metadataMatches);
191 }
192
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
196 {
197     const BitFlags<TransferControlFlags> transferCtl(Version & kVersionMask, TransferCtlFlags);
198
199     aBuffer.Put(transferCtl.Raw());
200     aBuffer.Put16(MaxBlockSize);
201
202     if (Metadata != nullptr)
203     {
204         aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
205     }
206     return aBuffer;
207 }
208
209 CHIP_ERROR SendAccept::Parse(System::PacketBufferHandle aBuffer)
210 {
211     CHIP_ERROR err      = CHIP_NO_ERROR;
212     uint8_t transferCtl = 0;
213     uint8_t * bufStart  = aBuffer->Start();
214     Reader bufReader(bufStart, aBuffer->DataLength());
215
216     SuccessOrExit(bufReader.Read8(&transferCtl).Read16(&MaxBlockSize).StatusCode());
217
218     Version = transferCtl & kVersionMask;
219
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));
222
223     // Rest of message is metadata (could be empty)
224     Metadata       = nullptr;
225     MetadataLength = 0;
226     if (bufReader.Remaining() > 0)
227     {
228         Metadata       = &bufStart[bufReader.OctetsRead()];
229         MetadataLength = bufReader.Remaining();
230     }
231
232     // Retain ownership of the packet buffer so that the Metadata pointer remains valid.
233     Buffer = std::move(aBuffer);
234
235 exit:
236     if (bufReader.StatusCode() != CHIP_NO_ERROR)
237     {
238         err = bufReader.StatusCode();
239     }
240     return err;
241 }
242
243 size_t SendAccept::MessageSize() const
244 {
245     BufferWriter emptyBuf(nullptr, 0);
246     return WriteToBuffer(emptyBuf).Needed();
247 }
248
249 bool SendAccept::operator==(const SendAccept & another) const
250 {
251     if (MetadataLength != another.MetadataLength)
252     {
253         return false;
254     }
255
256     bool metadataMatches = true;
257     if (MetadataLength > 0)
258     {
259         metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
260     }
261
262     return ((Version == another.Version) && (TransferCtlFlags == another.TransferCtlFlags) &&
263             (MaxBlockSize == another.MaxBlockSize) && metadataMatches);
264 }
265
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
269 {
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());
272
273     BitFlags<RangeControlFlags> rangeCtlFlags;
274     rangeCtlFlags.Set(RangeControlFlags::kDefLen, Length > 0);
275     rangeCtlFlags.Set(RangeControlFlags::kStartOffset, StartOffset > 0);
276     rangeCtlFlags.Set(RangeControlFlags::kWiderange, widerange);
277
278     aBuffer.Put(transferCtlFlags.Raw());
279     aBuffer.Put(rangeCtlFlags.Raw());
280     aBuffer.Put16(MaxBlockSize);
281
282     if (StartOffset > 0)
283     {
284         if (widerange)
285         {
286             aBuffer.Put64(StartOffset);
287         }
288         else
289         {
290             aBuffer.Put32(static_cast<uint32_t>(StartOffset));
291         }
292     }
293
294     if (Length > 0)
295     {
296         if (widerange)
297         {
298             aBuffer.Put64(Length);
299         }
300         else
301         {
302             aBuffer.Put32(static_cast<uint32_t>(Length));
303         }
304     }
305
306     if (Metadata != nullptr)
307     {
308         aBuffer.Put(Metadata, static_cast<size_t>(MetadataLength));
309     }
310     return aBuffer;
311 }
312
313 CHIP_ERROR ReceiveAccept::Parse(System::PacketBufferHandle aBuffer)
314 {
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;
321
322     SuccessOrExit(bufReader.Read8(&transferCtl).Read8(rangeCtlFlags.RawStorage()).Read16(&MaxBlockSize).StatusCode());
323
324     Version = transferCtl & kVersionMask;
325
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));
328
329     StartOffset = 0;
330     if (rangeCtlFlags.Has(RangeControlFlags::kStartOffset))
331     {
332         if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
333         {
334             SuccessOrExit(bufReader.Read64(&StartOffset).StatusCode());
335         }
336         else
337         {
338             SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
339             StartOffset = tmpUint32Value;
340         }
341     }
342
343     Length = 0;
344     if (rangeCtlFlags.Has(RangeControlFlags::kDefLen))
345     {
346         if (rangeCtlFlags.Has(RangeControlFlags::kWiderange))
347         {
348             SuccessOrExit(bufReader.Read64(&Length).StatusCode());
349         }
350         else
351         {
352             SuccessOrExit(bufReader.Read32(&tmpUint32Value).StatusCode());
353             Length = tmpUint32Value;
354         }
355     }
356
357     // Rest of message is metadata (could be empty)
358     Metadata       = nullptr;
359     MetadataLength = 0;
360     if (bufReader.Remaining() > 0)
361     {
362         Metadata       = &bufStart[bufReader.OctetsRead()];
363         MetadataLength = bufReader.Remaining();
364     }
365
366     // Retain ownership of the packet buffer so that the Metadata pointer remains valid.
367     Buffer = std::move(aBuffer);
368
369 exit:
370     if (bufReader.StatusCode() != CHIP_NO_ERROR)
371     {
372         err = bufReader.StatusCode();
373     }
374     return err;
375 }
376
377 size_t ReceiveAccept::MessageSize() const
378 {
379     BufferWriter emptyBuf(nullptr, 0);
380     return WriteToBuffer(emptyBuf).Needed();
381 }
382
383 bool ReceiveAccept::operator==(const ReceiveAccept & another) const
384 {
385     if (MetadataLength != another.MetadataLength)
386     {
387         return false;
388     }
389
390     bool metadataMatches = true;
391     if (MetadataLength > 0)
392     {
393         metadataMatches = (memcmp(Metadata, another.Metadata, MetadataLength) == 0);
394     }
395
396     return ((Version == another.Version) && (TransferCtlFlags == another.TransferCtlFlags) &&
397             (StartOffset == another.StartOffset) && (MaxBlockSize == another.MaxBlockSize) && (Length == another.Length) &&
398             metadataMatches);
399 }
400
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
404 {
405     return aBuffer.Put32(BlockCounter);
406 }
407
408 CHIP_ERROR CounterMessage::Parse(System::PacketBufferHandle aBuffer)
409 {
410     uint8_t * bufStart = aBuffer->Start();
411     Reader bufReader(bufStart, aBuffer->DataLength());
412     return bufReader.Read32(&BlockCounter).StatusCode();
413 }
414
415 size_t CounterMessage::MessageSize() const
416 {
417     BufferWriter emptyBuf(nullptr, 0);
418     return WriteToBuffer(emptyBuf).Needed();
419 }
420
421 bool CounterMessage::operator==(const CounterMessage & another) const
422 {
423     return (BlockCounter == another.BlockCounter);
424 }
425
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
429 {
430     aBuffer.Put32(BlockCounter);
431     if (Data != nullptr)
432     {
433         aBuffer.Put(Data, DataLength);
434     }
435     return aBuffer;
436 }
437
438 CHIP_ERROR DataBlock::Parse(System::PacketBufferHandle aBuffer)
439 {
440     CHIP_ERROR err     = CHIP_NO_ERROR;
441     uint8_t * bufStart = aBuffer->Start();
442     Reader bufReader(bufStart, aBuffer->DataLength());
443
444     SuccessOrExit(bufReader.Read32(&BlockCounter).StatusCode());
445
446     // Rest of message is data
447     Data       = nullptr;
448     DataLength = 0;
449     if (bufReader.Remaining() > 0)
450     {
451         Data       = &bufStart[bufReader.OctetsRead()];
452         DataLength = bufReader.Remaining();
453     }
454
455     // Retain ownership of the packet buffer so that the Data pointer remains valid.
456     Buffer = std::move(aBuffer);
457
458 exit:
459     if (bufReader.StatusCode() != CHIP_NO_ERROR)
460     {
461         err = bufReader.StatusCode();
462     }
463     return err;
464 }
465
466 size_t DataBlock::MessageSize() const
467 {
468     BufferWriter emptyBuf(nullptr, 0);
469     return WriteToBuffer(emptyBuf).Needed();
470 }
471
472 bool DataBlock::operator==(const DataBlock & another) const
473 {
474     if (DataLength != another.DataLength)
475     {
476         return false;
477     }
478
479     bool dataMatches = true;
480     if (DataLength > 0)
481     {
482         dataMatches = memcmp(Data, another.Data, DataLength) == 0;
483     }
484
485     return ((BlockCounter == another.BlockCounter) && dataMatches);
486 }