Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2016-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 :
19 : /**
20 : * @file
21 : * This file defines the member functions and private data for
22 : * the chip::System::PacketBuffer class, which provides the
23 : * mechanisms for manipulating packets of octet-serialized
24 : * data.
25 : */
26 :
27 : // Include module header
28 : #include <system/SystemPacketBuffer.h>
29 :
30 : // Include local headers
31 : #include <lib/support/CodeUtils.h>
32 : #include <lib/support/SafeInt.h>
33 : #include <lib/support/logging/CHIPLogging.h>
34 : #include <system/SystemFaultInjection.h>
35 : #include <system/SystemMutex.h>
36 : #include <system/SystemStats.h>
37 :
38 : #include <stdint.h>
39 :
40 : #include <limits.h>
41 : #include <limits>
42 : #include <stddef.h>
43 : #include <stdlib.h>
44 : #include <string.h>
45 : #include <utility>
46 :
47 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
48 : #include <lwip/mem.h>
49 : #include <lwip/pbuf.h>
50 : #if LWIP_VERSION_MAJOR == 2 && LWIP_VERSION_MINOR < 1
51 : #define PBUF_STRUCT_DATA_CONTIGUOUS(pbuf) (pbuf)->type == PBUF_RAM || (pbuf)->type == PBUF_POOL
52 : #else
53 : #define PBUF_STRUCT_DATA_CONTIGUOUS(pbuf) (pbuf)->type_internal & PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS
54 : #endif
55 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
56 :
57 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
58 : #include <lib/support/CHIPMem.h>
59 : #endif
60 :
61 : namespace chip {
62 : namespace System {
63 :
64 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
65 : //
66 : // Pool allocation for PacketBuffer objects.
67 : //
68 :
69 : PacketBuffer::BufferPoolElement PacketBuffer::sBufferPool[CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE];
70 :
71 : PacketBuffer * PacketBuffer::sFreeList = PacketBuffer::BuildFreeList();
72 :
73 : #if !CHIP_SYSTEM_CONFIG_NO_LOCKING
74 : static Mutex sBufferPoolMutex;
75 :
76 : #define LOCK_BUF_POOL() \
77 : do \
78 : { \
79 : sBufferPoolMutex.Lock(); \
80 : } while (0)
81 : #define UNLOCK_BUF_POOL() \
82 : do \
83 : { \
84 : sBufferPoolMutex.Unlock(); \
85 : } while (0)
86 : #endif // !CHIP_SYSTEM_CONFIG_NO_LOCKING
87 :
88 : PacketBuffer * PacketBuffer::BuildFreeList()
89 : {
90 : pbuf * lHead = nullptr;
91 :
92 : for (int i = 0; i < CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE; i++)
93 : {
94 : pbuf * lCursor = &sBufferPool[i].Header;
95 : lCursor->next = lHead;
96 : lCursor->ref = 0;
97 : lHead = lCursor;
98 : }
99 :
100 : #if !CHIP_SYSTEM_CONFIG_NO_LOCKING
101 : Mutex::Init(sBufferPoolMutex);
102 : #endif // !CHIP_SYSTEM_CONFIG_NO_LOCKING
103 :
104 : return static_cast<PacketBuffer *>(lHead);
105 : }
106 :
107 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
108 : //
109 : // Heap allocation for PacketBuffer objects.
110 : //
111 :
112 : #if CHIP_SYSTEM_PACKETBUFFER_HAS_CHECK
113 : void PacketBuffer::InternalCheck(const PacketBuffer * buffer)
114 : {
115 : if (buffer)
116 : {
117 : VerifyOrDieWithMsg(::chip::Platform::MemoryDebugCheckPointer(buffer, buffer->alloc_size + kStructureSize), chipSystemLayer,
118 : "invalid packet buffer pointer");
119 : VerifyOrDieWithMsg(buffer->alloc_size >= buffer->ReservedSize() + buffer->len, chipSystemLayer,
120 : "packet buffer overflow %" PRIu32 " < %" PRIu32 " +%" PRIu32, static_cast<uint32_t>(buffer->alloc_size),
121 : static_cast<uint32_t>(buffer->ReservedSize()), static_cast<uint32_t>(buffer->len));
122 : }
123 : }
124 : #endif // CHIP_SYSTEM_PACKETBUFFER_HAS_CHECK
125 :
126 : // Number of unused bytes below which \c RightSize() won't bother reallocating.
127 : constexpr uint16_t kRightSizingThreshold = 16;
128 :
129 7711 : void PacketBufferHandle::InternalRightSize()
130 : {
131 : // Require a single buffer with no other references.
132 7711 : if ((mBuffer == nullptr) || mBuffer->HasChainedBuffer() || (mBuffer->ref != 1))
133 : {
134 1 : return;
135 : }
136 :
137 : // Reallocate only if enough space will be saved.
138 7710 : const uint8_t * const start = mBuffer->ReserveStart();
139 7710 : const uint8_t * const payload = mBuffer->Start();
140 7710 : const size_t usedSize = static_cast<size_t>(payload - start + static_cast<ptrdiff_t>(mBuffer->len));
141 7710 : if (usedSize + kRightSizingThreshold > mBuffer->alloc_size)
142 : {
143 0 : return;
144 : }
145 :
146 7710 : const size_t blockSize = usedSize + PacketBuffer::kStructureSize;
147 7710 : PacketBuffer * newBuffer = reinterpret_cast<PacketBuffer *>(chip::Platform::MemoryAlloc(blockSize));
148 7710 : if (newBuffer == nullptr)
149 : {
150 0 : ChipLogError(chipSystemLayer, "PacketBuffer: pool EMPTY.");
151 0 : return;
152 : }
153 :
154 7710 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
155 :
156 7710 : uint8_t * const newStart = newBuffer->ReserveStart();
157 7710 : newBuffer->next = nullptr;
158 7710 : newBuffer->payload = newStart + (payload - start);
159 7710 : newBuffer->tot_len = mBuffer->tot_len;
160 7710 : newBuffer->len = mBuffer->len;
161 7710 : newBuffer->ref = 1;
162 7710 : newBuffer->alloc_size = usedSize;
163 7710 : memcpy(newStart, start, usedSize);
164 :
165 7710 : PacketBuffer::Free(mBuffer);
166 7710 : mBuffer = newBuffer;
167 : }
168 :
169 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_LWIP_CUSTOM_POOL
170 :
171 : void PacketBufferHandle::InternalRightSize()
172 : {
173 : PacketBuffer * lNewPacket = static_cast<PacketBuffer *>(pbuf_rightsize((struct pbuf *) mBuffer, -1));
174 : if (lNewPacket != mBuffer)
175 : {
176 : mBuffer = lNewPacket;
177 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
178 : ChipLogDetail(chipSystemLayer, "PacketBuffer: RightSize Copied");
179 : }
180 : }
181 :
182 : #endif
183 :
184 : #ifndef LOCK_BUF_POOL
185 : #define LOCK_BUF_POOL() \
186 : do \
187 : { \
188 : } while (0)
189 : #endif // !defined(LOCK_BUF_POOL)
190 :
191 : #ifndef UNLOCK_BUF_POOL
192 : #define UNLOCK_BUF_POOL() \
193 : do \
194 : { \
195 : } while (0)
196 : #endif // !defined(UNLOCK_BUF_POOL)
197 :
198 20092 : void PacketBuffer::SetStart(uint8_t * aNewStart)
199 : {
200 20092 : uint8_t * const kStart = ReserveStart();
201 20092 : uint8_t * const kEnd = this->Start() + this->MaxDataLength();
202 :
203 20092 : if (aNewStart < kStart)
204 9 : aNewStart = kStart;
205 20083 : else if (aNewStart > kEnd)
206 11 : aNewStart = kEnd;
207 :
208 20092 : ptrdiff_t lDelta = aNewStart - static_cast<uint8_t *>(this->payload);
209 20092 : if (lDelta > 0 && this->len < static_cast<size_t>(lDelta))
210 392 : lDelta = static_cast<ptrdiff_t>(this->len);
211 :
212 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
213 : VerifyOrDieWithMsg((static_cast<ptrdiff_t>(this->len) - lDelta) <= UINT16_MAX, chipSystemLayer,
214 : "LwIP buffer length cannot exceed UINT16_MAX");
215 : this->len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->len) - lDelta);
216 : VerifyOrDieWithMsg((static_cast<ptrdiff_t>(this->tot_len) - lDelta) <= UINT16_MAX, chipSystemLayer,
217 : "LwIP buffer length cannot exceed UINT16_MAX");
218 : this->tot_len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->tot_len) - lDelta);
219 : #else
220 20092 : this->len = static_cast<size_t>(static_cast<ptrdiff_t>(this->len) - lDelta);
221 20092 : this->tot_len = static_cast<size_t>(static_cast<ptrdiff_t>(this->tot_len) - lDelta);
222 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
223 20092 : this->payload = aNewStart;
224 20092 : }
225 :
226 59214 : void PacketBuffer::SetDataLength(size_t aNewLen, PacketBuffer * aChainHead)
227 : {
228 59214 : const size_t kMaxDataLen = this->MaxDataLength();
229 :
230 59214 : if (aNewLen > kMaxDataLen)
231 8113 : aNewLen = kMaxDataLen;
232 :
233 59214 : ssize_t lDelta = static_cast<ssize_t>(aNewLen) - static_cast<ssize_t>(this->len);
234 :
235 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
236 : VerifyOrDieWithMsg(aNewLen <= UINT16_MAX, chipSystemLayer, "LwIP buffer length cannot exceed UINT16_MAX");
237 : this->len = static_cast<uint16_t>(aNewLen);
238 : VerifyOrDieWithMsg((static_cast<ssize_t>(this->tot_len) + lDelta) <= UINT16_MAX, chipSystemLayer,
239 : "LwIP buffer length cannot exceed UINT16_MAX");
240 : this->tot_len = static_cast<uint16_t>(static_cast<ssize_t>(this->tot_len) + lDelta);
241 : #else
242 59214 : this->len = aNewLen;
243 59214 : this->tot_len = static_cast<size_t>(static_cast<ssize_t>(this->tot_len) + lDelta);
244 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
245 : // SetDataLength is often called after a client finished writing to the buffer,
246 : // so it's a good time to check for possible corruption.
247 59214 : Check(this);
248 :
249 67343 : while (aChainHead != nullptr && aChainHead != this)
250 : {
251 8129 : Check(aChainHead);
252 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
253 : VerifyOrDieWithMsg((static_cast<ssize_t>(aChainHead->tot_len) + lDelta) <= UINT16_MAX, chipSystemLayer,
254 : "LwIP buffer length cannot exceed UINT16_MAX");
255 : aChainHead->tot_len = static_cast<uint16_t>(static_cast<ssize_t>(aChainHead->tot_len) + lDelta);
256 : #else
257 8129 : aChainHead->tot_len = static_cast<size_t>(static_cast<ssize_t>(aChainHead->tot_len) + lDelta);
258 : #endif
259 8129 : aChainHead = aChainHead->ChainedBuffer();
260 : }
261 59214 : }
262 :
263 147252 : size_t PacketBuffer::MaxDataLength() const
264 : {
265 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
266 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)))
267 : {
268 : return DataLength();
269 : }
270 : #endif
271 147252 : return static_cast<size_t>(AllocSize() - ReservedSize());
272 : }
273 :
274 54803 : size_t PacketBuffer::AvailableDataLength() const
275 : {
276 54803 : return (this->MaxDataLength() - this->DataLength());
277 : }
278 :
279 176920 : uint16_t PacketBuffer::ReservedSize() const
280 : {
281 : // Cast to uint16_t is safe because Start() always points to "after"
282 : // ReserveStart(). At least when the payload is stored inline.
283 176920 : return static_cast<uint16_t>(Start() - ReserveStart());
284 : }
285 :
286 105326 : uint8_t * PacketBuffer::ReserveStart()
287 : {
288 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
289 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)))
290 : {
291 : return reinterpret_cast<uint8_t *>(this->Start());
292 : }
293 : #endif
294 105326 : return reinterpret_cast<uint8_t *>(this) + kStructureSize;
295 : }
296 :
297 176920 : const uint8_t * PacketBuffer::ReserveStart() const
298 : {
299 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
300 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)))
301 : {
302 : return reinterpret_cast<const uint8_t *>(this->Start());
303 : }
304 : #endif
305 176920 : return reinterpret_cast<const uint8_t *>(this) + kStructureSize;
306 : }
307 :
308 9149 : void PacketBuffer::AddToEnd(PacketBufferHandle && aPacketHandle)
309 : {
310 : // Ownership of aPacketHandle's buffer is transferred to the end of the chain.
311 9149 : PacketBuffer * aPacket = std::move(aPacketHandle).UnsafeRelease();
312 :
313 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
314 : pbuf_cat(this, aPacket);
315 : #else // !CHIP_SYSTEM_CONFIG_USE_LWIP
316 9149 : PacketBuffer * lCursor = this;
317 :
318 : while (true)
319 : {
320 11370 : size_t old_total_length = lCursor->tot_len;
321 11370 : lCursor->tot_len = lCursor->tot_len + aPacket->tot_len;
322 11370 : VerifyOrDieWithMsg(lCursor->tot_len >= old_total_length, chipSystemLayer, "buffer chain too large");
323 11370 : if (!lCursor->HasChainedBuffer())
324 : {
325 9149 : lCursor->next = aPacket;
326 9149 : break;
327 : }
328 :
329 2221 : lCursor = lCursor->ChainedBuffer();
330 2221 : }
331 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
332 9149 : }
333 :
334 1505 : void PacketBuffer::CompactHead()
335 : {
336 1505 : uint8_t * const kStart = ReserveStart();
337 :
338 1505 : if (this->payload != kStart)
339 : {
340 1315 : memmove(kStart, this->payload, this->len);
341 1315 : this->payload = kStart;
342 : }
343 :
344 1505 : size_t lAvailLength = this->AvailableDataLength();
345 :
346 2913 : while (lAvailLength > 0 && HasChainedBuffer())
347 : {
348 1408 : PacketBuffer & lNextPacket = *ChainedBuffer();
349 1408 : VerifyOrDieWithMsg(lNextPacket.ref == 1, chipSystemLayer, "next buffer %p is not exclusive to this chain", &lNextPacket);
350 :
351 1408 : size_t lMoveLength = lNextPacket.len;
352 1408 : if (lMoveLength > lAvailLength)
353 58 : lMoveLength = lAvailLength;
354 :
355 1408 : memcpy(static_cast<uint8_t *>(this->payload) + this->len, lNextPacket.payload, lMoveLength);
356 :
357 1408 : lNextPacket.payload = static_cast<uint8_t *>(lNextPacket.payload) + lMoveLength;
358 1408 : lAvailLength = lAvailLength - lMoveLength;
359 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
360 : VerifyOrDieWithMsg(CanCastTo<uint16_t>(this->len + lMoveLength), chipSystemLayer,
361 : "LwIP buffer length cannot exceed UINT16_MAX");
362 : this->len = static_cast<uint16_t>(this->len + lMoveLength);
363 : lNextPacket.len = static_cast<uint16_t>(lNextPacket.len - lMoveLength);
364 : lNextPacket.tot_len = static_cast<uint16_t>(lNextPacket.tot_len - lMoveLength);
365 : #else
366 1408 : this->len = this->len + lMoveLength;
367 1408 : lNextPacket.len = lNextPacket.len - lMoveLength;
368 1408 : lNextPacket.tot_len = lNextPacket.tot_len - lMoveLength;
369 : #endif
370 :
371 1408 : if (lNextPacket.len == 0)
372 1350 : this->next = this->FreeHead(&lNextPacket);
373 : }
374 1505 : }
375 :
376 21246 : void PacketBuffer::ConsumeHead(size_t aConsumeLength)
377 : {
378 21246 : if (aConsumeLength > this->len)
379 30 : aConsumeLength = this->len;
380 21246 : this->payload = static_cast<uint8_t *>(this->payload) + aConsumeLength;
381 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
382 : this->len = static_cast<uint16_t>(this->len - aConsumeLength);
383 : this->tot_len = static_cast<uint16_t>(this->tot_len - aConsumeLength);
384 : #else
385 21246 : this->len = this->len - aConsumeLength;
386 21246 : this->tot_len = this->tot_len - aConsumeLength;
387 : #endif
388 21246 : }
389 :
390 : /**
391 : * Consume data in a chain of buffers.
392 : *
393 : * Consume data in a chain of buffers starting with the current buffer and proceeding through the remaining buffers in the
394 : * chain. Each buffer that is completely consumed is freed and the function returns the first buffer (if any) containing the
395 : * remaining data. The current buffer must be the head of the buffer chain.
396 : *
397 : * @param[in] aConsumeLength - number of bytes to consume from the current chain.
398 : *
399 : * @return the first buffer from the current chain that contains any remaining data. If no data remains, nullptr is returned.
400 : */
401 6495 : PacketBuffer * PacketBuffer::Consume(size_t aConsumeLength)
402 : {
403 6495 : PacketBuffer * lPacket = this;
404 :
405 14253 : while (lPacket != nullptr && aConsumeLength > 0)
406 : {
407 9469 : const size_t kLength = lPacket->DataLength();
408 :
409 9469 : if (aConsumeLength >= kLength)
410 : {
411 7758 : lPacket = PacketBuffer::FreeHead(lPacket);
412 7758 : aConsumeLength = aConsumeLength - kLength;
413 : }
414 : else
415 : {
416 1711 : lPacket->ConsumeHead(aConsumeLength);
417 1711 : break;
418 : }
419 : }
420 :
421 6495 : return lPacket;
422 : }
423 :
424 147 : CHIP_ERROR PacketBuffer::Read(uint8_t * aDestination, size_t aReadLength) const
425 : {
426 147 : const PacketBuffer * lPacket = this;
427 :
428 147 : if (aReadLength > TotalLength())
429 : {
430 30 : return CHIP_ERROR_BUFFER_TOO_SMALL;
431 : }
432 306 : while (aReadLength > 0)
433 : {
434 239 : if (lPacket == nullptr)
435 : {
436 : // TotalLength() or an individual buffer's DataLength() must have been wrong.
437 50 : return CHIP_ERROR_INTERNAL;
438 : }
439 189 : size_t lToReadFromCurrentBuf = lPacket->DataLength();
440 189 : if (aReadLength < lToReadFromCurrentBuf)
441 : {
442 33 : lToReadFromCurrentBuf = aReadLength;
443 : }
444 189 : memcpy(aDestination, lPacket->Start(), lToReadFromCurrentBuf);
445 189 : aDestination += lToReadFromCurrentBuf;
446 189 : aReadLength -= lToReadFromCurrentBuf;
447 189 : lPacket = lPacket->ChainedBuffer();
448 : }
449 67 : return CHIP_NO_ERROR;
450 : }
451 :
452 19727 : bool PacketBuffer::EnsureReservedSize(uint16_t aReservedSize)
453 : {
454 19727 : const uint16_t kCurrentReservedSize = this->ReservedSize();
455 19727 : if (aReservedSize <= kCurrentReservedSize)
456 19688 : return true;
457 :
458 39 : if ((aReservedSize + this->len) > this->AllocSize())
459 26 : return false;
460 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
461 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)) && aReservedSize > 0)
462 : {
463 : return false;
464 : }
465 : #endif
466 : // Cast is safe because aReservedSize > kCurrentReservedSize.
467 13 : const uint16_t kMoveLength = static_cast<uint16_t>(aReservedSize - kCurrentReservedSize);
468 13 : memmove(static_cast<uint8_t *>(this->payload) + kMoveLength, this->payload, this->len);
469 13 : payload = static_cast<uint8_t *>(this->payload) + kMoveLength;
470 :
471 13 : return true;
472 : }
473 :
474 36 : bool PacketBuffer::AlignPayload(uint16_t aAlignBytes)
475 : {
476 36 : if (aAlignBytes == 0)
477 6 : return false;
478 :
479 30 : const uint16_t kPayloadOffset = static_cast<uint16_t>(reinterpret_cast<uintptr_t>(this->payload) % aAlignBytes);
480 :
481 30 : if (kPayloadOffset == 0)
482 7 : return true;
483 :
484 : // Cast is safe because by construction kPayloadOffset < aAlignBytes.
485 23 : const uint16_t kPayloadShift = static_cast<uint16_t>(aAlignBytes - kPayloadOffset);
486 :
487 23 : if (!CanCastTo<uint16_t>(this->ReservedSize() + kPayloadShift))
488 : {
489 0 : return false;
490 : }
491 :
492 23 : return (this->EnsureReservedSize(static_cast<uint16_t>(this->ReservedSize() + kPayloadShift)));
493 : }
494 :
495 : /**
496 : * Increment the reference count of the current buffer.
497 : */
498 49194 : void PacketBuffer::AddRef()
499 : {
500 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
501 : pbuf_ref(this);
502 : #else // !CHIP_SYSTEM_CONFIG_USE_LWIP
503 : LOCK_BUF_POOL();
504 49194 : VerifyOrDieWithMsg(this->ref < std::numeric_limits<decltype(this->ref)>::max(), chipSystemLayer,
505 : "packet buffer refcount overflow");
506 49194 : ++this->ref;
507 : UNLOCK_BUF_POOL();
508 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
509 49194 : }
510 :
511 48533 : PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aReservedSize)
512 : {
513 : // Sanity check for kStructureSize to ensure that it matches the PacketBuffer size.
514 : static_assert(PacketBuffer::kStructureSize == sizeof(PacketBuffer), "PacketBuffer size mismatch");
515 : // Setting a static upper bound on kStructureSize to ensure the summation of all the sizes does not overflow.
516 : static_assert(PacketBuffer::kStructureSize <= UINT16_MAX, "kStructureSize should not exceed UINT16_MAX.");
517 : // Setting a static upper bound on the maximum buffer size allocation for regular sized messages (not large).
518 : static_assert(PacketBuffer::kMaxSizeWithoutReserve <= UINT16_MAX, "kMaxSizeWithoutReserve should not exceed UINT16_MAX.");
519 :
520 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
521 : // Setting a static upper bound on the maximum buffer size allocation for
522 : // large messages.
523 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
524 : // LwIP based systems are internally limited to using a u16_t type as the size of a buffer.
525 : static_assert(PacketBuffer::kLargeBufMaxSizeWithoutReserve <= UINT16_MAX,
526 : "In LwIP, max size for Large payload buffers cannot exceed UINT16_MAX!");
527 : #else
528 : // Messages over TCP are framed using a length field that is 32 bits in
529 : // length.
530 : static_assert(PacketBuffer::kLargeBufMaxSizeWithoutReserve <= UINT32_MAX,
531 : "Max size for Large payload buffers cannot exceed UINT32_MAX");
532 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
533 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
534 :
535 : // Ensure that aAvailableSize is bound within a max and is not big enough to cause overflow during
536 : // subsequent addition of all the sizes.
537 48533 : if (aAvailableSize > UINT32_MAX)
538 : {
539 0 : ChipLogError(chipSystemLayer,
540 : "PacketBuffer: AvailableSize of a buffer cannot exceed UINT32_MAX. aAvailableSize = 0x" ChipLogFormatX64,
541 : ChipLogValueX64(static_cast<uint64_t>(aAvailableSize)));
542 0 : return PacketBufferHandle();
543 : }
544 :
545 : // Cast all to uint64_t and add. This cannot overflow because we have
546 : // ensured that the maximal value of the summation is
547 : // UINT32_MAX + UINT16_MAX + UINT16_MAX, which should always fit in
548 : // a uint64_t variable.
549 48533 : uint64_t sumOfSizes = static_cast<uint64_t>(aAvailableSize) + static_cast<uint64_t>(aReservedSize) +
550 : static_cast<uint64_t>(PacketBuffer::kStructureSize);
551 48533 : uint64_t sumOfAvailAndReserved = static_cast<uint64_t>(aAvailableSize) + static_cast<uint64_t>(aReservedSize);
552 :
553 : // Ensure that the sum fits in a size_t so that casting into size_t variables,
554 : // viz., lBlockSize and lAllocSize, is safe.
555 48533 : if (!CanCastTo<size_t>(sumOfSizes))
556 : {
557 0 : ChipLogError(chipSystemLayer,
558 : "PacketBuffer: Sizes of allocation request are invalid. (aAvailableSize = " ChipLogFormatX64
559 : ", aReservedSize = " ChipLogFormatX64 ")",
560 : ChipLogValueX64(static_cast<uint64_t>(aAvailableSize)), ChipLogValueX64(static_cast<uint64_t>(aReservedSize)));
561 0 : return PacketBufferHandle();
562 : }
563 :
564 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
565 : // LwIP based APIs have a maximum buffer size of UINT16_MAX. Ensure that
566 : // limit is met during allocation.
567 : if (sumOfAvailAndReserved > UINT16_MAX)
568 : {
569 : ChipLogError(chipSystemLayer,
570 : "LwIP based systems require total buffer size to be less than UINT16_MAX!"
571 : "Attempted allocation size = " ChipLogFormatX64,
572 : ChipLogValueX64(sumOfAvailAndReserved));
573 : return PacketBufferHandle();
574 : }
575 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
576 :
577 : // sumOfAvailAndReserved is no larger than sumOfSizes, which we checked can be cast to
578 : // size_t.
579 48533 : const size_t lAllocSize = static_cast<size_t>(sumOfAvailAndReserved);
580 : PacketBuffer * lPacket;
581 :
582 48533 : CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_PacketBufferNew, return PacketBufferHandle());
583 :
584 48533 : if (lAllocSize > PacketBuffer::kMaxAllocSize)
585 : {
586 0 : ChipLogError(chipSystemLayer, "PacketBuffer: allocation exceeding buffer capacity limits: %lu > %lu",
587 : static_cast<unsigned long>(lAllocSize), static_cast<unsigned long>(PacketBuffer::kMaxAllocSize));
588 0 : return PacketBufferHandle();
589 : }
590 :
591 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
592 : // This cast is safe because lAllocSize is no larger than
593 : // kMaxSizeWithoutReserve, which fits in uint16_t.
594 : lPacket = static_cast<PacketBuffer *>(
595 : pbuf_alloc(PBUF_RAW, static_cast<uint16_t>(lAllocSize), CHIP_SYSTEM_PACKETBUFFER_LWIP_PBUF_TYPE));
596 :
597 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
598 :
599 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
600 :
601 : #if !CHIP_SYSTEM_CONFIG_NO_LOCKING && CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING
602 : if (!sBufferPoolMutex.isInitialized())
603 : {
604 : Mutex::Init(sBufferPoolMutex);
605 : }
606 : #endif
607 : LOCK_BUF_POOL();
608 :
609 : lPacket = PacketBuffer::sFreeList;
610 : if (lPacket != nullptr)
611 : {
612 : PacketBuffer::sFreeList = lPacket->ChainedBuffer();
613 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
614 : }
615 :
616 : UNLOCK_BUF_POOL();
617 :
618 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
619 : // sumOfSizes is essentially (kStructureSize + lAllocSize) which we already
620 : // checked to fit in a size_t.
621 48533 : const size_t lBlockSize = static_cast<size_t>(sumOfSizes);
622 48533 : lPacket = reinterpret_cast<PacketBuffer *>(chip::Platform::MemoryAlloc(lBlockSize));
623 :
624 : #else
625 : #error "Unimplemented PacketBuffer storage case"
626 : #endif
627 :
628 48533 : if (lPacket == nullptr)
629 : {
630 0 : ChipLogError(chipSystemLayer, "PacketBuffer: pool EMPTY.");
631 0 : return PacketBufferHandle();
632 : }
633 :
634 48533 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
635 :
636 48533 : lPacket->payload = lPacket->ReserveStart() + aReservedSize;
637 48533 : lPacket->len = lPacket->tot_len = 0;
638 48533 : lPacket->next = nullptr;
639 48533 : lPacket->ref = 1;
640 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
641 48533 : lPacket->alloc_size = lAllocSize;
642 : #endif
643 :
644 48533 : return PacketBufferHandle(lPacket);
645 : }
646 :
647 218 : PacketBufferHandle PacketBufferHandle::NewWithData(const void * aData, size_t aDataSize, size_t aAdditionalSize,
648 : uint16_t aReservedSize)
649 : {
650 : // Since `aDataSize` fits in uint16_t, the sum `aDataSize + aAdditionalSize` will not overflow.
651 : // `New()` will only return a non-null buffer if the total allocation size does not overflow.
652 218 : PacketBufferHandle buffer = New(aDataSize + aAdditionalSize, aReservedSize);
653 218 : if (buffer.mBuffer != nullptr)
654 : {
655 218 : memcpy(buffer.mBuffer->payload, aData, aDataSize);
656 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
657 : // Checks in the New() call catch buffer allocations greater
658 : // than UINT16_MAX for LwIP based platforms.
659 : buffer.mBuffer->len = buffer.mBuffer->tot_len = static_cast<uint16_t>(aDataSize);
660 : #else
661 218 : buffer.mBuffer->len = buffer.mBuffer->tot_len = aDataSize;
662 : #endif
663 : }
664 218 : return buffer;
665 : }
666 :
667 : /**
668 : * Free all packet buffers in a chain.
669 : *
670 : * Decrement the reference count to all the buffers in the current chain. If the reference count reaches 0, the respective buffers
671 : * are freed or returned to allocation pools as appropriate. As a rule, users should treat this method as an equivalent of
672 : * `free()` function and not use the argument after the call.
673 : *
674 : * @param[in] aPacket - packet buffer to be freed.
675 : */
676 102431 : void PacketBuffer::Free(PacketBuffer * aPacket)
677 : {
678 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
679 :
680 : if (aPacket != nullptr)
681 : {
682 : pbuf_free(aPacket);
683 :
684 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
685 : }
686 :
687 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP || CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
688 :
689 : LOCK_BUF_POOL();
690 :
691 207952 : while (aPacket != nullptr)
692 : {
693 105521 : PacketBuffer * lNextPacket = aPacket->ChainedBuffer();
694 :
695 105521 : VerifyOrDieWithMsg(aPacket->ref > 0, chipSystemLayer, "SystemPacketBuffer::Free: aPacket->ref = 0");
696 :
697 105521 : aPacket->ref--;
698 105521 : if (aPacket->ref == 0)
699 : {
700 56243 : SYSTEM_STATS_DECREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
701 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
702 56243 : ::chip::Platform::MemoryDebugCheckPointer(aPacket, aPacket->alloc_size + kStructureSize);
703 : #endif
704 56243 : aPacket->Clear();
705 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
706 : aPacket->next = sFreeList;
707 : sFreeList = aPacket;
708 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
709 56243 : chip::Platform::MemoryFree(aPacket);
710 : #endif
711 56243 : aPacket = lNextPacket;
712 : }
713 : else
714 : {
715 49278 : aPacket = nullptr;
716 : }
717 : }
718 :
719 : UNLOCK_BUF_POOL();
720 :
721 : #else
722 : #error "Unimplemented PacketBuffer storage case"
723 : #endif
724 102431 : }
725 :
726 : /**
727 : * Clear content of the packet buffer.
728 : *
729 : * This method is called by Free(), before the buffer is released to the free buffer pool.
730 : */
731 56243 : void PacketBuffer::Clear()
732 : {
733 56243 : tot_len = 0;
734 56243 : len = 0;
735 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
736 56243 : alloc_size = 0;
737 : #endif
738 56243 : }
739 :
740 : /**
741 : * Free the first buffer in a chain, returning a pointer to the remaining buffers.
742 : `*
743 : * @note When the buffer chain is referenced by multiple callers, `FreeHead()` will detach the head, but will not forcibly
744 : * deallocate the head buffer.
745 : *
746 : * @param[in] aPacket - buffer chain.
747 : *
748 : * @return packet buffer chain consisting of the tail of the input buffer (may be \c nullptr).
749 : */
750 9175 : PacketBuffer * PacketBuffer::FreeHead(PacketBuffer * aPacket)
751 : {
752 9175 : PacketBuffer * lNextPacket = aPacket->ChainedBuffer();
753 9175 : aPacket->next = nullptr;
754 9175 : PacketBuffer::Free(aPacket);
755 9175 : return lNextPacket;
756 : }
757 :
758 1812 : PacketBufferHandle PacketBufferHandle::PopHead()
759 : {
760 1812 : PacketBuffer * head = mBuffer;
761 :
762 : // This takes ownership from the `next` link.
763 1812 : mBuffer = mBuffer->ChainedBuffer();
764 :
765 1812 : head->next = nullptr;
766 1812 : head->tot_len = head->len;
767 :
768 : // The returned handle takes ownership from this.
769 1812 : return PacketBufferHandle(head);
770 : }
771 :
772 9859 : PacketBufferHandle PacketBufferHandle::CloneData() const
773 : {
774 9859 : PacketBufferHandle cloneHead;
775 :
776 19747 : for (PacketBuffer * original = mBuffer; original != nullptr; original = original->ChainedBuffer())
777 : {
778 9889 : size_t originalDataSize = original->MaxDataLength();
779 9889 : uint16_t originalReservedSize = original->ReservedSize();
780 :
781 9889 : if (originalDataSize + originalReservedSize > PacketBuffer::kMaxAllocSize)
782 : {
783 : // The original memory allocation may have provided a larger block than requested (e.g. when using a shared pool),
784 : // and in particular may have provided a larger block than we are able to request from PackBufferHandle::New().
785 : // It is a genuine error if that extra space has been used.
786 2 : if (originalReservedSize + original->DataLength() > PacketBuffer::kMaxAllocSize)
787 : {
788 1 : return PacketBufferHandle();
789 : }
790 : // Otherwise, reduce the requested data size. This subtraction can not underflow because the above test
791 : // guarantees originalReservedSize <= PacketBuffer::kMaxAllocSize.
792 1 : originalDataSize = PacketBuffer::kMaxAllocSize - originalReservedSize;
793 : }
794 :
795 9888 : PacketBufferHandle clone = PacketBufferHandle::New(originalDataSize, originalReservedSize);
796 9888 : if (clone.IsNull())
797 : {
798 0 : return PacketBufferHandle();
799 : }
800 9888 : clone.mBuffer->tot_len = clone.mBuffer->len = original->len;
801 9888 : memcpy(clone->ReserveStart(), original->ReserveStart(), originalDataSize + originalReservedSize);
802 :
803 9888 : if (cloneHead.IsNull())
804 : {
805 9858 : cloneHead = std::move(clone);
806 : }
807 : else
808 : {
809 30 : cloneHead->AddToEnd(std::move(clone));
810 : }
811 9888 : }
812 :
813 9858 : return cloneHead;
814 9859 : }
815 :
816 : } // namespace System
817 :
818 : namespace Encoding {
819 :
820 73 : System::PacketBufferHandle PacketBufferWriterUtil::Finalize(BufferWriter & aBufferWriter, System::PacketBufferHandle & aPacket)
821 : {
822 73 : if (!aPacket.IsNull() && aBufferWriter.Fit())
823 : {
824 : // Since mPacket was successfully allocated to hold the maximum length,
825 : // we know that the actual length fits in a uint16_t.
826 72 : aPacket->SetDataLength(aBufferWriter.Needed());
827 : }
828 : else
829 : {
830 1 : aPacket = nullptr;
831 : }
832 73 : aBufferWriter = Encoding::BufferWriter(nullptr, 0);
833 73 : return std::move(aPacket);
834 : }
835 :
836 : } // namespace Encoding
837 : } // namespace chip
|