Coverage Report

Created: 2025-10-26 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openweave-core/src/system/SystemPacketBuffer.cpp
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 2016-2017 Nest Labs, Inc.
4
 *    All rights reserved.
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 nl::Weave::System::PacketBuffer class, which provides the
23
 *      mechanisms for manipulating packets of octet-serialized
24
 *      data.
25
 */
26
27
// Include standard C library limit macros
28
#ifndef __STDC_LIMIT_MACROS
29
#define __STDC_LIMIT_MACROS
30
#endif
31
#include <stdint.h>
32
33
// Include module header
34
#include <SystemLayer/SystemPacketBuffer.h>
35
36
// Include common private header
37
#include "SystemLayerPrivate.h"
38
39
// Include local headers
40
#include <SystemLayer/SystemMutex.h>
41
#include <SystemLayer/SystemFaultInjection.h>
42
43
#include <string.h>
44
#include <stdlib.h>
45
#include <stddef.h>
46
47
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
48
#include <lwip/pbuf.h>
49
#include <lwip/mem.h>
50
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
51
52
#include <Weave/Support/logging/WeaveLogging.h>
53
#include <Weave/Support/crypto/WeaveCrypto.h>
54
#include <Weave/Support/CodeUtils.h>
55
56
#include <SystemLayer/SystemStats.h>
57
58
namespace nl {
59
namespace Weave {
60
namespace System {
61
62
//
63
// Pool allocation for PacketBuffer objects (toll-free bridged with LwIP pbuf allocator if WEAVE_SYSTEM_CONFIG_USE_LWIP)
64
//
65
#if !WEAVE_SYSTEM_CONFIG_USE_LWIP
66
#if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
67
68
static BufferPoolElement sBufferPool[WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC];
69
70
PacketBuffer* PacketBuffer::sFreeList = PacketBuffer::BuildFreeList();
71
72
#if !WEAVE_SYSTEM_CONFIG_NO_LOCKING
73
static Mutex sBufferPoolMutex;
74
75
56.2k
#define LOCK_BUF_POOL()     do { sBufferPoolMutex.Lock(); } while (0)
76
56.2k
#define UNLOCK_BUF_POOL()   do { sBufferPoolMutex.Unlock(); } while (0)
77
#endif // !WEAVE_SYSTEM_CONFIG_NO_LOCKING
78
79
#endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
80
81
#ifndef LOCK_BUF_POOL
82
#define LOCK_BUF_POOL()     do { } while (0)
83
#endif // !defined(LOCK_BUF_POOL)
84
85
#ifndef UNLOCK_BUF_POOL
86
#define UNLOCK_BUF_POOL()   do { } while (0)
87
#endif // !defined(UNLOCK_BUF_POOL)
88
89
#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
90
91
/**
92
 * Get pointer to start of data in buffer.
93
 *
94
 *  @return pointer to the start of data.
95
 */
96
uint8_t* PacketBuffer::Start() const
97
136k
{
98
136k
    return static_cast<uint8_t*>(this->payload);
99
136k
}
100
101
/**
102
 *  Set the start data in buffer, adjusting length and total length accordingly.
103
 *
104
 *  @note The data within the buffer is not moved, only accounting information is changed.  The function is commonly used to either
105
 *  strip or prepend protocol headers in a zero-copy way.
106
 *
107
 *  @note This call should not be used on any buffer that is not the head of a buffer chain, as it only alters the current buffer.
108
 *
109
 *  @param[in] aNewStart - A pointer to where the new payload should start.  newStart will be adjusted internally to fall within
110
 *      the boundaries of the first buffer in the PacketBuffer chain.
111
 */
112
void PacketBuffer::SetStart(uint8_t* aNewStart)
113
0
{
114
0
    uint8_t* const kStart = reinterpret_cast<uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE;
115
0
    uint8_t* const kEnd = kStart + this->AllocSize();
116
117
0
    if (aNewStart < kStart)
118
0
        aNewStart = kStart;
119
0
    else if (aNewStart > kEnd)
120
0
        aNewStart = kEnd;
121
122
0
    ptrdiff_t lDelta = aNewStart - static_cast<uint8_t*>(this->payload);
123
0
    if (lDelta > this->len)
124
0
        lDelta = this->len;
125
126
0
    this->len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->len) - lDelta);
127
0
    this->tot_len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->tot_len) - lDelta);
