pbuf - the basic buffer in lwIP

The memory and buffer management system in a communication system must be prepared to accommodate buffers of very varying sizes, ranging from buffers containing full-sized TCP segments with several hundred bytes worth of data to short ICMP echo replies consisting of only a few bytes. Also, in order to avoid copying it should be possible to let the data content of the buffers reside in memory that is not managed by the networking subsystem, such as application memory or ROM.

A pbuf is lwIP’s internal representation of a packet, and is designed for the special needs of the minimal stack. Pbufs are similar to the mbufs used in the BSD implementations. The pbuf structure has support both for allocating dynamic memory to hold packet contents, and for letting packet data reside in static memory. Pbufs can be linked together in a list, called a pbuf chain so that a packet may span over several pbufs.

Allocating a new pbuf

To allocate a new pbuf, the application should call pbuf_alloc:

struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_flag flag)

There are three arguments to this function:

Typically, the user will use PBUF_RAM or PBUF_ROM pbuf's to construct new packets to send. Incoming pbuf's are often of the type PBUF_POOL and allocated by the device driver for its buffer management. Depending on your drivers, you may or may not want to use these types of buffers in your application.

In any case, when the user has finished with the pbuf, it must be free'd via pbuf_free. pbuf_free knows what kind of pbuf (PBUF_RAM, etc) the pbuf is and will free the payload as well if it can. For a PBUF_ROM, there is no payload to free, and in the PBUF_REF case, the stack cannot free the payload because it has no way to determine how to free the memory.

u8_t pbuf_free(struct pbuf *p)

The return value indicates how many pbuf's were actually free'd (a pbuf may not be immediately free'd if another part of the stack or program has also claimed responsibility for the pbuf by increasing its reference count... discussed in the next section).

Chains and the struct pbuf

The format of a PBUF_RAM
the format of a PBUF_RAM

struct pbuf {
struct pbuf *next;
void *payload;
u16_t total_len;
u16_t len;
u16_t flags;
u16_t ref;
}

The pbuf structure consistsof two pointers, two length fields, a flags field, and a reference count. The next field is a pointer to the next pbuf in caseof a pbuf chain. The payload pointer points to the start of the data in the pbuf. The len field contains the length of the data contents of the pbuf. The tot_len field of each pbuf contains the sum of the lengths of the current pbuf and all len fields of pbufs further down in
the pbuf chain.So, the total_len field of the first pbuf in a chain represents the total size of all the pbufs in the chain; the second pbuf's total_len is the sum of all the pbufs except the first; and, so forth, until the final pbuf, which has its total_len equal to len. The flags field indicates the type of the pbuf (e.g., PBUF_RAM) and the ref field contains a reference count used by pbuf_free.

The next and payload fields are native pointers and the size of those varies depending on the processor architecture used. The two length fields, flags field, and ref fields are 16 bit unsigned integers. The total size of the pbuf structure depends on the size of a pointer in the processor architecture being used. On an architecture with 32 bit pointers and 4 byte alignment, the total size is 16 bytes and on an architecture with 16 bit pointers and 1 byte alignment, the size is 12 bytes.

The pbuf module provides functions for manipulation of pbufs. Allocation of a pbuf is done by the function pbuf_alloc() which can allocate pbufs of any of the three types described above. The function pbuf_ref() increases the reference count. Deallocation is made by the function pbuf_free(), which first decreases the reference count of the pbuf. If the reference count reaches zero the pbuf is deallocated. The function pbuf_realloc() shrinks the pbuf so that it occupies just enough memory to cover the size of the data. The function pbuf_header() adjusts the payload pointer and the length fields so that a header can be prepended to the data in the pbuf. The functions pbuf_chain() and pbuf_dechain() are used for chaining pbufs.

An example pbuf chain

For example, a static packet of a web page that never changes could be stored in flash. This could be served by a pbuf chain of two pbufs: the first pbuf (a PBUF_RAM) to hold the TCP, IP, and link headers, chained to the second pbuf (a PBUF_ROM) pointing to the ROM data.

an example pbuf chain
An example pbuf chain: a PBUF_RAM for the headers of a packet based on a PBUF_ROM

Using the PBUF_REF type

[TODO] This should explain how to allocate, set, use, and properly free a PBUF_REF type.