Merge pull request #3496 from authmillenon/ng_pktbuf/enh/new_default

ng_pktbuf: new default packet buffer implementation
dev/timer
Martine Lenders 8 years ago
commit 3d9945667f

@ -218,6 +218,16 @@ ifneq (,$(filter ng_pktdump,$(USEMODULE)))
USEMODULE += od
endif
ifneq (,$(filter ng_pktbuf, $(USEMODULE)))
ifeq (,$(filter ng_pktbuf_%, $(USEMODULE)))
USEMODULE += ng_pktbuf_static
endif
endif
ifneq (,$(filter ng_pktbuf_%, $(USEMODULE)))
USEMODULE += ng_pktbuf # make MODULE_NG_PKTBUF macro available for all implementations
endif
ifneq (,$(filter ng_slip,$(USEMODULE)))
USEMODULE += ng_netbase
endif

@ -7,6 +7,7 @@ PSEUDOMODULES += ng_ipv6_router
PSEUDOMODULES += ng_ipv6_router_default
PSEUDOMODULES += pktqueue
PSEUDOMODULES += ng_netbase
PSEUDOMODULES += ng_pktbuf
PSEUDOMODULES += newlib
PSEUDOMODULES += ng_sixlowpan_default
PSEUDOMODULES += log

@ -113,8 +113,8 @@ endif
ifneq (,$(filter cipher_modes,$(USEMODULE)))
DIRS += crypto/modes
endif
ifneq (,$(filter ng_pktbuf,$(USEMODULE)))
DIRS += net/crosslayer/ng_pktbuf
ifneq (,$(filter ng_pktbuf_static,$(USEMODULE)))
DIRS += net/crosslayer/ng_pktbuf_static
endif
ifneq (,$(filter ng_zep,$(USEMODULE)))
DIRS += net/application_layer/ng_zep

@ -99,6 +99,10 @@
#include "l2_ping.h"
#endif
#ifdef MODULE_NG_PKTBUF
#include "net/ng_pktbuf.h"
#endif
#ifdef MODULE_NG_PKTDUMP
#include "net/ng_pktdump.h"
#endif
@ -305,6 +309,10 @@ void auto_init(void)
DEBUG("Auto init transport layer module: [tcp].\n");
tcp_init_transport_layer();
#endif
#ifdef MODULE_NG_PKTBUF
DEBUG("Auto init ng_pktbuf module\n");
ng_pktbuf_init();
#endif
#ifdef MODULE_NG_PKTDUMP
DEBUG("Auto init ng_pktdump module.\n");
ng_pktdump_init();