128
0
    this->payload = aNewStart;
129
0
}
130
131
/**
132
 * Get length, in bytes, of data in packet buffer.
133
 *
134
 *  @return length, in bytes (current payload length).
135
 */
136
uint16_t PacketBuffer::DataLength() const
137
49.3k
{
138
49.3k
    return this->len;
139
49.3k
}
140
141
/**
142
 * Set length, in bytes, of data in buffer, adjusting total length accordingly.
143
 *
144
 *  The function sets the length, in bytes, of the data in the buffer, adjusting the total length appropriately.  When the buffer
145
 *  is not the head of the buffer chain (common case: the caller adds data to the last buffer in the PacketBuffer chain prior to
146
 *  calling higher layers), the aChainHead __must__ be passed in to properly adjust the total lengths of each buffer ahead of the
147
 *  current buffer.
148
 *
149
 *  @param[in] aNewLen - new length, in bytes, of this buffer.
150
 *
151
 *  @param[inout] aChainHead - the head of the buffer chain the current buffer belongs to.  May be NULL if the current buffer is
152
 *      the head of the buffer chain.
153
 */
154
void PacketBuffer::SetDataLength(uint16_t aNewLen, PacketBuffer* aChainHead)
155
32.7k
{
156
32.7k
    const uint16_t kMaxDataLen = this->MaxDataLength();
157
158
32.7k
    if (aNewLen > kMaxDataLen)
159
64
        aNewLen = kMaxDataLen;
160
161
32.7k
    ptrdiff_t lDelta = static_cast<ptrdiff_t>(aNewLen) - static_cast<ptrdiff_t>(this->len);
162
163
32.7k
    this->len = aNewLen;
164
32.7k
    this->tot_len = (uint16_t) (this->tot_len + lDelta);
165
166
32.7k
    while (aChainHead != NULL && aChainHead != this)
167
0
    {
168
0
        aChainHead->tot_len = static_cast<uint16_t>(aChainHead->tot_len + lDelta);
169
0
        aChainHead = static_cast<PacketBuffer*>(aChainHead->next);
170
0
    }
171
32.7k
}
172
173
/**
174
 * Get total length of packet data in the buffer chain.
175
 *
176
 * @return total length, in octets.
177
 */
178
uint16_t PacketBuffer::TotalLength() const
179
0
{
180
0
    return this->tot_len;
181
0
}
182
183
/**
184
 * Get the maximum amount, in bytes, of data that will fit in the buffer given the current start position and buffer size.
185
 *
186
 * @return number of bytes that fits in the buffer given the current start position.
187
 */
188
uint16_t PacketBuffer::MaxDataLength() const
189
82.3k
{
190
82.3k
    const uint8_t* const kStart = reinterpret_cast<const uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE;
191
82.3k
    const ptrdiff_t kDelta = static_cast<uint8_t*>(this->payload) - kStart;
192
82.3k
    return static_cast<uint16_t>(this->AllocSize() - kDelta);
193
82.3k
}
194
195
/**
196
 * Get the number of bytes of data that can be added to the current buffer given the current start position and data length.
197
 *
198
 * @return the length, in bytes, of data that will fit in the current buffer given the current start position and data length.
199
 */
200
uint16_t PacketBuffer::AvailableDataLength() const
201
49.6k
{
202
49.6k
    return this->MaxDataLength() - this->len;
203
49.6k
}
204
205
/**
206
 * Get the number of bytes within the current buffer between the start of the buffer and the current data start position.
207
 *
208
 * @return the amount, in bytes, of space between the start of the buffer and the current data start position.
209
 */
