LCOV - code coverage report
Current view: top level - system - SystemPacketBuffer.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 223 232 96.1 %
Date: 2024-02-15 08:20:41 Functions: 24 24 100.0 %

          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

Generated by: LCOV version 1.14