@ -56,34 +56,37 @@ extern "C" {
#define NG_PKTBUF_SIZE (6144)
#endif /* NG_PKTBUF_SIZE */
/**
* @brief Initializes packet buffer module.
*/
void ng_pktbuf_init(void);
/**
* @brief Adds a new ng_pktsnip_t and its packet to the packet buffer.
*
* @details This function is very powerful and reflects the unique characterics
* of ng_pktsnip_t of being reversed for either the sending or
* receiving context. Because of this the assumtion of the transmission
* direction, the state of the packet buffer and the values for the
* members of the resulting ng_pktsnip_t can be very different after
* execution of this function depending on what parameters you use:
*
* * The return value of this function is a @ref ng_pktsnip_t struct referred
* to as `result`
* * for most cases the build-up of `result` will be pretty straight forward: Its
* members will be exactly as the given parameters (ng_pktsnip_t::next of
* result will be set to @p pkt). If @p pkt is not NULL it and in turn `result`
* are assumed to be in sending direction. For packet creation (@p pkt == NULL)
* no assumtions about direction of `result` will be made (since its
* ng_pktsnip::next will be set to NULL).
* * if @p pkt != NULL, @p data = `pkt->data`, @p size < `pkt->size` receiving
* direction is assumed and the following values will be set:
* * ng_pktsnip_t::next of `result` = `pkt->next`
* * ng_pktsnip_t::data of `result` = @p data
* * ng_pktsnip_t::size of `result` = @p size
* * ng_pktsnip_t::next of @p pkt = `result`
* * ng_pktsnip_t::data of @p pkt = @p data + @p size
* * ng_pktsnip_t::size of @p pkt = old size value - @p size
*
* graphically this can be represented as follows:
* @warning **Do not** change the fields of the ng_pktsnip_t created by this
* function externally. This will most likely create memory leaks or
* not allowed memory access.
*
* @param[in] next Next ng_pktsnip_t in the packet. Leave NULL if you
* want to create a new packet.
* @param[in] data Data of the new ng_pktsnip_t. If @p data is NULL no data
* will be inserted into `result`.
* @param[in] size Length of @p data. May not be 0.
* @param[in] type Protocol type of the ng_pktsnip_t.
*
* @return Pointer to the packet part that represents the new ng_pktsnip_t.
* @return NULL, if no space is left in the packet buffer.
* @return NULL, if @p size == 0.
*/
ng_pktsnip_t *ng_pktbuf_add(ng_pktsnip_t *next, void *data, size_t size,
ng_nettype_t type);
/**
* @brief Marks the first @p size bytes in a received packet with a new
* packet snip that is appended to the packet.
*
* Graphically this can be represented as follows:
* @code
* Before After
* ====== =====
@ -95,36 +98,23 @@ extern "C" {
* \__________pkt->size___________/ \_result->size_/ \__pkt->size__/
* @endcode
*
* @note **Do not** change the ng_pktsnip_t::data and ng_pktsnip_t::size
* of a ng_pktsnip_t created by this function externally, except if
* they both are null or data is not from inside the packet buffer.
* This will most likely create memory leaks.
* @pre @p pkt != NULL && @p size != 0
*
* @param[in,out] pkt The packet you want to add a ng_pktsnip_t to. Leave
* NULL if you want to create a new packet. Members may
* change values; see above.
* @param[in] data Data of the new ng_pktsnip_t. If @p data is NULL no data
* will be inserted into `result`. If @p data is already
* in the packet buffer (e.g. a payload of an already
* allocated packet) it will not be duplicated.
* @param[in] size Length of @p data. If @p size is 0 no data will be inserted
* into the the packet buffer and ng_pktsnip_t::data will be
* set to @p data.
* @param[in] type Protocol type of the ng_pktsnip_t.
* @param[in] pkt A received packet.
* @param[in] size The size of the new packet snip.
* @param[in] type The type of the new packet snip.
*
* @return Pointer to the packet part that represents the new ng_pktsnip_t.
* @return The new packet snip in @p pkt on success.
* @return NULL, if pkt == NULL or size == 0 or size > pkt->size or pkt->data == NULL.
* @return NULL, if no space is left in the packet buffer.
* @return NULL, if @p pkt != NULL, @p data = `pkt->data`,
* and @p size > `pkt->data`.
*/
ng_pktsnip_t *ng_pktbuf_add(ng_pktsnip_t *pkt, void *data, size_t size,
ng_nettype_t type);
ng_pktsnip_t *ng_pktbuf_mark(ng_pktsnip_t *pkt, size_t size, ng_nettype_t type);
/**
* @brief Reallocates ng_pktsnip_t::data of @p pkt in the packet buffer, without
* changing the content.
*
* @pre `pkt->users == 1 && pkt->next == NULL` and @p pkt must be in packet buffer
* @pre ng_pktsnip_t::data of @p pkt is in the packet buffer.
*
* @details If enough memory is available behind it or @p size is smaller than
* the original size the packet then ng_pktsnip_t::data of @p pkt will
@ -135,8 +125,6 @@ ng_pktsnip_t *ng_pktbuf_add(ng_pktsnip_t *pkt, void *data, size_t size,
* @param[in] size The size for @p pkt.
*
* @return 0, on success
* @return EINVAL, if precondition is not met
* @return ENOENT, if ng_pktsnip_t::data of @p pkt was not from the packet buffer.
* @return ENOMEM, if no space is left in the packet buffer or size was 0.
*/
int ng_pktbuf_realloc_data(ng_pktsnip_t *pkt, size_t size);
@ -182,7 +170,7 @@ ng_pktsnip_t *ng_pktbuf_start_write(ng_pktsnip_t *pkt);
* @return The new reference to @p pkt.
*/
static inline ng_pktsnip_t *ng_pktbuf_remove_snip(ng_pktsnip_t *pkt,
ng_pktsnip_t *snip)
ng_pktsnip_t *snip)
{
LL_DELETE(pkt, snip);
snip->next = NULL;
@ -213,9 +201,12 @@ void ng_pktbuf_stats(void);
bool ng_pktbuf_is_empty(void);
/**
* @brief Resets the whole packet buffer
* @brief Checks if the implenation's internal invariants still uphold
*
* @return true, the packet buffer is sane.
* @return false, the packet buffer is insane.
*/
void ng_pktbuf_reset(void);
bool ng_pktbuf_is_sane(void);
#endif
#ifdef __cplusplus

@ -724,7 +724,7 @@ static ng_pktsnip_t *_create_received(ng_zep_t *dev, ng_pktsnip_t *pkt,
return NULL;
}
payload = ng_pktbuf_add(pkt, pkt->data, pkt->size - 2, dev->proto);
payload = ng_pktbuf_mark(pkt, pkt->size - 2, dev->proto);
if (payload == NULL) {
return NULL;
@ -738,7 +738,7 @@ static ng_pktsnip_t *_create_received(ng_zep_t *dev, ng_pktsnip_t *pkt,
return NULL;
}
mhr = ng_pktbuf_add(pkt, pkt->data, mhr_len, NG_NETTYPE_UNDEF);
mhr = ng_pktbuf_mark(pkt, mhr_len, NG_NETTYPE_UNDEF);
/* TODO: send ACK */
@ -772,7 +772,7 @@ static ng_pktsnip_t *_recv_v1(ng_zep_t *dev, ng_pktsnip_t *pkt)
return NULL;
}
zep = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_zep_v1_hdr_t), NG_NETTYPE_UNDEF);
zep = ng_pktbuf_mark(pkt, sizeof(ng_zep_v1_hdr_t), NG_NETTYPE_UNDEF);
if (zep == NULL) {
return NULL;
@ -803,7 +803,7 @@ static ng_pktsnip_t *_recv_v2(ng_zep_t *dev, ng_pktsnip_t *pkt)
return NULL;
}
zep = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_zep_v2_data_hdr_t), NG_NETTYPE_UNDEF);
zep = ng_pktbuf_mark(pkt, sizeof(ng_zep_v2_data_hdr_t), NG_NETTYPE_UNDEF);
if (zep == NULL) {
return NULL;

@ -1,299 +0,0 @@
/*
* Copyright (C) 2015 Martin Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_ng_pktbuf
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <stdbool.h>
#include <stdlib.h>
#include "_pktbuf_internal.h"
#include "net/ng_pktbuf.h"
#include "utlist.h"
#if NG_PKTBUF_SIZE == 0
/* chunk table to allow for free(ptr + x)-like behaviour */
typedef struct __attribute__((packed)) _chunk_list_t {
struct _chunk_list_t *next;
uint8_t *ptr;
} _chunk_list_t;
typedef struct __attribute__((packed)) _chunk_table_t {
struct _chunk_table_t *next;
uint8_t *range_start;
size_t range_len;
_chunk_list_t *chunks;
uint8_t used;
} _chunk_table_t;
static _chunk_table_t *_chunk_table = NULL;
/* this organizes chunks, since free(ptr + x) is not possible on most platforms */
static _chunk_table_t *_create_table_entry(void *pkt, size_t size);
static _chunk_table_t *_find_chunk(const uint8_t *chunk, _chunk_table_t **prev,
_chunk_list_t **node_res);
static inline bool _in_range(_chunk_table_t *entry, uint8_t *ptr);
void *_pktbuf_internal_alloc(size_t size)
{
_chunk_table_t *entry;
void *data;
if (size == 0) {
return 0;
}
data = malloc(size);
if (data == NULL) {
return NULL;
}
entry = _create_table_entry(data, size);
if (entry == NULL) {
free(data);
return NULL;
}
/* cppcheck-suppress memleak entry will be freed eventually in _pktbuf_internal_free().
* Checked with valgrind. */
return data;
}
void *_pktbuf_internal_realloc(void *ptr, size_t size)
{
_chunk_list_t *node = NULL;
void *new_value = NULL;
_chunk_table_t *entry;
if (size == 0) {
return NULL;
}
entry = _find_chunk(ptr, NULL, &node);
/* entry can't be NULL since prelimanary _pktbuf_internal_contains() check ensures that */
if ((ptr == entry->range_start) && (entry->chunks == NULL)) {
new_value = realloc(entry->range_start, size);
if (new_value == NULL) {
return NULL;
}
entry->range_start = new_value;
entry->range_len = size;
}
else {
size_t range_len = entry->range_len;
if (node != NULL) {
range_len -= (node->ptr - entry->range_start);
}
new_value = malloc(size);
if (new_value == NULL) {
return NULL;
}
entry = _create_table_entry(new_value, size);
if (entry == NULL) {
free(new_value);
return NULL;
}
memcpy(new_value, ptr, (size < range_len) ? size : range_len);
_pktbuf_internal_free(ptr);
}
return new_value;
/* cppcheck-suppress memleak entry will be freed eventually in _pktbuf_internal_free().
* Checked with valgrind. */
}
bool _pktbuf_internal_add_pkt(void *ptr)
{
_chunk_table_t *entry = _chunk_table;
while (entry != NULL) {
if (_in_range(entry, ptr)) {
_chunk_list_t *node = malloc(sizeof(_chunk_list_t));
if (node == NULL) {
return false;
}
node->ptr = ptr;
LL_PREPEND(entry->chunks, node);
return true;
}
entry = entry->next;
}
return false;
}
void _pktbuf_internal_free(void *ptr)
{
_chunk_list_t *node = NULL;
_chunk_table_t *prev = NULL, *entry = _find_chunk(ptr, &prev, &node);
if (node != NULL) {
LL_DELETE(entry->chunks, node);
free(node);
}
else if (entry->range_start == ptr) {
entry->used = 0;
}
if (entry->chunks == NULL && entry->used == 0) {
if (prev == NULL) {
if (entry->next == NULL) {
_chunk_table = NULL;
}
else {
_chunk_table = entry->next;
}
}
else {
prev->next = entry->next;
}
free(entry->range_start);
free(entry);
}
}
bool _pktbuf_internal_contains(const void *ptr)
{
return (_find_chunk(ptr, NULL, NULL) != NULL);
}
#ifdef DEVELHELP
void _pktbuf_internal_stats(void)
{
printf("Dynamic packet buffer\n");
}
#endif
#ifdef TEST_SUITES
bool _pktbuf_internal_is_empty(void)
{
return (_chunk_table == NULL);
}
void _pktbuf_internal_reset(void)
{
_chunk_table_t *entry = _chunk_table;
while (entry != NULL) {
_chunk_table_t *next = entry->next;
_chunk_list_t *node = entry->chunks;
free(entry->range_start);
while (entry->chunks != NULL) {
LL_DELETE(entry->chunks, node);
free(node);
}
free(entry);
entry = next;
}
_chunk_table = NULL;
}
#endif
static _chunk_table_t *_create_table_entry(void *data, size_t size)
{
_chunk_table_t *entry = (_chunk_table_t *)malloc(sizeof(_chunk_table_t));
if (entry == NULL) {
return NULL;
}
if (_chunk_table == NULL) {
entry->next = NULL;
_chunk_table = entry;
}
else {
entry->next = _chunk_table;
_chunk_table = entry;
}
entry->range_start = data;
entry->range_len = size;
entry->chunks = NULL;
entry->used = 1;
return entry;
}
static _chunk_table_t *_find_chunk(const uint8_t *chunk, _chunk_table_t **prev,
_chunk_list_t **node_res)
{
_chunk_table_t *entry = _chunk_table;
if (prev != NULL) {
*prev = NULL;
}
while (entry != NULL) {
_chunk_list_t *node = entry->chunks;
if (entry->range_start == chunk) {
if (node_res != NULL) {
*node_res = NULL;
}
return entry;
}
while (node != NULL) {
if (node->ptr == chunk) {
if (node_res != NULL) {
*node_res = node;
}
return entry;
}
node = node->next;
}
if (prev != NULL) {
*prev = entry;
}
entry = entry->next;
}
return NULL;
}
static inline bool _in_range(_chunk_table_t *entry, uint8_t *ptr)
{
return (entry != NULL) &&
(ptr >= entry->range_start) &&
(ptr < (entry->range_start + entry->range_len));
}
#endif
/** @} */

@ -1,107 +0,0 @@
/*
* Copyright (C) 2015 Martin Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_ng_pktbuf
* @{
*
* @file
* @brief Internal definitions for the packet buffer
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef XPKTBUF_INTERNAL_H_
#define XPKTBUF_INTERNAL_H_
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Internal alloc on packet buffer
*
* @internal
*
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html">
* malloc()
* </a>
*/
void *_pktbuf_internal_alloc(size_t size);
/**
* @brief Internal realloc on static packet buffer
*
* @internal
*
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html">
* realloc()
* </a>
*/
void *_pktbuf_internal_realloc(void *ptr, size_t size);
/**
* @brief Adds packet that uses @p ptr for its data part
*
* @internal
*/
bool _pktbuf_internal_add_pkt(void *ptr);
/**
* @brief Internal free on static packet buffer
*
* @internal
*
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">
* free()
* </a> but @p ptr can be anywhere in alloced space.
*/
void _pktbuf_internal_free(void *ptr);
/**
* @brief Checks if a pointer is part of the static packet buffer.
*
* @param[in] ptr A pointer.
*
* @return true, if @p ptr is part of the static packet buffer.
* @return false, if @p ptr is not part of the static packet buffer.
*/
bool _pktbuf_internal_contains(const void *ptr);
#ifdef DEVELHELP
/**
* @brief Prints some statistics about the packet buffer to stdout.
*
* @details Statistics include maximum number of reserved bytes.
*/
void _pktbuf_internal_stats(void);
#endif
/* for testing */
#ifdef TEST_SUITES
/**
* @brief Checks if packet buffer is empty
*
* @return 1, if packet buffer is empty
* @return 0, if packet buffer is not empty
*/
bool _pktbuf_internal_is_empty(void);
/**
* @brief Sets the whole packet buffer to 0
*/
void _pktbuf_internal_reset(void);
#endif /* TEST_SUITES */
#ifdef __cplusplus
}
#endif
#endif /* XPKTBUF_INTERNAL_H_ */
/** @} */

