blob: fa21901c9ff302c68c8c1483063d5bac7a9bf010 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2016-2017 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file defines the chip::System::PacketBuffer class,
* which provides the mechanisms for manipulating packets of *
* octet-serialized data.
*/
#ifndef SYSTEMPACKETBUFFER_H
#define SYSTEMPACKETBUFFER_H
// Include configuration header
#include <system/SystemConfig.h>
// Include dependent headers
#include <support/DLLUtil.h>
#include <system/SystemAlignSize.h>
#include <system/SystemError.h>
#include <stddef.h>
#if CHIP_SYSTEM_CONFIG_USE_LWIP
#include <lwip/mem.h>
#include <lwip/memp.h>
#include <lwip/pbuf.h>
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
namespace chip {
namespace System {
#if !CHIP_SYSTEM_CONFIG_USE_LWIP
struct pbuf
{
struct pbuf * next;
void * payload;
uint16_t tot_len;
uint16_t len;
uint16_t ref;
#if CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0
uint16_t alloc_size;
#endif // CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0
};
#endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
/** @class PacketBuffer
*
* @brief
* The packet buffer class is the core structure used for manipulating packets of octet-serialized data, usually in the
* context of a data communications network, like Bluetooth or the Internet protocol.
*
* In LwIP-based environments, this class is built on top of the pbuf structure defined in that library. In the absence of
* LwIP, chip provides either a malloc-based implementation, or a pool-based implementation that closely approximates the
* memory challenges of deeply embedded devices.
*
* The PacketBuffer class, like many similar structures used in layered network stacks, provide a mechanism to reserve space
* for protocol headers at each layer of a configurable communication stack. For details, see `PacketBuffer::New()` as well
* as LwIP documentation.
*
* PacketBuffer objects are reference-counted, and the prevailing usage mode within chip is "fire-and-forget". As the packet
* (and its underlying PacketBuffer object) is dispatched through various protocol layers, the successful upcall or downcall
* between layers implies ownership transfer, and the callee is responsible for freeing the buffer. On failure of a
* cross-layer call, the responsibilty for freeing the buffer rests with the caller.
*
* New objects of PacketBuffer class are initialized at the beginning of an allocation of memory obtained from the underlying
* environment, e.g. from LwIP pbuf target pools, from the standard C library heap, from an internal buffer pool. In the
* simple case, the size of the data buffer is #CHIP_SYSTEM_PACKETBUFFER_SIZE. A composer is provided that permits usage of
* data buffers of other sizes.
*
* PacketBuffer objects may be chained to accomodate larger payloads. Chaining, however, is not transparent, and users of the
* class must explicitly decide to support chaining. Examples of classes written with chaining support are as follows:
*
* @ref chip::chipTLVReader
* @ref chip::chipTLVWriter
*
*/
class DLL_EXPORT PacketBuffer : private pbuf
{
public:
size_t AllocSize(void) const;
uint8_t * Start(void) const;
void SetStart(uint8_t * aNewStart);
uint16_t DataLength(void) const;
void SetDataLength(uint16_t aNewLen, PacketBuffer * aChainHead = NULL);
uint16_t TotalLength(void) const;
uint16_t MaxDataLength(void) const;
uint16_t AvailableDataLength(void) const;
uint16_t ReservedSize(void) const;
PacketBuffer * Next(void) const;
void AddToEnd(PacketBuffer * aPacket);
PacketBuffer * DetachTail(void);
void CompactHead(void);
PacketBuffer * Consume(uint16_t aConsumeLength);
void ConsumeHead(uint16_t aConsumeLength);
bool EnsureReservedSize(uint16_t aReservedSize);
bool AlignPayload(uint16_t aAlignBytes);
void AddRef(void);
static PacketBuffer * NewWithAvailableSize(size_t aAvailableSize);
static PacketBuffer * NewWithAvailableSize(uint16_t aReservedSize, size_t aAvailableSize);
static PacketBuffer * New(void);
static PacketBuffer * New(uint16_t aReservedSize);
static PacketBuffer * RightSize(PacketBuffer * aPacket);
static void Free(PacketBuffer * aPacket);
static PacketBuffer * FreeHead(PacketBuffer * aPacket);
private:
#if !CHIP_SYSTEM_CONFIG_USE_LWIP && CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
static PacketBuffer * sFreeList;
static PacketBuffer * BuildFreeList(void);
#endif // !CHIP_SYSTEM_CONFIG_USE_LWIP && CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
void Clear(void);
};
} // namespace System
} // namespace chip
// Sizing definitions
/**
* @def CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE
*
* The effective size of the packet buffer structure.
*
* TODO: This is an implementation details that does not need to be public and should be moved to the source file.
*/
#if CHIP_SYSTEM_CONFIG_USE_LWIP
#define CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(struct ::pbuf))
#else // CHIP_SYSTEM_CONFIG_USE_LWIP
#define CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE CHIP_SYSTEM_ALIGN_SIZE(sizeof(::chip::System::PacketBuffer), 4)
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
/**
* @def CHIP_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX
*
* See SystemConfig.h for full description. This is defined in here specifically for LwIP platform to preserve backwards
* compatibility.
*
* TODO: This is an implementation details that does not need to be public and should be moved to the source file.
*
*/
#if CHIP_SYSTEM_CONFIG_USE_LWIP
#define CHIP_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX (LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) - CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE)
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
/**
* @def CHIP_SYSTEM_PACKETBUFFER_SIZE
*
* The memory footprint of a PacketBuffer object, computed from max capacity size and the size of the packet buffer structure.
*
* TODO: This is an implementation details that does not need to be public and should be moved to the source file.
*/
#define CHIP_SYSTEM_PACKETBUFFER_SIZE (CHIP_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX + CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE)
namespace chip {
namespace System {
//
// Pool allocation for PacketBuffer objects (toll-free bridged with LwIP pbuf allocator if CHIP_SYSTEM_CONFIG_USE_LWIP)
//
#if !CHIP_SYSTEM_CONFIG_USE_LWIP && CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
typedef union
{
PacketBuffer Header;
uint8_t Block[CHIP_SYSTEM_PACKETBUFFER_SIZE];
} BufferPoolElement;
#endif // !CHIP_SYSTEM_CONFIG_USE_LWIP && CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC
/**
* Return the size of the allocation including the reserved and payload data spaces but not including space
* allocated for the PacketBuffer structure.
*
* @note The allocation size is equal or greater than \c aAllocSize paramater to \c Create method).
*
* @return size of the allocation
*/
inline size_t PacketBuffer::AllocSize(void) const
{
#if CHIP_SYSTEM_CONFIG_USE_LWIP
#if LWIP_PBUF_FROM_CUSTOM_POOLS
// Temporary workaround for custom pbufs by assuming size to be PBUF_POOL_BUFSIZE
if (this->flags & PBUF_FLAG_IS_CUSTOM)
return LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) - CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE;
else
return LWIP_MEM_ALIGN_SIZE(memp_sizes[this->pool]) - CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE;
#else // !LWIP_PBUF_FROM_CUSTOM_POOLS
return LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) - CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE;
#endif // !LWIP_PBUF_FROM_CUSTOM_POOLS
#else // !CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0
return static_cast<size_t>(this->alloc_size);
#else // CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC != 0
extern BufferPoolElement gDummyBufferPoolElement;
return sizeof(gDummyBufferPoolElement.Block) - CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE;
#endif // CHIP_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC != 0
#endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
}
} // namespace System
} // namespace chip
#endif // defined(SYSTEMPACKETBUFFER_H)