210
uint16_t PacketBuffer::ReservedSize() const
211
0
{
212
0
    const ptrdiff_t kDelta = static_cast<uint8_t*>(this->payload) - reinterpret_cast<const uint8_t*>(this);
213
0
    return static_cast<uint16_t>(kDelta - WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE);
214
0
}
215
216
/**
217
 *
218
 * Add the given packet buffer to the end of the buffer chain, adjusting the total length of each buffer in the chain accordingly.
219
 *
220
 *  @note The current packet buffer must be the head of the buffer chain for the lengths to be adjusted properly. The caller MUST
221
 *  NOT reference the given packet buffer afterwards.
222
 *
223
 * @param[in] aPacket - the packet buffer to be added to the end of the current chain.
224
 */
225
void PacketBuffer::AddToEnd(PacketBuffer* aPacket)
226
0
{
227
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
228
    pbuf_cat(this, aPacket);
229
#else // !WEAVE_SYSTEM_CONFIG_USE_LWIP
230
0
    PacketBuffer* lCursor = this;
231
232
0
    while (true)
233
0
    {
234
0
        lCursor->tot_len += aPacket->tot_len;
235
0
        if (lCursor->next == NULL)
236
0
        {
237
0
            lCursor->next = aPacket;
238
0
            break;
239
0
        }
240
241
0
        lCursor = static_cast<PacketBuffer*>(lCursor->next);
242
0
    }
243
0
#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
244
0
}
245
246
/**
247
 *  Detach the current buffer from its chain and return a pointer to the remaining buffers.  The current buffer must be the head of
248
 *  the chain.
249
 *
250
 *  @return the tail of the current buffer chain or NULL if the current buffer is the only buffer in the chain.
251
 */
252
PacketBuffer* PacketBuffer::DetachTail()
253
0
{
254
0
    PacketBuffer* lReturn = static_cast<PacketBuffer*>(this->next);
255
256
0
    this->next = NULL;
257
0
    this->tot_len = this->len;
258
259
0
    return lReturn;
260
0
}
261
262
/**
263
 * Move data from subsequent buffers in the chain into the current buffer until it is full.
264
 *
265
 *  Only the current buffer is compacted: the data within the current buffer is moved to the front of the buffer, eliminating any
266
 *  reserved space.  The remaining available space is filled with data moved from subsequent buffers in the chain, until the
267
 *  current buffer is full.  If a subsequent buffer in the chain is moved into the current buffer in its entirety, it is removed
268
 *  from the chain and freed.  The method takes no parameters, returns no results and cannot fail.
269
 */
270
void PacketBuffer::CompactHead()
271
0
{
272
0
    uint8_t* const kStart = reinterpret_cast<uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE;
273
274
0
    if (this->payload != kStart)
275
0
    {
276
0
        memmove(kStart, this->payload, this->len);
277
0
        this->payload = kStart;
278
0
    }
279
280
0
    uint16_t lAvailLength = this->AvailableDataLength();
281
282
0
    while (lAvailLength > 0 && this->next != NULL)
283
0
    {
284
0
        PacketBuffer& lNextPacket = *static_cast<PacketBuffer*>(this->next);
285
0
        VerifyOrDieWithMsg(lNextPacket.ref == 1, WeaveSystemLayer, "next buffer %p is not exclusive to this chain", &lNextPacket);
286
287
0
        uint16_t lMoveLength = lNextPacket.len;
288
0
        if (lMoveLength > lAvailLength)
289
0
            lMoveLength = lAvailLength;
290
291
0
        memcpy(static_cast<uint8_t*>(this->payload) + this->len, lNextPacket.payload, lMoveLength);
292
293
0
        lNextPacket.payload = (uint8_t *) lNextPacket.payload + lMoveLength;
294
0
        this->len += lMoveLength;
295
0
        lAvailLength -= lMoveLength;
296
0
        lNextPacket.len -= lMoveLength;
297
0
        lNextPacket.tot_len -= lMoveLength;
298
299
0
        if (lNextPacket.len == 0)
300
0
            this->next = this->FreeHead(&lNextPacket);
301
0
    }
302
0
}
303
304
/**
305
 * Adjust the current buffer to indicate the amount of data consumed.
306
 *
307
 *  Advance the data start position in the current buffer by the specified amount, in bytes, up to the length of data in the
308
 *  buffer. Decrease the length and total length by the amount consumed.
309
 *
310
 *  @param[in] aConsumeLen - number of bytes to consume from the current buffer.
311
 */