@ -1,318 +0,0 @@
/*
* Copyright (C) 2015 Martin Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_ng_pktbuf
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "od.h"
#include "net/ng_pktbuf.h"
#include "_pktbuf_internal.h"
/* only for static packet buffer */
#if NG_PKTBUF_SIZE > 0
#define _PKTBUF_ALIGN_BYTES (sizeof(void *))
#ifdef DEVELHELP
static unsigned int _pktbuf_max_bytes = 0;
#endif
/**
* @brief Data type to represent used chunks in packet buffer.
*/
typedef struct __attribute__((packed)) _used_t {
struct _used_t *next;
uint16_t size;
uint8_t pkts;
uint8_t _align; /* alignment */
} _used_t;
static uint8_t _buf[NG_PKTBUF_SIZE];
/**
* @brief Get first element in buffer
*/
static inline _used_t *_head(void)
{
return (_used_t *)_buf;
}
/**
* @brief Get data part (memory behind `_used_t` descriptive header) of a packet
*/
static inline void *_data(_used_t *node)
{
return (void *)(((_used_t *)node) + 1);
}
static inline void *_data_end(_used_t *node)
{
return (void *)(((uint8_t *)_data(node)) + node->size);
}
static inline bool _in_data_range(_used_t *node, const void *ptr)
{
return (ptr >= _data(node)) && (ptr < _data_end(node));
}
/**
* @brief Size with metadata of allocation
*/
static inline size_t _total_sz(uint16_t sz)
{
return sizeof(_used_t) + sz;
}
/**
* @brief _used_t typed alias for _total_sz
*/
static inline size_t __total_sz(_used_t *node)
{
return _total_sz(node->size);
}
/**
* @brief aligns @p size to the next word alignment.
*/
static inline size_t _al_sz(size_t size)
{
if (size % _PKTBUF_ALIGN_BYTES) {
return size + (_PKTBUF_ALIGN_BYTES - (size % _PKTBUF_ALIGN_BYTES));
}
else {
return size;
}
}
/**
* @brief aligned size with metadata
*/
static inline size_t __al_total_sz(_used_t *node)
{
return _al_sz(__total_sz(node));
}
/**
* @brief Index of an allocation's first byte in buffer
*/
static inline unsigned int _start_idx(_used_t *node)
{
return (int)(((uint8_t *)node) - _buf);
}
/**
* @brief Index of an allocation's last byte in buffer
*/
static inline unsigned int _end_idx(_used_t *node)
{
return _start_idx(node) + __total_sz(node) - 1;
}
static _used_t *_find(_used_t **prev_ptr, _used_t **node_ptr, const void *ptr)
{
_used_t *node = _head(), *prev = NULL;
if (ptr != NULL) {
while (node != NULL) {
if (_in_data_range(node, ptr)) {
*prev_ptr = prev;
*node_ptr = node;
return node;
}
prev = node;
node = (_used_t *)node->next;
}
}
*prev_ptr = NULL;
*node_ptr = NULL;
return NULL;
}
/**
* @brief Allocate chunk of @p size in _buf
*/
void *_pktbuf_internal_alloc(size_t size)
{
_used_t *node = _head(), *old_next, *new_next;
if ((size == 0) || (size > NG_PKTBUF_SIZE)) {
return NULL;
}
if (node->size == 0) { /* if head is currently not initialized */
if (node->next == NULL || (_start_idx(node->next) >= _total_sz(size))) {
/* if enough space is there */
node->size = size; /* just take it */
node->pkts = 1;
return _data(node);
}
else if (node->next != NULL) {
/* else go directly to next allocation if it exists */
node = node->next;
}
}
while ((node->next != NULL) /* while not last chunk allocation */
/* and if space between current and next allocation is not big enough */
&& ((_start_idx(node->next) - _end_idx(node)) < _al_sz(_total_sz(size)))) {
node = node->next;
}
/* jump ahead size of current packet */
new_next = (_used_t *)(((uint8_t *)node) + __al_total_sz(node));
if ((((uint8_t *)new_next) + size) > (((uint8_t *)_head()) + NG_PKTBUF_SIZE)) {
/* new packet does not fit into _pktbuf */
return NULL;
}
old_next = node->next;
node->next = new_next;
node->next->next = old_next;
node = new_next;
node->size = size;
node->pkts = 1;
#ifdef DEVELHELP
if ((_end_idx(node) + 1) > _pktbuf_max_bytes) {
_pktbuf_max_bytes = _end_idx(node) + 1;
}
#endif
return _data(node);
}
bool _pktbuf_internal_add_pkt(void *ptr)
{
_used_t *prev, *node;
if (_find(&prev, &node, ptr) != NULL) {
(node->pkts)++;
return true;
}
return false;
}
static inline void _free_helper(_used_t *prev, _used_t *node)
{
if ((--(node->pkts)) == 0) {
if (prev == NULL) {
node->size = 0;
}
else {
prev->next = node->next;
}
}
}
void _pktbuf_internal_free(void *ptr)
{
_used_t *prev, *node;
if (_find(&prev, &node, ptr) != NULL) {
_free_helper(prev, node);
}
}
void *_pktbuf_internal_realloc(void *ptr, size_t size)
{
_used_t *new, *prev, *orig = NULL;
if ((size == 0) || (size > NG_PKTBUF_SIZE)) {
return NULL;
}
_find(&prev, &orig, ptr);
if ((orig != NULL) &&
((orig->size >= size) /* size in orig is sufficient */
|| ((orig->next == NULL) /* or orig is last packet and buffer space is sufficient */
&& ((_start_idx(orig) + _total_sz(size)) < NG_PKTBUF_SIZE))
|| ((orig->next != NULL) /* or space between orig and orig->next is sufficient */
&& ((_start_idx(orig->next) - _start_idx(orig)) >= _total_sz(size))))) {
orig->size = size;
return ptr;
}
new = _pktbuf_internal_alloc(size);
if (new != NULL) {
if (orig != NULL) {
memcpy(_data(new), ptr, (orig->size < size) ? orig->size : size);
_free_helper(prev, orig);
}
return _data(new);
}
return NULL;
}
bool _pktbuf_internal_contains(const void *ptr)
{
return ((_buf < ((uint8_t *)ptr)) && (((uint8_t *)ptr) <= &(_buf[NG_PKTBUF_SIZE - 1])));
}
#ifdef DEVELHELP
void _pktbuf_internal_stats(void)
{
_used_t *ptr = _head();
printf("== Static packet buffer ==\n");
printf("--- Maximum number of reserved bytes: %u ---\n", _pktbuf_max_bytes);
while (ptr) {
printf("**** %p: next: %p, size: %" PRIu16 ", pkts: %" PRIu8 " ****\n",
(void *)ptr, (void *)ptr->next, ptr->size, ptr->pkts);
od_hex_dump(_data(ptr), ptr->size, OD_WIDTH_DEFAULT);
puts("");
ptr = ptr->next;
}
}
#endif
/* for testing */
#ifdef TEST_SUITES
bool _pktbuf_internal_is_empty(void)
{
return ((_head()->next == NULL) && (_head()->size == 0));
}
void _pktbuf_internal_reset(void)
{
_head()->next = NULL;
_head()->size = 0;
#ifdef DEVELHELP
_pktbuf_max_bytes = 0;
#endif
}
#endif /* TEST_SUITES */
#endif /* NG_PKTBUF_SIZE > 0 */
/** @} */

