Matter SDK Coverage Report
Current view: top level - system - SystemPacketBuffer.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 94.5 % 237 224
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 24 24

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

Generated by: LCOV version 2.0-1