312
void PacketBuffer::ConsumeHead(uint16_t aConsumeLength)
313
0
{
314
0
    if (aConsumeLength > this->len)
315
0
        aConsumeLength = this->len;
316
0
    this->payload = static_cast<uint8_t*>(this->payload) + aConsumeLength;
317
0
    this->len -= aConsumeLength;
318
0
    this->tot_len -= aConsumeLength;
319
0
}
320
321
/**
322
 * Consume data in a chain of buffers.
323
 *
324
 *  Consume data in a chain of buffers starting with the current buffer and proceeding through the remaining buffers in the chain.
325
 *  Each buffer that is completely consumed is freed and the function returns the first buffer (if any) containing the remaining
326
 *  data. The current buffer must be the head of the buffer chain.
327
 *
328
 *  @param[in] aConsumeLength - number of bytes to consume from the current chain.
329
 *
330
 *  @return the first buffer from the current chain that contains any remaining data.  If no data remains, a NULL is returned.
331
 */
332
PacketBuffer* PacketBuffer::Consume(uint16_t aConsumeLength)
333
0
{
334
0
    PacketBuffer* lPacket = this;
335
336
0
    while (lPacket != NULL && aConsumeLength > 0)
337
0
    {
338
0
        const uint16_t kLength = lPacket->DataLength();
339
340
0
        if (aConsumeLength >= kLength)
341
0
        {
342
0
            lPacket = PacketBuffer::FreeHead(lPacket);
343
0
            aConsumeLength -= kLength;
344
0
        }
345
0
        else
346
0
        {
347
0
            lPacket->ConsumeHead(aConsumeLength);
348
0
            break;
349
0
        }
350
0
    }
351
352
0
    return lPacket;
353
0
}
354
355
/**
356
 * Ensure the buffer has at least the specified amount of reserved space.
357
 *
358
 *  Ensure the buffer has at least the specified amount of reserved space moving the data in the buffer forward to make room if
359
 *  necessary.
360
 *
361
 *  @param[in] aReservedSize - number of bytes desired for the headers.
362
 *
363
 *  @return \c true if the requested reserved size is available, \c false if there's not enough room in the buffer.
364
 */
365
bool PacketBuffer::EnsureReservedSize(uint16_t aReservedSize)
366
0
{
367
0
    const uint16_t kCurrentReservedSize = this->ReservedSize();
368
0
    if (aReservedSize <= kCurrentReservedSize)
369
0
        return true;
370
371
0
    if ((aReservedSize + this->len) > this->AllocSize())
372
0
        return false;
373
374
0
    const uint16_t kMoveLength = aReservedSize - kCurrentReservedSize;
375
0
    memmove(static_cast<uint8_t*>(this->payload) + kMoveLength, this->payload, this->len);
376
0
    payload = static_cast<uint8_t*>(this->payload) + kMoveLength;
377
378
0
    return true;
379
0
}
380
381
/**
382
 * Align the buffer payload on the specified bytes boundary.
383
 *
384
 *  Moving the payload in the buffer forward if necessary.
385
 *
386
 *  @param[in] aAlignBytes - specifies number of bytes alignment for the payload start pointer.
387
 *
388
 *  @return \c true if alignment is successful, \c false if there's not enough room in the buffer.
389
 */
390
bool PacketBuffer::AlignPayload(uint16_t aAlignBytes)
391
0
{
392
0
    if (aAlignBytes == 0)
393
0
        return false;
394
395
0
    const uint16_t kPayloadOffset = reinterpret_cast<uintptr_t>(this->payload) % aAlignBytes;
396
397
0
    if (kPayloadOffset == 0)
398
0
        return true;
399
400
0
    const uint16_t kPayloadShift = aAlignBytes - kPayloadOffset;
401
402
0
    return (this->EnsureReservedSize(this->ReservedSize() + kPayloadShift));
403
0
}
404
405
/**
406
 * Get pointer to next buffer in chain.
407
 *
408
 *  @return a pointer to the next buffer in the chain.  \c NULL is returned when there is no buffers in the chain.
409
 */