@ -1,350 +0,0 @@
/*
* Copyright (C) 2014 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_ng_pktbuf
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "clist.h"
#include "mutex.h"
#include "utlist.h"
#include "net/ng_pktbuf.h"
#include "net/ng_nettype.h"
#include "net/ng_pkt.h"
#include "_pktbuf_internal.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static mutex_t _pktbuf_mutex = MUTEX_INIT;
/* internal ng_pktbuf functions */
static ng_pktsnip_t *_pktbuf_alloc(size_t size);
static ng_pktsnip_t *_pktbuf_add_unsafe(ng_pktsnip_t *pkt, void *data,
size_t size, ng_nettype_t type);
static ng_pktsnip_t *_pktbuf_duplicate(const ng_pktsnip_t *pkt);
int ng_pktbuf_realloc_data(ng_pktsnip_t *pkt, size_t size)
{
void *new;
if (pkt == NULL || !_pktbuf_internal_contains(pkt->data)) {
DEBUG("pktbuf: (pkt = %p) not in packet buffer\n", (void *)pkt);
return ENOENT;
}
if (pkt->users > 1 || pkt->next != NULL) {
DEBUG("pktbuf: more than one user (%u) or pkt->next != NULL (%p)\n",
pkt->users, (void *)pkt->next);
return EINVAL;
}
mutex_lock(&_pktbuf_mutex);
new = _pktbuf_internal_realloc(pkt->data, size);
mutex_unlock(&_pktbuf_mutex);
if (new == NULL) {
DEBUG("pktbuf: no buffer space for realloc left\n");
return ENOMEM;
}
pkt->data = new;
pkt->size = size;
return 0;
}
ng_pktsnip_t *ng_pktbuf_add(ng_pktsnip_t *pkt, void *data, size_t size,
ng_nettype_t type)
{
ng_pktsnip_t *new_pktsnip;
mutex_lock(&_pktbuf_mutex);
new_pktsnip = _pktbuf_add_unsafe(pkt, data, size, type);
mutex_unlock(&_pktbuf_mutex);
return new_pktsnip;
}
void ng_pktbuf_hold(ng_pktsnip_t *pkt, unsigned int num)
{
if ((pkt == NULL) || (num == 0)) {
return;
}
mutex_lock(&_pktbuf_mutex);
while (pkt != NULL) {
DEBUG("pktbuf: hold (pkt = %p) %u times\n", (void *)pkt, num);
pkt->users += num;
pkt = pkt->next;
}
mutex_unlock(&_pktbuf_mutex);
}
void ng_pktbuf_release(ng_pktsnip_t *pkt)
{
if (pkt == NULL) {
return;
}
mutex_lock(&_pktbuf_mutex);
while (pkt != NULL) {
if (pkt->users > 0) { /* Don't accidentally overshoot */
DEBUG("pktbuf: release (pkt = %p)\n", (void *)pkt);
pkt->users--;
}
if (pkt->users == 0) {
if (_pktbuf_internal_contains(pkt->data)) {
DEBUG("pktbuf: free pkt->data = %p\n", pkt->data);
_pktbuf_internal_free(pkt->data);
}
if (_pktbuf_internal_contains(pkt)) {
DEBUG("pktbuf: free pkt = %p\n", (void *)pkt);
_pktbuf_internal_free(pkt);
}
}
pkt = pkt->next;
}
mutex_unlock(&_pktbuf_mutex);
}
ng_pktsnip_t *ng_pktbuf_start_write(ng_pktsnip_t *pkt)
{
if (pkt != NULL && pkt->users > 1) {
ng_pktsnip_t *res = NULL;
mutex_lock(&_pktbuf_mutex);
DEBUG("pktbuf: pkt->users = %u => copy-on-write\n", pkt->users);
res = _pktbuf_duplicate(pkt);
DEBUG("pktbuf: copy-on-write result: (pkt = %p) copied to (res = %p)\n",
(void *)pkt, (void *)res);
pkt->users--;
mutex_unlock(&_pktbuf_mutex);
return res;
}
return pkt;
}
/***********************************
* internal ng_pktbuf functions *
***********************************/
static ng_pktsnip_t *_pktbuf_alloc(size_t size)
{
ng_pktsnip_t *pkt;
pkt = (ng_pktsnip_t *)_pktbuf_internal_alloc(sizeof(ng_pktsnip_t));
DEBUG("pktbuf: allocated (pkt = %p) ", (void *)pkt);
if (pkt == NULL) {
DEBUG("=> failed\n");
return NULL;
}
DEBUG("of size %u\n", (unsigned)sizeof(ng_pktsnip_t));
pkt->data = _pktbuf_internal_alloc(size);
DEBUG("pktbuf: allocated (pkt->data = %p) ", pkt->data);
if (pkt->data == NULL) {
_pktbuf_internal_free(pkt);
DEBUG("=> failed (freeing %p)\n", (void *)pkt);
return NULL;
}
DEBUG("of size %u\n", (unsigned)size);
pkt->next = NULL;
pkt->size = size;
pkt->users = 1;
return pkt;
}
static ng_pktsnip_t *_pktbuf_add_unsafe(ng_pktsnip_t *pkt, void *data,
size_t size, ng_nettype_t type)
{
ng_pktsnip_t *new_pktsnip;
if (pkt == NULL || pkt->data != data) {
new_pktsnip = (ng_pktsnip_t *)_pktbuf_internal_alloc(sizeof(ng_pktsnip_t));
DEBUG("pktbuf: allocated (new_pktsnip = %p) ", (void *)new_pktsnip);
if (new_pktsnip == NULL) {
DEBUG("=> failed\n");
return NULL;
}
DEBUG("of size %u\n", (unsigned)sizeof(ng_pktsnip_t));
if ((size != 0) && (!_pktbuf_internal_contains(data))) {
new_pktsnip->data = _pktbuf_internal_alloc(size);
DEBUG("pktbuf: allocated (new_pktsnip->data = %p) ", new_pktsnip->data);
if (new_pktsnip->data == NULL) {
_pktbuf_internal_free(new_pktsnip);
DEBUG("=> failed (freeing %p)\n", (void *)pkt);
return NULL;
}
DEBUG("of size %u\n", (unsigned)size);
if (data != NULL) {
DEBUG("pktbuf: copying %u byte from %p to %p\n", (unsigned)size,
data, new_pktsnip->data);
memcpy(new_pktsnip->data, data, size);
}
}
else {
if (_pktbuf_internal_contains(data)) {
DEBUG("pktbuf: Adding chunk to %p ", new_pktsnip->data);
if (!_pktbuf_internal_add_pkt(new_pktsnip->data)) {
_pktbuf_internal_free(new_pktsnip);
DEBUG("failed (freeing %p)\n", (void *)pkt);
return NULL;
}
DEBUG("successful\n");
}
new_pktsnip->data = data;
DEBUG("pktbuf: set new_pktsnip->data = %p\n", new_pktsnip->data);
}
new_pktsnip->next = NULL;
LL_PREPEND(pkt, new_pktsnip);
DEBUG("pktbuf: prepended new_pktsnip to pkt\n");
}
else {
if (size > pkt->size) {
DEBUG("pktbuf: new size (%u) out of pkt's boundaries (pkt->size = %u)",
(unsigned)size, (unsigned)pkt->size);
return NULL;
}
if (size == pkt->size) {
DEBUG("pktbuf: size (%u) == pkt->size (%u) => just set new packet "
"type and return\n", (unsigned)size, (unsigned)pkt->size);
pkt->type = type;
return pkt;
}
new_pktsnip = (ng_pktsnip_t *)_pktbuf_internal_alloc(sizeof(ng_pktsnip_t));
DEBUG("pktbuf: allocated (new_pktsnip = %p) ", (void *)new_pktsnip);
if (new_pktsnip == NULL) {
DEBUG("=> failed\n");
return NULL;
}
DEBUG("of size %u\n", (unsigned)sizeof(ng_pktsnip_t));
DEBUG("pktbuf: Adding chunk to %p ", pkt->data);
if (!_pktbuf_internal_add_pkt(pkt->data)) {
DEBUG("failed (freeing %p)\n", (void *)new_pktsnip);
_pktbuf_internal_free(new_pktsnip);
return NULL;
}
DEBUG("successful\n");
new_pktsnip->next = pkt->next;
new_pktsnip->data = data;
DEBUG("pktbuf: set new_pktsnip->data = %p\n", new_pktsnip->data);
DEBUG("pktbuf: add new_pktsnip (%p) to pkt (%p) after head\n",
(void *)new_pktsnip, (void *)pkt);
pkt->next = new_pktsnip;
pkt->size -= size;
DEBUG("pktbuf: resize pkt->size to %u\n", (unsigned)pkt->size);
pkt->data = (void *)(((uint8_t *)pkt->data) + size);
DEBUG("pktbuf: move pkt->data to %p\n", pkt->data);
}
new_pktsnip->size = size;
new_pktsnip->type = type;
new_pktsnip->users = 1;
DEBUG("pktbuf: summary of new snip %p: next = %p, data = %p, size = %u, "
"type = %d, users: %u\n", (void *)new_pktsnip, (void *)new_pktsnip->next,
new_pktsnip->data, (unsigned)new_pktsnip->size, new_pktsnip->type,
new_pktsnip->users);
return new_pktsnip;
}
static ng_pktsnip_t *_pktbuf_duplicate(const ng_pktsnip_t *pkt)
{
ng_pktsnip_t *res = NULL;
res = _pktbuf_alloc(pkt->size);
if (res == NULL) {
return NULL;
}
DEBUG("pktbuf: copying %u byte from %p to %p\n", (unsigned)pkt->size,
pkt->data, res->data);
memcpy(res->data, pkt->data, pkt->size);
res->type = pkt->type;
res->next = pkt->next;
DEBUG("pktbuf: set res->next to %p", (void *)pkt->next);
return res;
}
#ifdef DEVELHELP
void ng_pktbuf_stats(void)
{
_pktbuf_internal_stats();
}
#endif
#ifdef TEST_SUITES
bool ng_pktbuf_is_empty(void)
{
return _pktbuf_internal_is_empty();
}
void ng_pktbuf_reset(void)
{
_pktbuf_internal_reset();
}
#endif
/** @} */

