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 : // Include standard C library limit macros
27 : #ifndef __STDC_LIMIT_MACROS
28 : #define __STDC_LIMIT_MACROS
29 : #endif
30 :
31 : // Include module header
32 : #include <system/SystemPacketBuffer.h>
33 :
34 : // Include local headers
35 : #include <lib/support/CodeUtils.h>
36 : #include <lib/support/SafeInt.h>
37 : #include <lib/support/logging/CHIPLogging.h>
38 : #include <system/SystemFaultInjection.h>
39 : #include <system/SystemMutex.h>
40 : #include <system/SystemStats.h>
41 :
42 : #include <stdint.h>
43 :
44 : #include <limits.h>
45 : #include <limits>
46 : #include <stddef.h>
47 : #include <stdlib.h>
48 : #include <string.h>
49 : #include <utility>
50 :
51 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
52 : #include <lwip/mem.h>
53 : #include <lwip/pbuf.h>
54 : #if LWIP_VERSION_MAJOR == 2 && LWIP_VERSION_MINOR < 1
55 : #define PBUF_STRUCT_DATA_CONTIGUOUS(pbuf) (pbuf)->type == PBUF_RAM || (pbuf)->type == PBUF_POOL
56 : #else
57 : #define PBUF_STRUCT_DATA_CONTIGUOUS(pbuf) (pbuf)->type_internal & PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS
58 : #endif
59 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
60 :
61 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
62 : #include <lib/support/CHIPMem.h>
63 : #endif
64 :
65 : namespace chip {
66 : namespace System {
67 :
68 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
69 : //
70 : // Pool allocation for PacketBuffer objects.
71 : //
72 :
73 : PacketBuffer::BufferPoolElement PacketBuffer::sBufferPool[CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE];
74 :
75 : PacketBuffer * PacketBuffer::sFreeList = PacketBuffer::BuildFreeList();
76 :
77 : #if !CHIP_SYSTEM_CONFIG_NO_LOCKING
78 : static Mutex sBufferPoolMutex;
79 :
80 : #define LOCK_BUF_POOL() \
81 : do \
82 : { \
83 : sBufferPoolMutex.Lock(); \
84 : } while (0)
85 : #define UNLOCK_BUF_POOL() \
86 : do \
87 : { \
88 : sBufferPoolMutex.Unlock(); \
89 : } while (0)
90 : #endif // !CHIP_SYSTEM_CONFIG_NO_LOCKING
91 :
92 : PacketBuffer * PacketBuffer::BuildFreeList()
93 : {
94 : pbuf * lHead = nullptr;
95 :
96 : for (int i = 0; i < CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE; i++)
97 : {
98 : pbuf * lCursor = &sBufferPool[i].Header;
99 : lCursor->next = lHead;
100 : lCursor->ref = 0;
101 : lHead = lCursor;
102 : }
103 :
104 : #if !CHIP_SYSTEM_CONFIG_NO_LOCKING
105 : Mutex::Init(sBufferPoolMutex);
106 : #endif // !CHIP_SYSTEM_CONFIG_NO_LOCKING
107 :
108 : return static_cast<PacketBuffer *>(lHead);
109 : }
110 :
111 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
112 : //
113 : // Heap allocation for PacketBuffer objects.
114 : //
115 :
116 : #if CHIP_SYSTEM_PACKETBUFFER_HAS_CHECK
117 : void PacketBuffer::InternalCheck(const PacketBuffer * buffer)
118 : {
119 : if (buffer)
120 : {
121 : VerifyOrDieWithMsg(::chip::Platform::MemoryDebugCheckPointer(buffer, buffer->alloc_size + kStructureSize), chipSystemLayer,
122 : "invalid packet buffer pointer");
123 : VerifyOrDieWithMsg(buffer->alloc_size >= buffer->ReservedSize() + buffer->len, chipSystemLayer,
124 : "packet buffer overflow %u < %u+%u", buffer->alloc_size, buffer->ReservedSize(), buffer->len);
125 : }
126 : }
127 : #endif // CHIP_SYSTEM_PACKETBUFFER_HAS_CHECK
128 :
129 : // Number of unused bytes below which \c RightSize() won't bother reallocating.
130 : constexpr uint16_t kRightSizingThreshold = 16;
131 :
132 7729 : void PacketBufferHandle::InternalRightSize()
133 : {
134 : // Require a single buffer with no other references.
135 7729 : if ((mBuffer == nullptr) || mBuffer->HasChainedBuffer() || (mBuffer->ref != 1))
136 : {
137 1 : return;
138 : }
139 :
140 : // Reallocate only if enough space will be saved.
141 7728 : const uint8_t * const start = mBuffer->ReserveStart();
142 7728 : const uint8_t * const payload = mBuffer->Start();
143 7728 : const uint16_t usedSize = static_cast<uint16_t>(payload - start + mBuffer->len);
144 7728 : if (usedSize + kRightSizingThreshold > mBuffer->alloc_size)
145 : {
146 0 : return;
147 : }
148 :
149 7728 : const size_t blockSize = usedSize + PacketBuffer::kStructureSize;
150 7728 : PacketBuffer * newBuffer = reinterpret_cast<PacketBuffer *>(chip::Platform::MemoryAlloc(blockSize));
151 7728 : if (newBuffer == nullptr)
152 : {
153 0 : ChipLogError(chipSystemLayer, "PacketBuffer: pool EMPTY.");
154 0 : return;
155 : }
156 :
157 7728 : uint8_t * const newStart = newBuffer->ReserveStart();
158 7728 : newBuffer->next = nullptr;
159 7728 : newBuffer->payload = newStart + (payload - start);
160 7728 : newBuffer->tot_len = mBuffer->tot_len;
161 7728 : newBuffer->len = mBuffer->len;
162 7728 : newBuffer->ref = 1;
163 7728 : newBuffer->alloc_size = static_cast<uint16_t>(usedSize);
164 7728 : memcpy(newStart, start, usedSize);
165 :
166 7728 : PacketBuffer::Free(mBuffer);
167 7728 : mBuffer = newBuffer;
168 : }
169 :
170 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_LWIP_CUSTOM_POOL
171 :
172 : void PacketBufferHandle::InternalRightSize()
173 : {
174 : PacketBuffer * lNewPacket = static_cast<PacketBuffer *>(pbuf_rightsize((struct pbuf *) mBuffer, -1));
175 : if (lNewPacket != mBuffer)
176 : {
177 : mBuffer = lNewPacket;
178 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
179 : ChipLogDetail(chipSystemLayer, "PacketBuffer: RightSize Copied");
180 : }
181 : }
182 :
183 : #endif
184 :
185 : #ifndef LOCK_BUF_POOL
186 : #define LOCK_BUF_POOL() \
187 : do \
188 : { \
189 : } while (0)
190 : #endif // !defined(LOCK_BUF_POOL)
191 :
192 : #ifndef UNLOCK_BUF_POOL
193 : #define UNLOCK_BUF_POOL() \
194 : do \
195 : { \
196 : } while (0)
197 : #endif // !defined(UNLOCK_BUF_POOL)
198 :
199 19605 : void PacketBuffer::SetStart(uint8_t * aNewStart)
200 : {
201 19605 : uint8_t * const kStart = ReserveStart();
202 19605 : uint8_t * const kEnd = this->Start() + this->MaxDataLength();
203 :
204 19605 : if (aNewStart < kStart)
205 9 : aNewStart = kStart;
206 19596 : else if (aNewStart > kEnd)
207 11 : aNewStart = kEnd;
208 :
209 19605 : ptrdiff_t lDelta = aNewStart - static_cast<uint8_t *>(this->payload);
210 19605 : if (lDelta > this->len)
211 392 : lDelta = this->len;
212 :
213 19605 : this->len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->len) - lDelta);
214 19605 : this->tot_len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->tot_len) - lDelta);
215 19605 : this->payload = aNewStart;
216 19605 : }
217 :
218 58602 : void PacketBuffer::SetDataLength(uint16_t aNewLen, PacketBuffer * aChainHead)
219 : {
220 58602 : const uint16_t kMaxDataLen = this->MaxDataLength();
221 :
222 58602 : if (aNewLen > kMaxDataLen)
223 8113 : aNewLen = kMaxDataLen;
224 :
225 58602 : ptrdiff_t lDelta = static_cast<ptrdiff_t>(aNewLen) - static_cast<ptrdiff_t>(this->len);
226 :
227 58602 : this->len = aNewLen;
228 58602 : this->tot_len = static_cast<uint16_t>(this->tot_len + lDelta);
229 :
230 : // SetDataLength is often called after a client finished writing to the buffer,
231 : // so it's a good time to check for possible corruption.
232 58602 : Check(this);
233 :
234 66731 : while (aChainHead != nullptr && aChainHead != this)
235 : {
236 8129 : Check(aChainHead);
237 8129 : aChainHead->tot_len = static_cast<uint16_t>(aChainHead->tot_len + lDelta);
238 8129 : aChainHead = aChainHead->ChainedBuffer();
239 : }
240 58602 : }
241 :
242 125812 : uint16_t PacketBuffer::MaxDataLength() const
243 : {
244 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
245 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)))
246 : {
247 : return DataLength();
248 : }
249 : #endif
250 125812 : return static_cast<uint16_t>(AllocSize() - ReservedSize());
251 : }
252 :
253 35101 : uint16_t PacketBuffer::AvailableDataLength() const
254 : {
255 35101 : return static_cast<uint16_t>(this->MaxDataLength() - this->DataLength());
256 : }
257 :
258 154766 : uint16_t PacketBuffer::ReservedSize() const
259 : {
260 : // Cast to uint16_t is safe because Start() always points to "after"
261 : // ReserveStart(). At least when the payload is stored inline.
262 154766 : return static_cast<uint16_t>(Start() - ReserveStart());
263 : }
264 :
265 103881 : uint8_t * PacketBuffer::ReserveStart()
266 : {
267 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
268 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)))
269 : {
270 : return reinterpret_cast<uint8_t *>(this->Start());
271 : }
272 : #endif
273 103881 : return reinterpret_cast<uint8_t *>(this) + kStructureSize;
274 : }
275 :
276 154766 : const uint8_t * PacketBuffer::ReserveStart() const
277 : {
278 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
279 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)))
280 : {
281 : return reinterpret_cast<const uint8_t *>(this->Start());
282 : }
283 : #endif
284 154766 : return reinterpret_cast<const uint8_t *>(this) + kStructureSize;
285 : }
286 :
287 9141 : void PacketBuffer::AddToEnd(PacketBufferHandle && aPacketHandle)
288 : {
289 : // Ownership of aPacketHandle's buffer is transferred to the end of the chain.
290 9141 : PacketBuffer * aPacket = std::move(aPacketHandle).UnsafeRelease();
291 :
292 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
293 : pbuf_cat(this, aPacket);
294 : #else // !CHIP_SYSTEM_CONFIG_USE_LWIP
295 9141 : PacketBuffer * lCursor = this;
296 :
297 : while (true)
298 : {
299 11362 : uint16_t old_total_length = lCursor->tot_len;
300 11362 : lCursor->tot_len = static_cast<uint16_t>(lCursor->tot_len + aPacket->tot_len);
301 11362 : VerifyOrDieWithMsg(lCursor->tot_len >= old_total_length, chipSystemLayer, "buffer chain too large");
302 11362 : if (!lCursor->HasChainedBuffer())
303 : {
304 9141 : lCursor->next = aPacket;
305 9141 : break;
306 : }
307 :
308 2221 : lCursor = lCursor->ChainedBuffer();
309 2221 : }
310 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
311 9141 : }
312 :
313 1497 : void PacketBuffer::CompactHead()
314 : {
315 1497 : uint8_t * const kStart = ReserveStart();
316 :
317 1497 : if (this->payload != kStart)
318 : {
319 1310 : memmove(kStart, this->payload, this->len);
320 1310 : this->payload = kStart;
321 : }
322 :
323 1497 : uint16_t lAvailLength = this->AvailableDataLength();
324 :
325 2897 : while (lAvailLength > 0 && HasChainedBuffer())
326 : {
327 1400 : PacketBuffer & lNextPacket = *ChainedBuffer();
328 1400 : VerifyOrDieWithMsg(lNextPacket.ref == 1, chipSystemLayer, "next buffer %p is not exclusive to this chain", &lNextPacket);
329 :
330 1400 : uint16_t lMoveLength = lNextPacket.len;
331 1400 : if (lMoveLength > lAvailLength)
332 58 : lMoveLength = lAvailLength;
333 :
334 1400 : memcpy(static_cast<uint8_t *>(this->payload) + this->len, lNextPacket.payload, lMoveLength);
335 :
336 1400 : lNextPacket.payload = static_cast<uint8_t *>(lNextPacket.payload) + lMoveLength;
337 1400 : this->len = static_cast<uint16_t>(this->len + lMoveLength);
338 1400 : lAvailLength = static_cast<uint16_t>(lAvailLength - lMoveLength);
339 1400 : lNextPacket.len = static_cast<uint16_t>(lNextPacket.len - lMoveLength);
340 1400 : lNextPacket.tot_len = static_cast<uint16_t>(lNextPacket.tot_len - lMoveLength);
341 :
342 1400 : if (lNextPacket.len == 0)
343 1342 : this->next = this->FreeHead(&lNextPacket);
344 : }
345 1497 : }
346 :
347 20783 : void PacketBuffer::ConsumeHead(uint16_t aConsumeLength)
348 : {
349 20783 : if (aConsumeLength > this->len)
350 30 : aConsumeLength = this->len;
351 20783 : this->payload = static_cast<uint8_t *>(this->payload) + aConsumeLength;
352 20783 : this->len = static_cast<uint16_t>(this->len - aConsumeLength);
353 20783 : this->tot_len = static_cast<uint16_t>(this->tot_len - aConsumeLength);
354 20783 : }
355 :
356 : /**
357 : * Consume data in a chain of buffers.
358 : *
359 : * Consume data in a chain of buffers starting with the current buffer and proceeding through the remaining buffers in the
360 : * chain. Each buffer that is completely consumed is freed and the function returns the first buffer (if any) containing the
361 : * remaining data. The current buffer must be the head of the buffer chain.
362 : *
363 : * @param[in] aConsumeLength - number of bytes to consume from the current chain.
364 : *
365 : * @return the first buffer from the current chain that contains any remaining data. If no data remains, nullptr is returned.
366 : */
367 6492 : PacketBuffer * PacketBuffer::Consume(uint16_t aConsumeLength)
368 : {
369 6492 : PacketBuffer * lPacket = this;
370 :
371 14226 : while (lPacket != nullptr && aConsumeLength > 0)
372 : {
373 9466 : const uint16_t kLength = lPacket->DataLength();
374 :
375 9466 : if (aConsumeLength >= kLength)
376 : {
377 7734 : lPacket = PacketBuffer::FreeHead(lPacket);
378 7734 : aConsumeLength = static_cast<uint16_t>(aConsumeLength - kLength);
379 : }
380 : else
381 : {
382 1732 : lPacket->ConsumeHead(aConsumeLength);
383 1732 : break;
384 : }
385 : }
386 :
387 6492 : return lPacket;
388 : }
389 :
390 144 : CHIP_ERROR PacketBuffer::Read(uint8_t * aDestination, size_t aReadLength) const
391 : {
392 144 : const PacketBuffer * lPacket = this;
393 :
394 144 : if (aReadLength > TotalLength())
395 : {
396 30 : return CHIP_ERROR_BUFFER_TOO_SMALL;
397 : }
398 300 : while (aReadLength > 0)
399 : {
400 236 : if (lPacket == nullptr)
401 : {
402 : // TotalLength() or an individual buffer's DataLength() must have been wrong.
403 50 : return CHIP_ERROR_INTERNAL;
404 : }
405 186 : size_t lToReadFromCurrentBuf = lPacket->DataLength();
406 186 : if (aReadLength < lToReadFromCurrentBuf)
407 : {
408 30 : lToReadFromCurrentBuf = aReadLength;
409 : }
410 186 : memcpy(aDestination, lPacket->Start(), lToReadFromCurrentBuf);
411 186 : aDestination += lToReadFromCurrentBuf;
412 186 : aReadLength -= lToReadFromCurrentBuf;
413 186 : lPacket = lPacket->ChainedBuffer();
414 : }
415 64 : return CHIP_NO_ERROR;
416 : }
417 :
418 19244 : bool PacketBuffer::EnsureReservedSize(uint16_t aReservedSize)
419 : {
420 19244 : const uint16_t kCurrentReservedSize = this->ReservedSize();
421 19244 : if (aReservedSize <= kCurrentReservedSize)
422 19204 : return true;
423 :
424 40 : if ((aReservedSize + this->len) > this->AllocSize())
425 26 : return false;
426 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
427 : if (!(PBUF_STRUCT_DATA_CONTIGUOUS(this)) && aReservedSize > 0)
428 : {
429 : return false;
430 : }
431 : #endif
432 : // Cast is safe because aReservedSize > kCurrentReservedSize.
433 14 : const uint16_t kMoveLength = static_cast<uint16_t>(aReservedSize - kCurrentReservedSize);
434 14 : memmove(static_cast<uint8_t *>(this->payload) + kMoveLength, this->payload, this->len);
435 14 : payload = static_cast<uint8_t *>(this->payload) + kMoveLength;
436 :
437 14 : return true;
438 : }
439 :
440 36 : bool PacketBuffer::AlignPayload(uint16_t aAlignBytes)
441 : {
442 36 : if (aAlignBytes == 0)
443 6 : return false;
444 :
445 30 : const uint16_t kPayloadOffset = static_cast<uint16_t>(reinterpret_cast<uintptr_t>(this->payload) % aAlignBytes);
446 :
447 30 : if (kPayloadOffset == 0)
448 6 : return true;
449 :
450 : // Cast is safe because by construction kPayloadOffset < aAlignBytes.
451 24 : const uint16_t kPayloadShift = static_cast<uint16_t>(aAlignBytes - kPayloadOffset);
452 :
453 24 : if (!CanCastTo<uint16_t>(this->ReservedSize() + kPayloadShift))
454 : {
455 0 : return false;
456 : }
457 :
458 24 : return (this->EnsureReservedSize(static_cast<uint16_t>(this->ReservedSize() + kPayloadShift)));
459 : }
460 :
461 : /**
462 : * Increment the reference count of the current buffer.
463 : */
464 48710 : void PacketBuffer::AddRef()
465 : {
466 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
467 : pbuf_ref(this);
468 : #else // !CHIP_SYSTEM_CONFIG_USE_LWIP
469 : LOCK_BUF_POOL();
470 48710 : VerifyOrDieWithMsg(this->ref < std::numeric_limits<decltype(this->ref)>::max(), chipSystemLayer,
471 : "packet buffer refcount overflow");
472 48710 : ++this->ref;
473 : UNLOCK_BUF_POOL();
474 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
475 48710 : }
476 :
477 48014 : PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aReservedSize)
478 : {
479 : // Adding three 16-bit-int sized numbers together will never overflow
480 : // assuming int is at least 32 bits.
481 : static_assert(INT_MAX >= INT32_MAX, "int is not big enough");
482 : static_assert(PacketBuffer::kStructureSize == sizeof(PacketBuffer), "PacketBuffer size mismatch");
483 : static_assert(PacketBuffer::kStructureSize < UINT16_MAX, "Check for overflow more carefully");
484 : static_assert(SIZE_MAX >= INT_MAX, "Our additions might not fit in size_t");
485 : static_assert(PacketBuffer::kMaxSizeWithoutReserve <= UINT16_MAX, "PacketBuffer may have size not fitting uint16_t");
486 :
487 : // When `aAvailableSize` fits in uint16_t (as tested below) and size_t is at least 32 bits (as asserted above),
488 : // these additions will not overflow.
489 48014 : const size_t lAllocSize = aReservedSize + aAvailableSize;
490 48014 : const size_t lBlockSize = PacketBuffer::kStructureSize + lAllocSize;
491 : PacketBuffer * lPacket;
492 :
493 48014 : CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_PacketBufferNew, return PacketBufferHandle());
494 :
495 48014 : if (aAvailableSize > UINT16_MAX || lAllocSize > PacketBuffer::kMaxSizeWithoutReserve || lBlockSize > UINT16_MAX)
496 : {
497 1 : ChipLogError(chipSystemLayer, "PacketBuffer: allocation too large.");
498 1 : return PacketBufferHandle();
499 : }
500 :
501 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
502 :
503 : lPacket = static_cast<PacketBuffer *>(
504 : pbuf_alloc(PBUF_RAW, static_cast<uint16_t>(lAllocSize), CHIP_SYSTEM_PACKETBUFFER_LWIP_PBUF_TYPE));
505 :
506 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
507 :
508 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
509 :
510 : static_cast<void>(lBlockSize);
511 : #if !CHIP_SYSTEM_CONFIG_NO_LOCKING && CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING
512 : if (!sBufferPoolMutex.isInitialized())
513 : {
514 : Mutex::Init(sBufferPoolMutex);
515 : }
516 : #endif
517 : LOCK_BUF_POOL();
518 :
519 : lPacket = PacketBuffer::sFreeList;
520 : if (lPacket != nullptr)
521 : {
522 : PacketBuffer::sFreeList = lPacket->ChainedBuffer();
523 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
524 : }
525 :
526 : UNLOCK_BUF_POOL();
527 :
528 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
529 :
530 48013 : lPacket = reinterpret_cast<PacketBuffer *>(chip::Platform::MemoryAlloc(lBlockSize));
531 48013 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
532 :
533 : #else
534 : #error "Unimplemented PacketBuffer storage case"
535 : #endif
536 :
537 48013 : if (lPacket == nullptr)
538 : {
539 0 : ChipLogError(chipSystemLayer, "PacketBuffer: pool EMPTY.");
540 0 : return PacketBufferHandle();
541 : }
542 :
543 48013 : lPacket->payload = lPacket->ReserveStart() + aReservedSize;
544 48013 : lPacket->len = lPacket->tot_len = 0;
545 48013 : lPacket->next = nullptr;
546 48013 : lPacket->ref = 1;
547 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
548 48013 : lPacket->alloc_size = static_cast<uint16_t>(lAllocSize);
549 : #endif
550 :
551 48013 : return PacketBufferHandle(lPacket);
552 : }
553 :
554 194 : PacketBufferHandle PacketBufferHandle::NewWithData(const void * aData, size_t aDataSize, uint16_t aAdditionalSize,
555 : uint16_t aReservedSize)
556 : {
557 194 : if (aDataSize > UINT16_MAX)
558 : {
559 0 : ChipLogError(chipSystemLayer, "PacketBuffer: allocation too large.");
560 0 : return PacketBufferHandle();
561 : }
562 : // Since `aDataSize` fits in uint16_t, the sum `aDataSize + aAdditionalSize` will not overflow.
563 : // `New()` will only return a non-null buffer if the total allocation size does not overflow.
564 194 : PacketBufferHandle buffer = New(aDataSize + aAdditionalSize, aReservedSize);
565 194 : if (buffer.mBuffer != nullptr)
566 : {
567 194 : memcpy(buffer.mBuffer->payload, aData, aDataSize);
568 194 : buffer.mBuffer->len = buffer.mBuffer->tot_len = static_cast<uint16_t>(aDataSize);
569 : }
570 194 : return buffer;
571 194 : }
572 :
573 : /**
574 : * Free all packet buffers in a chain.
575 : *
576 : * Decrement the reference count to all the buffers in the current chain. If the reference count reaches 0, the respective buffers
577 : * are freed or returned to allocation pools as appropriate. As a rule, users should treat this method as an equivalent of
578 : * `free()` function and not use the argument after the call.
579 : *
580 : * @param[in] aPacket - packet buffer to be freed.
581 : */
582 101445 : void PacketBuffer::Free(PacketBuffer * aPacket)
583 : {
584 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
585 :
586 : if (aPacket != nullptr)
587 : {
588 : pbuf_free(aPacket);
589 :
590 : SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
591 : }
592 :
593 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP || CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
594 :
595 : LOCK_BUF_POOL();
596 :
597 205980 : while (aPacket != nullptr)
598 : {
599 104535 : PacketBuffer * lNextPacket = aPacket->ChainedBuffer();
600 :
601 104535 : VerifyOrDieWithMsg(aPacket->ref > 0, chipSystemLayer, "SystemPacketBuffer::Free: aPacket->ref = 0");
602 :
603 104535 : aPacket->ref--;
604 104535 : if (aPacket->ref == 0)
605 : {
606 55741 : SYSTEM_STATS_DECREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs);
607 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
608 55741 : ::chip::Platform::MemoryDebugCheckPointer(aPacket, aPacket->alloc_size + kStructureSize);
609 : #endif
610 55741 : aPacket->Clear();
611 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
612 : aPacket->next = sFreeList;
613 : sFreeList = aPacket;
614 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
615 55741 : chip::Platform::MemoryFree(aPacket);
616 : #endif
617 55741 : aPacket = lNextPacket;
618 : }
619 : else
620 : {
621 48794 : aPacket = nullptr;
622 : }
623 : }
624 :
625 : UNLOCK_BUF_POOL();
626 :
627 : #else
628 : #error "Unimplemented PacketBuffer storage case"
629 : #endif
630 101445 : }
631 :
632 : /**
633 : * Clear content of the packet buffer.
634 : *
635 : * This method is called by Free(), before the buffer is released to the free buffer pool.
636 : */
637 55741 : void PacketBuffer::Clear()
638 : {
639 55741 : tot_len = 0;
640 55741 : len = 0;
641 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
642 55741 : alloc_size = 0;
643 : #endif
644 55741 : }
645 :
646 : /**
647 : * Free the first buffer in a chain, returning a pointer to the remaining buffers.
648 : `*
649 : * @note When the buffer chain is referenced by multiple callers, `FreeHead()` will detach the head, but will not forcibly
650 : * deallocate the head buffer.
651 : *
652 : * @param[in] aPacket - buffer chain.
653 : *
654 : * @return packet buffer chain consisting of the tail of the input buffer (may be \c nullptr).
655 : */
656 9139 : PacketBuffer * PacketBuffer::FreeHead(PacketBuffer * aPacket)
657 : {
658 9139 : PacketBuffer * lNextPacket = aPacket->ChainedBuffer();
659 9139 : aPacket->next = nullptr;
660 9139 : PacketBuffer::Free(aPacket);
661 9139 : return lNextPacket;
662 : }
663 :
664 1805 : PacketBufferHandle PacketBufferHandle::PopHead()
665 : {
666 1805 : PacketBuffer * head = mBuffer;
667 :
668 : // This takes ownership from the `next` link.
669 1805 : mBuffer = mBuffer->ChainedBuffer();
670 :
671 1805 : head->next = nullptr;
672 1805 : head->tot_len = head->len;
673 :
674 : // The returned handle takes ownership from this.
675 1805 : return PacketBufferHandle(head);
676 : }
677 :
678 9626 : PacketBufferHandle PacketBufferHandle::CloneData() const
679 : {
680 9626 : PacketBufferHandle cloneHead;
681 :
682 19281 : for (PacketBuffer * original = mBuffer; original != nullptr; original = original->ChainedBuffer())
683 : {
684 9656 : uint16_t originalDataSize = original->MaxDataLength();
685 9656 : uint16_t originalReservedSize = original->ReservedSize();
686 :
687 9656 : if (originalDataSize + originalReservedSize > PacketBuffer::kMaxSizeWithoutReserve)
688 : {
689 : // The original memory allocation may have provided a larger block than requested (e.g. when using a shared pool),
690 : // and in particular may have provided a larger block than we are able to request from PackBufferHandle::New().
691 : // It is a genuine error if that extra space has been used.
692 2 : if (originalReservedSize + original->DataLength() > PacketBuffer::kMaxSizeWithoutReserve)
693 : {
694 1 : return PacketBufferHandle();
695 : }
696 : // Otherwise, reduce the requested data size. This subtraction can not underflow because the above test
697 : // guarantees originalReservedSize <= PacketBuffer::kMaxSizeWithoutReserve.
698 1 : originalDataSize = static_cast<uint16_t>(PacketBuffer::kMaxSizeWithoutReserve - originalReservedSize);
699 : }
700 :
701 9655 : PacketBufferHandle clone = PacketBufferHandle::New(originalDataSize, originalReservedSize);
702 9655 : if (clone.IsNull())
703 : {
704 0 : return PacketBufferHandle();
705 : }
706 9655 : clone.mBuffer->tot_len = clone.mBuffer->len = original->len;
707 9655 : memcpy(clone->ReserveStart(), original->ReserveStart(), originalDataSize + originalReservedSize);
708 :
709 9655 : if (cloneHead.IsNull())
710 : {
711 9625 : cloneHead = std::move(clone);
712 : }
713 : else
714 : {
715 30 : cloneHead->AddToEnd(std::move(clone));
716 : }
717 9655 : }
718 :
719 9625 : return cloneHead;
720 9626 : }
721 :
722 : } // namespace System
723 :
724 : namespace Encoding {
725 :
726 71 : System::PacketBufferHandle PacketBufferWriterUtil::Finalize(BufferWriter & aBufferWriter, System::PacketBufferHandle & aPacket)
727 : {
728 71 : if (!aPacket.IsNull() && aBufferWriter.Fit())
729 : {
730 : // Since mPacket was successfully allocated to hold the maximum length,
731 : // we know that the actual length fits in a uint16_t.
732 70 : aPacket->SetDataLength(static_cast<uint16_t>(aBufferWriter.Needed()));
733 : }
734 : else
735 : {
736 1 : aPacket = nullptr;
737 : }
738 71 : aBufferWriter = Encoding::BufferWriter(nullptr, 0);
739 71 : return std::move(aPacket);
740 : }
741 :
742 : } // namespace Encoding
743 : } // namespace chip
|