410
PacketBuffer* PacketBuffer::Next() const
411
0
{
412
0
    return static_cast<PacketBuffer*>(this->next);
413
0
}
414
415
/**
416
 * Increment the reference count of the current buffer.
417
 */
418
void PacketBuffer::AddRef()
419
0
{
420
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
421
    pbuf_ref(this);
422
#else // !WEAVE_SYSTEM_CONFIG_USE_LWIP
423
0
    LOCK_BUF_POOL();
424
0
    ++this->ref;
425
0
    UNLOCK_BUF_POOL();
426
0
#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
427
0
}
428
429
/**
430
 * Allocates a PacketBuffer object with at least \c aReservedSize bytes reserved in the payload for headers, and at least
431
 *  \c aAllocSize bytes of space for additional data after the initial cursor pointer.
432
 *
433
 *  @param[in]  aReservedSize   Number of octets to reserve behind the cursor.
434
 *  @param[in]  aAvailableSize  Number of octets to allocate after the cursor.
435
 *
436
 *  @return     On success, a pointer to the PacketBuffer in the allocated block. On fail, \c NULL.
437
 */
438
PacketBuffer* PacketBuffer::NewWithAvailableSize(uint16_t aReservedSize, size_t aAvailableSize)
439
24.1k
{
440
24.1k
    const size_t lReservedSize = static_cast<size_t>(aReservedSize);
441
24.1k
    const size_t lAllocSize = lReservedSize + aAvailableSize;
442
24.1k
    PacketBuffer* lPacket;
443
444
24.1k
    WEAVE_SYSTEM_FAULT_INJECT(FaultInjection::kFault_PacketBufferNew, return NULL);
445
446
24.1k
    if (lAllocSize > WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX)
447
0
    {
448
0
        WeaveLogError(WeaveSystemLayer, "PacketBuffer: allocation too large.");
449
0
        return NULL;
450
0
    }
451
452
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
453
454
    lPacket = static_cast<PacketBuffer*>(pbuf_alloc(PBUF_RAW, lAllocSize, PBUF_POOL));
455
456
    SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
457
458
#else // !WEAVE_SYSTEM_CONFIG_USE_LWIP
459
24.1k
#if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
460
461
24.1k
    LOCK_BUF_POOL();
462
463
24.1k
    lPacket = sFreeList;
464
24.1k
    if (lPacket != NULL)
465
24.1k
    {
466
24.1k
        sFreeList = static_cast<PacketBuffer*>(lPacket->next);
467
24.1k
        SYSTEM_STATS_INCREMENT(nl::Weave::System::Stats::kSystemLayer_NumPacketBufs);
468
24.1k
    }
469
470
24.1k
    UNLOCK_BUF_POOL();
471
472
#else // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
473
474
    const size_t lBlockSize = WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE + lAllocSize;
475
476
    lPacket = reinterpret_cast<PacketBuffer*>(malloc(lBlockSize));
477
    SYSTEM_STATS_INCREMENT(nl::Weave::System::Stats::kSystemLayer_NumPacketBufs);
478
479
#endif // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
480
24.1k
#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
481
482
24.1k
    if (lPacket == NULL)
483
0
    {
484
0
        WeaveLogError(WeaveSystemLayer, "PacketBuffer: pool EMPTY.");
485
0
        return NULL;
486
0
    }
487
488
24.1k
    lPacket->payload = reinterpret_cast<uint8_t*>(lPacket) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE + lReservedSize;
489
24.1k
    lPacket->len = lPacket->tot_len = 0;
490
24.1k
    lPacket->next = NULL;
491
24.1k
    lPacket->ref = 1;
492
#if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0
493
    lPacket->alloc_size = lAllocSize;
494
#endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0
495
496
24.1k
    return lPacket;
497
24.1k
}
498
499
/**
500
 * Allocates a PacketBuffer with default reserved size (#WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE) in the payload for headers,
501
 * and at least \c aAllocSize bytes of space for additional data after the initial cursor pointer.
502
 *
503
 * This usage is most appropriate when allocating a PacketBuffer for an application-layer message.
504
 *
505
 *  @param[in]  aAvailableSize  Number of octets to allocate after the cursor.
506
 *
507
 *  @return     On success, a pointer to the PacketBuffer in the allocated block. On fail, \c NULL. *
508
 */