@ -0,0 +1,430 @@
/*
* Copyright (C) 2014 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_ng_pktbuf
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include "mutex.h"
#include "od.h"
#include "utlist.h"
#include "net/ng_pktbuf.h"
#include "net/ng_nettype.h"
#include "net/ng_pkt.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define _ALIGNMENT_MASK (sizeof(void *) - 1)
typedef struct _unused {
struct _unused *next;
unsigned int size;
} _unused_t;
static mutex_t _mutex = MUTEX_INIT;
static uint8_t _pktbuf[NG_PKTBUF_SIZE];
static _unused_t *_first_unused;
/* internal ng_pktbuf functions */
static ng_pktsnip_t *_create_snip(ng_pktsnip_t *next, void *data, size_t size,
ng_nettype_t type);
static void *_pktbuf_alloc(size_t size);
static void _pktbuf_free(void *data, size_t size);
static inline bool _pktbuf_contains(void *ptr)
{
return (&_pktbuf[0] <= (uint8_t *)ptr) &&
((uint8_t *)ptr <= &_pktbuf[NG_PKTBUF_SIZE - 1]);
}
/* fits size to byte alignment */
static inline size_t _align(size_t size)
{
return ((size + _ALIGNMENT_MASK) & ~(_ALIGNMENT_MASK));
}
void ng_pktbuf_init(void)
{
mutex_lock(&_mutex);
_first_unused = (_unused_t *)_pktbuf;
_first_unused->next = NULL;
_first_unused->size = sizeof(_pktbuf);
mutex_unlock(&_mutex);
}
ng_pktsnip_t *ng_pktbuf_add(ng_pktsnip_t *next, void *data, size_t size,
ng_nettype_t type)
{
ng_pktsnip_t *pkt;
if ((size == 0) || (size > NG_PKTBUF_SIZE)) {
DEBUG("pktbuf: size (%u) == 0 || size == NG_PKTBUF_SIZE (%u)\n",
(unsigned)size, NG_PKTBUF_SIZE);
return NULL;
}
mutex_lock(&_mutex);
pkt = _create_snip(next, data, size, type);
mutex_unlock(&_mutex);
return pkt;
}
ng_pktsnip_t *ng_pktbuf_mark(ng_pktsnip_t *pkt, size_t size, ng_nettype_t type)
{
ng_pktsnip_t *marked_snip;
/* size required for chunk */
size_t required_new_size = (size < sizeof(_unused_t)) ?
_align(sizeof(_unused_t)) : _align(size);
mutex_lock(&_mutex);
if ((size == 0) || (pkt == NULL) || (size > pkt->size) || (pkt->data == NULL)) {
DEBUG("pktbuf: size == 0 (was %u) or pkt == NULL (was %p) or "
"size > pkt->size (was %u) or pkt->data == NULL (was %p)\n",
(unsigned)size, (void *)pkt, (unsigned)pkt->size, pkt->data);
mutex_unlock(&_mutex);
return NULL;
}
else if (size == pkt->size) {