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 : SuccessOrDie(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 8056 : void PacketBufferHandle::InternalRightSize()
130 : {
131 : // Require a single buffer with no other references.
132 8056 : if ((mBuffer == nullptr) || mBuffer->HasChainedBuffer() || (mBuffer->ref != 1))
133 : {
134 1 : return;
135 : }
136 :
137 : // Reallocate only if enough space will be saved.
138 8055 : const uint8_t * const start = mBuffer->ReserveStart();
139 8055 : const uint8_t * const payload = mBuffer->Start();
140 8055 : const size_t usedSize = static_cast<size_t>(payload - start + static_cast<ptrdiff_t>(mBuffer->len));
141 8055 : if (usedSize + kRightSizingThreshold > mBuffer->alloc_size)
142 : {
143 0 : return;
144 : }
145 :
146 8055 : const size_t blockSize = usedSize + PacketBuffer::kStructureSize;
147 8055 : PacketBuffer * newBuffer = reinterpret_cast<PacketBuffer *>(chip::Platform::MemoryAlloc(blockSize));
148 8055 : if (newBuffer == nullptr)
149 : {
150 0 : ChipLogError(chipSystemLayer, "PacketBuffer: pool EMPTY.");
151 0 : return;
152 : }
153 :
154 8055 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
155 :
156 8055 : uint8_t * const newStart = newBuffer->ReserveStart();
157 8055 : newBuffer->next = nullptr;
158 8055 : newBuffer->payload = newStart + (payload - start);
159 8055 : newBuffer->tot_len = mBuffer->tot_len;
160 8055 : newBuffer->len = mBuffer->len;
161 8055 : newBuffer->ref = 1;
162 8055 : newBuffer->alloc_size = usedSize;
163 8055 : memcpy(newStart, start, usedSize);
164 :
165 8055 : PacketBuffer::Free(mBuffer);
166 8055 : 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 30933 : void PacketBuffer::SetStart(uint8_t * aNewStart)
199 : {
200 30933 : uint8_t * const kStart = ReserveStart();
201 30933 : uint8_t * const kEnd = this->Start() + this->MaxDataLength();
202 :
203 30933 : if (aNewStart < kStart)
204 9 : aNewStart = kStart;
205 30924 : else if (aNewStart > kEnd)
206 11 : aNewStart = kEnd;
207 :
208 30933 : ptrdiff_t lDelta = aNewStart - static_cast<uint8_t *>(this->payload);
209 30933 : 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 30933 : this->len = static_cast<size_t>(static_cast<ptrdiff_t>(this->len) - lDelta);
221 30933 : this->tot_len = static_cast<size_t>(static_cast<ptrdiff_t>(this->tot_len) - lDelta);
222 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
223 30933 : this->payload = aNewStart;
224 30933 : }
225 :
226 77157 : void PacketBuffer::SetDataLength(size_t aNewLen, PacketBuffer * aChainHead)
227 : {
228 77157 : const size_t kMaxDataLen = this->MaxDataLength();
229 :
230 77157 : if (aNewLen > kMaxDataLen)
231 8113 : aNewLen = kMaxDataLen;
232 :
233 77157 : 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 77157 : this->len = aNewLen;
243 77157 : 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 77157 : Check(this);
248 :
249 85286 : 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 77157 : }
262 :
263 199752 : 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 199752 : return static_cast<size_t>(AllocSize() - ReservedSize());
272 : }
273 :
274 73070 : size_t PacketBuffer::AvailableDataLength() const
275 : {
276 73070 : return (this->MaxDataLength() - this->DataLength());
277 : }
278 :
279 245289 : 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 245289 : return static_cast<uint16_t>(Start() - ReserveStart());
284 : }
285 :
286 138831 : 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 138831 : return reinterpret_cast<uint8_t *>(this) + kStructureSize;
295 : }
296 :
297 245289 : 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 245289 : return reinterpret_cast<const uint8_t *>(this) + kStructureSize;
306 : }
307 :
308 10859 : void PacketBuffer::AddToEnd(PacketBufferHandle && aPacketHandle)
309 : {
310 : // Ownership of aPacketHandle's buffer is transferred to the end of the chain.
311 10859 : 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 10859 : PacketBuffer * lCursor = this;
317 :
318 : while (true)
319 : {
320 15836 : size_t old_total_length = lCursor->tot_len;
321 15836 : lCursor->tot_len = lCursor->tot_len + aPacket->tot_len;
322 15836 : VerifyOrDieWithMsg(lCursor->tot_len >= old_total_length, chipSystemLayer, "buffer chain too large");
323 15836 : if (!lCursor->HasChainedBuffer())
324 : {
325 10859 : lCursor->next = aPacket;
326 10859 : break;
327 : }
328 :
329 4977 : lCursor = lCursor->ChainedBuffer();
330 4977 : }
331 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
332 10859 : }
333 :
334 1515 : void PacketBuffer::CompactHead()
335 : {
336 1515 : uint8_t * const kStart = ReserveStart();
337 :
338 1515 : if (this->payload != kStart)
339 : {
340 1323 : memmove(kStart, this->payload, this->len);
341 1323 : this->payload = kStart;
342 : }
343 :
344 1515 : size_t lAvailLength = this->AvailableDataLength();
345 :
346 2933 : while (lAvailLength > 0 && HasChainedBuffer())
347 : {
348 1418 : PacketBuffer & lNextPacket = *ChainedBuffer();
349 1418 : VerifyOrDieWithMsg(lNextPacket.ref == 1, chipSystemLayer, "next buffer %p is not exclusive to this chain", &lNextPacket);
350 :
351 1418 : size_t lMoveLength = lNextPacket.len;
352 1418 : if (lMoveLength > lAvailLength)
353 58 : lMoveLength = lAvailLength;
354 :
355 1418 : memcpy(static_cast<uint8_t *>(this->payload) + this->len, lNextPacket.payload, lMoveLength);
356 :
357 1418 : lNextPacket.payload = static_cast<uint8_t *>(lNextPacket.payload) + lMoveLength;
358 1418 : 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 1418 : this->len = this->len + lMoveLength;
367 1418 : lNextPacket.len = lNextPacket.len - lMoveLength;
368 1418 : lNextPacket.tot_len = lNextPacket.tot_len - lMoveLength;
369 : #endif
370 :
371 1418 : if (lNextPacket.len == 0)
372 1360 : this->next = this->FreeHead(&lNextPacket);
373 : }
374 1515 : }
375 :
376 31835 : void PacketBuffer::ConsumeHead(size_t aConsumeLength)
377 : {
378 31835 : if (aConsumeLength > this->len)
379 30 : aConsumeLength = this->len;
380 31835 : 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 31835 : this->len = this->len - aConsumeLength;
386 31835 : this->tot_len = this->tot_len - aConsumeLength;
387 : #endif
388 31835 : }
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 6508 : PacketBuffer * PacketBuffer::Consume(size_t aConsumeLength)
402 : {
403 6508 : PacketBuffer * lPacket = this;
404 :
405 14267 : while (lPacket != nullptr && aConsumeLength > 0)
406 : {
407 9482 : const size_t kLength = lPacket->DataLength();
408 :
409 9482 : if (aConsumeLength >= kLength)
410 : {
411 7759 : lPacket = PacketBuffer::FreeHead(lPacket);
412 7759 : aConsumeLength = aConsumeLength - kLength;
413 : }
414 : else
415 : {
416 1723 : lPacket->ConsumeHead(aConsumeLength);
417 1723 : break;
418 : }
419 : }
420 :
421 6508 : return lPacket;
422 : }
423 :
424 160 : CHIP_ERROR PacketBuffer::Read(uint8_t * aDestination, size_t aReadLength) const
425 : {
426 160 : const PacketBuffer * lPacket = this;
427 :
428 160 : if (aReadLength > TotalLength())
429 : {
430 30 : return CHIP_ERROR_BUFFER_TOO_SMALL;
431 : }
432 332 : while (aReadLength > 0)
433 : {
434 252 : if (lPacket == nullptr)
435 : {
436 : // TotalLength() or an individual buffer's DataLength() must have been wrong.
437 50 : return CHIP_ERROR_INTERNAL;
438 : }
439 202 : size_t lToReadFromCurrentBuf = lPacket->DataLength();
440 202 : if (aReadLength < lToReadFromCurrentBuf)
441 : {
442 45 : lToReadFromCurrentBuf = aReadLength;
443 : }
444 202 : memcpy(aDestination, lPacket->Start(), lToReadFromCurrentBuf);
445 202 : aDestination += lToReadFromCurrentBuf;
446 202 : aReadLength -= lToReadFromCurrentBuf;
447 202 : lPacket = lPacket->ChainedBuffer();
448 : }
449 80 : return CHIP_NO_ERROR;
450 : }
451 :
452 30312 : bool PacketBuffer::EnsureReservedSize(uint16_t aReservedSize)
453 : {
454 30312 : const uint16_t kCurrentReservedSize = this->ReservedSize();
455 30312 : if (aReservedSize <= kCurrentReservedSize)
456 30272 : return true;
457 :
458 40 : if ((aReservedSize + this->len) > this->AllocSize())
459 27 : 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 8 : return true;
483 :
484 : // Cast is safe because by construction kPayloadOffset < aAlignBytes.
485 22 : const uint16_t kPayloadShift = static_cast<uint16_t>(aAlignBytes - kPayloadOffset);
486 :
487 22 : if (!CanCastTo<uint16_t>(this->ReservedSize() + kPayloadShift))
488 : {
489 0 : return false;
490 : }
491 :
492 22 : return (this->EnsureReservedSize(static_cast<uint16_t>(this->ReservedSize() + kPayloadShift)));
493 : }
494 :
495 : /**
496 : * Increment the reference count of the current buffer.
497 : */
498 59772 : 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 59772 : VerifyOrDieWithMsg(this->ref < std::numeric_limits<decltype(this->ref)>::max(), chipSystemLayer,
505 : "packet buffer refcount overflow");
506 59772 : ++this->ref;
507 : UNLOCK_BUF_POOL();
508 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
509 59772 : }
510 :
511 59925 : 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 59925 : 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 59925 : uint64_t sumOfSizes = static_cast<uint64_t>(aAvailableSize) + static_cast<uint64_t>(aReservedSize) +
550 : static_cast<uint64_t>(PacketBuffer::kStructureSize);
551 59925 : 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 59925 : 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 59925 : const size_t lAllocSize = static_cast<size_t>(sumOfAvailAndReserved);
580 : PacketBuffer * lPacket;
581 :
582 59925 : CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_PacketBufferNew, return PacketBufferHandle());
583 :
584 59925 : 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 : #if CHIP_SYSTEM_CONFIG_PACKETBUFFER_LWIP_PBUF_RAM
593 : // Allocate buffer using kMaxAllocSize instead of the requested size (lAllocSize).
594 : //
595 : // Rationale:
596 : // 1. PBUF_RAM provides a contiguous payload buffer, ensuring consistent behavior
597 : // with PBUF_POOL (non-chained) operations regardless of actual data size.
598 : // 2. The standard lwIP pbuf structure lacks a field to store the actual allocated
599 : // size. By always allocating kMaxAllocSize, AllocSize() can return a constant
600 : // value (kMaxAllocSize) without needing to track the original allocation size.
601 : //
602 : // kMaxAllocSize configuration:
603 : // - TCP: Configurable via CHIP_SYSTEM_CONFIG_MAX_LARGE_BUFFER_SIZE_BYTES to support
604 : // larger packets exceeding IPv6 MTU. Note: This may result in unused buffer
605 : // space; configure based on the maximum packet size requirements.
606 : // - UDP: Fixed to LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
607 : //
608 : // Despite allocating kMaxAllocSize, we still keep the validation for lAllocSize
609 : // to fail early if the requested size exceeds the maximum capacity.
610 : //
611 : // This cast is safe because kLargeBufMaxSizeWithoutReserve has been statically
612 : // asserted to fit in uint16_t.
613 : lPacket = static_cast<PacketBuffer *>(
614 : pbuf_alloc(PBUF_RAW, static_cast<uint16_t>(PacketBuffer::kMaxAllocSize), CHIP_SYSTEM_PACKETBUFFER_LWIP_PBUF_TYPE));
615 : #else
616 : // This cast is safe because lAllocSize is no larger than
617 : // kMaxSizeWithoutReserve, which fits in uint16_t.
618 : lPacket = static_cast<PacketBuffer *>(
619 : pbuf_alloc(PBUF_RAW, static_cast<uint16_t>(lAllocSize), CHIP_SYSTEM_PACKETBUFFER_LWIP_PBUF_TYPE));
620 : #endif
621 :
622 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
623 :
624 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
625 :
626 : #if !CHIP_SYSTEM_CONFIG_NO_LOCKING && CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING
627 : if (!sBufferPoolMutex.isInitialized())
628 : {
629 : SuccessOrDie(Mutex::Init(sBufferPoolMutex));
630 : }
631 : #endif
632 : LOCK_BUF_POOL();
633 :
634 : lPacket = PacketBuffer::sFreeList;
635 : if (lPacket != nullptr)
636 : {
637 : PacketBuffer::sFreeList = lPacket->ChainedBuffer();
638 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
639 : }
640 :
641 : UNLOCK_BUF_POOL();
642 :
643 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
644 : // sumOfSizes is essentially (kStructureSize + lAllocSize) which we already
645 : // checked to fit in a size_t.
646 59925 : const size_t lBlockSize = static_cast<size_t>(sumOfSizes);
647 59925 : lPacket = reinterpret_cast<PacketBuffer *>(chip::Platform::MemoryAlloc(lBlockSize));
648 :
649 : #else
650 : #error "Unimplemented PacketBuffer storage case"
651 : #endif
652 :
653 59925 : if (lPacket == nullptr)
654 : {
655 0 : ChipLogError(chipSystemLayer, "PacketBuffer: pool EMPTY.");
656 0 : return PacketBufferHandle();
657 : }
658 :
659 59925 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
660 :
661 59925 : lPacket->payload = lPacket->ReserveStart() + aReservedSize;
662 59925 : lPacket->len = lPacket->tot_len = 0;
663 59925 : lPacket->next = nullptr;
664 59925 : lPacket->ref = 1;
665 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
666 59925 : lPacket->alloc_size = lAllocSize;
667 : #endif
668 :
669 59925 : return PacketBufferHandle(lPacket);
670 : }
671 :
672 285 : PacketBufferHandle PacketBufferHandle::NewWithData(const void * aData, size_t aDataSize, size_t aAdditionalSize,
673 : uint16_t aReservedSize)
674 : {
675 : // Since `aDataSize` fits in uint16_t, the sum `aDataSize + aAdditionalSize` will not overflow.
676 : // `New()` will only return a non-null buffer if the total allocation size does not overflow.
677 285 : PacketBufferHandle buffer = New(aDataSize + aAdditionalSize, aReservedSize);
678 285 : if (buffer.mBuffer != nullptr)
679 : {
680 285 : memcpy(buffer.mBuffer->payload, aData, aDataSize);
681 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
682 : // Checks in the New() call catch buffer allocations greater
683 : // than UINT16_MAX for LwIP based platforms.
684 : buffer.mBuffer->len = buffer.mBuffer->tot_len = static_cast<uint16_t>(aDataSize);
685 : #else
686 285 : buffer.mBuffer->len = buffer.mBuffer->tot_len = aDataSize;
687 : #endif
688 : }
689 285 : return buffer;
690 : }
691 :
692 : /**
693 : * Free all packet buffers in a chain.
694 : *
695 : * Decrement the reference count to all the buffers in the current chain. If the reference count reaches 0, the respective buffers
696 : * are freed or returned to allocation pools as appropriate. As a rule, users should treat this method as an equivalent of
697 : * `free()` function and not use the argument after the call.
698 : *
699 : * @param[in] aPacket - packet buffer to be freed.
700 : */
701 124662 : void PacketBuffer::Free(PacketBuffer * aPacket)
702 : {
703 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
704 :
705 : if (aPacket != nullptr)
706 : {
707 : pbuf_free(aPacket);
708 :
709 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
710 : }
711 :
712 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP || CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
713 :
714 : LOCK_BUF_POOL();
715 :
716 252498 : while (aPacket != nullptr)
717 : {
718 127836 : PacketBuffer * lNextPacket = aPacket->ChainedBuffer();
719 :
720 127836 : VerifyOrDieWithMsg(aPacket->ref > 0, chipSystemLayer, "SystemPacketBuffer::Free: aPacket->ref = 0");
721 :
722 127836 : aPacket->ref--;
723 127836 : if (aPacket->ref == 0)
724 : {
725 67980 : SYSTEM_STATS_DECREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
726 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
727 67980 : ::chip::Platform::MemoryDebugCheckPointer(aPacket, aPacket->alloc_size + kStructureSize);
728 : #endif
729 67980 : aPacket->Clear();
730 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
731 : aPacket->next = sFreeList;
732 : sFreeList = aPacket;
733 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
734 67980 : chip::Platform::MemoryFree(aPacket);
735 : #endif
736 67980 : aPacket = lNextPacket;
737 : }
738 : else
739 : {
740 59856 : aPacket = nullptr;
741 : }
742 : }
743 :
744 : UNLOCK_BUF_POOL();
745 :
746 : #else
747 : #error "Unimplemented PacketBuffer storage case"
748 : #endif
749 124662 : }
750 :
751 : /**
752 : * Clear content of the packet buffer.
753 : *
754 : * This method is called by Free(), before the buffer is released to the free buffer pool.
755 : */
756 67980 : void PacketBuffer::Clear()
757 : {
758 67980 : tot_len = 0;
759 67980 : len = 0;
760 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
761 67980 : alloc_size = 0;
762 : #endif
763 67980 : }
764 :
765 : /**
766 : * Free the first buffer in a chain, returning a pointer to the remaining buffers.
767 : `*
768 : * @note When the buffer chain is referenced by multiple callers, `FreeHead()` will detach the head, but will not forcibly
769 : * deallocate the head buffer.
770 : *
771 : * @param[in] aPacket - buffer chain.
772 : *
773 : * @return packet buffer chain consisting of the tail of the input buffer (may be \c nullptr).
774 : */
775 9198 : PacketBuffer * PacketBuffer::FreeHead(PacketBuffer * aPacket)
776 : {
777 9198 : PacketBuffer * lNextPacket = aPacket->ChainedBuffer();
778 9198 : aPacket->next = nullptr;
779 9198 : PacketBuffer::Free(aPacket);
780 9198 : return lNextPacket;
781 : }
782 :
783 3983 : PacketBufferHandle PacketBufferHandle::PopHead()
784 : {
785 3983 : PacketBuffer * head = mBuffer;
786 :
787 : // This takes ownership from the `next` link.
788 3983 : mBuffer = mBuffer->ChainedBuffer();
789 :
790 3983 : head->next = nullptr;
791 3983 : head->tot_len = head->len;
792 :
793 : // The returned handle takes ownership from this.
794 3983 : return PacketBufferHandle(head);
795 : }
796 :
797 15145 : PacketBufferHandle PacketBufferHandle::CloneData() const
798 : {
799 15145 : PacketBufferHandle cloneHead;
800 :
801 30319 : for (PacketBuffer * original = mBuffer; original != nullptr; original = original->ChainedBuffer())
802 : {
803 15175 : size_t originalDataSize = original->MaxDataLength();
804 15175 : uint16_t originalReservedSize = original->ReservedSize();
805 :
806 15175 : if (originalDataSize + originalReservedSize > PacketBuffer::kMaxAllocSize)
807 : {
808 : // The original memory allocation may have provided a larger block than requested (e.g. when using a shared pool),
809 : // and in particular may have provided a larger block than we are able to request from PackBufferHandle::New().
810 : // It is a genuine error if that extra space has been used.
811 2 : if (originalReservedSize + original->DataLength() > PacketBuffer::kMaxAllocSize)
812 : {
813 1 : return PacketBufferHandle();
814 : }
815 : // Otherwise, reduce the requested data size. This subtraction can not underflow because the above test
816 : // guarantees originalReservedSize <= PacketBuffer::kMaxAllocSize.
817 1 : originalDataSize = PacketBuffer::kMaxAllocSize - originalReservedSize;
818 : }
819 :
820 15174 : PacketBufferHandle clone = PacketBufferHandle::New(originalDataSize, originalReservedSize);
821 15174 : if (clone.IsNull())
822 : {
823 0 : return PacketBufferHandle();
824 : }
825 15174 : clone.mBuffer->tot_len = clone.mBuffer->len = original->len;
826 15174 : memcpy(clone->ReserveStart(), original->ReserveStart(), originalDataSize + originalReservedSize);
827 :
828 15174 : if (cloneHead.IsNull())
829 : {
830 15144 : cloneHead = std::move(clone);
831 : }
832 : else
833 : {
834 30 : cloneHead->AddToEnd(std::move(clone));
835 : }
836 15174 : }
837 :
838 15144 : return cloneHead;
839 15145 : }
840 :
841 : } // namespace System
842 :
843 : namespace Encoding {
844 :
845 89 : System::PacketBufferHandle PacketBufferWriterUtil::Finalize(BufferWriter & aBufferWriter, System::PacketBufferHandle & aPacket)
846 : {
847 89 : if (!aPacket.IsNull() && aBufferWriter.Fit())
848 : {
849 : // Since mPacket was successfully allocated to hold the maximum length,
850 : // we know that the actual length fits in a uint16_t.
851 88 : aPacket->SetDataLength(aBufferWriter.Needed());
852 : }
853 : else
854 : {
855 1 : aPacket = nullptr;
856 : }
857 89 : aBufferWriter = Encoding::BufferWriter(nullptr, 0);
858 89 : return std::move(aPacket);
859 : }
860 :
861 : } // namespace Encoding
862 : } // namespace chip
|