509
PacketBuffer* PacketBuffer::NewWithAvailableSize(size_t aAvailableSize)
510
0
{
511
0
    return PacketBuffer::NewWithAvailableSize(WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE, aAvailableSize);
512
0
}
513
514
/**
515
 * Allocates a single PacketBuffer of maximum total size with a specific header reserve size.
516
 *
517
 *  The parameter passed in is the size reserved prior to the payload to accomodate packet headers from different stack layers,
518
 *  __not__ the overall size of the buffer to allocate. The size of the buffer #WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX
519
 *  and not, specified in the call.
520
 *
521
 * - `PacketBuffer::New(0)` : when called in this fashion, the buffer will be returned without any header reserved, consequently
522
 *      the entire payload is usable by the caller. This pattern is particularly useful at the lower layers of networking stacks,
523
 *      in cases where the user knows the payload will be copied out into the final message with appropriate header reserves or in
524
 *      creating PacketBuffer that are appended to a chain of PacketBuffer via `PacketBuffer::AddToEnd()`.
525
 *
526
 *  @param[in] aReservedSize  amount of header space to reserve.
527
 *
528
 *  @return On success, a pointer to the PacketBuffer, on failure \c NULL.
529
 */
530
PacketBuffer* PacketBuffer::New(uint16_t aReservedSize)
531
24.1k
{
532
24.1k
    const size_t lReservedSize = static_cast<size_t>(aReservedSize);
533
534
24.1k
    const size_t lAvailableSize =
535
24.1k
        lReservedSize < WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX ? WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX - lReservedSize : 0;
536
537
24.1k
    return PacketBuffer::NewWithAvailableSize(aReservedSize, lAvailableSize);
538
24.1k
}
539
540
/**
541
 * Allocates a single PacketBuffer of default max size (#WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX) with default reserved size
542
 * (#WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE) in the payload.
543
 *
544
 * The reserved size (#WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE) is large enough to hold transport layer headers as well as headers required by
545
 * \c WeaveMessageLayer and \c WeaveExchangeLayer.
546
 */
547
PacketBuffer* PacketBuffer::New(void)
548
24.1k
{
549
24.1k
    return PacketBuffer::New(WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE);
550
24.1k
}
551
552
/**
553
 * Free all packet buffers in a chain.
554
 *
555
 *  Decrement the reference count to all the buffers in the current chain. If the reference count reaches 0, the respective buffers
556
 *  are freed or returned to allocation pools as appropriate. As a rule, users should treat this method as an equivalent of
557
 *  `free()` function and not use the argument after the call.
558
 *
559
 *  @param[in] aPacket - packet buffer to be freed.
560
 */
561
void PacketBuffer::Free(PacketBuffer* aPacket)
562
32.1k
{
563
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
564
565
    if (aPacket != NULL)
566
    {
567
        pbuf_free(aPacket);
568
569
        SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
570
    }
571
572
#else // !WEAVE_SYSTEM_CONFIG_USE_LWIP
573
574
32.1k
    LOCK_BUF_POOL();
575
576
56.2k
    while (aPacket != NULL)
577
24.1k
    {
578
24.1k
        PacketBuffer* lNextPacket = static_cast<PacketBuffer*>(aPacket->next);
579
580
24.1k
        VerifyOrDieWithMsg(aPacket->ref > 0, WeaveSystemLayer, "SystemPacketBuffer::Free: aPacket->ref = 0");
581
582
24.1k
        aPacket->ref--;
583
24.1k
        if (aPacket->ref == 0)
584
24.1k
        {
585
24.1k
            SYSTEM_STATS_DECREMENT(nl::Weave::System::Stats::kSystemLayer_NumPacketBufs);
586
24.1k
            aPacket->Clear();
587
24.1k
#if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
588
24.1k
            aPacket->next = sFreeList;
589
24.1k
            sFreeList = aPacket;
590
#else // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
591
            free(aPacket);
592
#endif // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
593
24.1k
            aPacket = lNextPacket;
594
24.1k
        }
595
0
        else
596
0
        {
597
0
            aPacket = NULL;
598
0
        }
599
24.1k
    }
600
601
32.1k
    UNLOCK_BUF_POOL();
602
603
32.1k
#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
604
32.1k
}
605
606
/**
607
 * Clear content of the packet buffer.
608
 *
609
 * This method is called by Free(), before the buffer is released to the free buffer pool.
610
 */
611
void PacketBuffer::Clear(void)
612
24.1k
{
613
24.1k
    nl::Weave::Crypto::ClearSecretData(reinterpret_cast<uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE, this->AllocSize());
614
24.1k
    tot_len = 0;
615
24.1k
    len = 0;
616
#if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0
617
    alloc_size = 0;
618
#endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0
619
24.1k
}
620
621
/**
622
 * Free the first buffer in a chain, returning a pointer to the remaining buffers.
623
 `*
624
 *  @note When the buffer chain is referenced by multiple callers, `FreeHead()` will detach the head, but will not forcibly
625
 *  deallocate the head buffer.
626
 *
627
 *  @param[in] aPacket - buffer chain.
628
 *
629
 *  @return packet buffer chain consisting of the tail of the input buffer (may be \c NULL).
630
 */
631
PacketBuffer* PacketBuffer::FreeHead(PacketBuffer* aPacket)
632
0
{
633
0
    PacketBuffer* lNextPacket = static_cast<PacketBuffer*>(aPacket->next);
634
0
    aPacket->next = NULL;
635
0
    PacketBuffer::Free(aPacket);
636
0
    return lNextPacket;
637
0
}
638
639
/**
640
 * Copy the given buffer to a right-sized buffer if applicable.
641
 * This function is a no-op for sockets.
642
 *
643
 *  @param[in] aPacket - buffer or buffer chain.
644
 *
645
 *  @return new packet buffer or the original buffer
646
 */
647
PacketBuffer* PacketBuffer::RightSize(PacketBuffer *aPacket)
648
0
{
649
0
    PacketBuffer *lNewPacket = aPacket;
650
#if WEAVE_SYSTEM_CONFIG_USE_LWIP && LWIP_PBUF_FROM_CUSTOM_POOLS
651
    lNewPacket =  static_cast<PacketBuffer *>(pbuf_rightsize((struct pbuf *)aPacket, -1));
652
    if (lNewPacket != aPacket)
653
    {
654
        SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS();
655
656
        WeaveLogProgress(WeaveSystemLayer, "PacketBuffer: RightSize Copied");
657
    }
658
#endif
659
0
    return lNewPacket;
660
0
}
661
662
#if !WEAVE_SYSTEM_CONFIG_USE_LWIP && WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
663
664
PacketBuffer* PacketBuffer::BuildFreeList()
665
12
{
666
12
    PacketBuffer* lHead = NULL;
667
668
3.61k
    for (int i = 0; i < WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC; i++)
669
3.60k
    {
670
3.60k
        PacketBuffer* lCursor = &sBufferPool[i].Header;
671
3.60k
        lCursor->next = lHead;
672
3.60k
        lCursor->ref = 0;
673
3.60k
        lHead = lCursor;
674
3.60k
    }
675
676
12
    Mutex::Init(sBufferPoolMutex);
677
678
12
    return lHead;
679
12
}
680
681
#endif //  !WEAVE_SYSTEM_CONFIG_USE_LWIP && WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
682
683
} // namespace System
684
} // namespace Weave
685
} // namespace nl