2015-07-24 17:29:29 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2015-08-17 15:41:29 +02:00
|
|
|
* @ingroup net_gnrc_pktbuf
|
2015-07-24 17:29:29 +02:00
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @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"
|
2015-08-17 15:41:29 +02:00
|
|
|
#include "net/gnrc/pktbuf.h"
|
|
|
|
#include "net/gnrc/nettype.h"
|
|
|
|
#include "net/gnrc/pkt.h"
|
2015-07-24 17:29:29 +02:00
|
|
|
|
2021-01-22 18:00:34 +01:00
|
|
|
#include "pktbuf_internal.h"
|
2021-02-19 11:28:01 +01:00
|
|
|
#include "pktbuf_static.h"
|
2021-01-22 18:00:34 +01:00
|
|
|
|
2020-10-22 11:35:22 +02:00
|
|
|
#define ENABLE_DEBUG 0
|
2015-07-24 17:29:29 +02:00
|
|
|
#include "debug.h"
|
|
|
|
|
2020-09-22 15:03:24 +02:00
|
|
|
/* The static buffer needs to be aligned to word size, so that its start
|
|
|
|
* address can be casted to `_unused_t *` safely. Just allocating an array of
|
|
|
|
* (word sized) uintptr_t is a trivial way to do this */
|
|
|
|
static uintptr_t _pktbuf_buf[CONFIG_GNRC_PKTBUF_SIZE / sizeof(uintptr_t)];
|
2021-01-22 18:00:34 +01:00
|
|
|
uint8_t *gnrc_pktbuf_static_buf = (uint8_t *)_pktbuf_buf;
|
2015-07-24 17:29:29 +02:00
|
|
|
static _unused_t *_first_unused;
|
|
|
|
|
2015-11-13 15:16:48 +01:00
|
|
|
#ifdef DEVELHELP
|
|
|
|
/* maximum number of bytes allocated */
|
|
|
|
static uint16_t max_byte_count = 0;
|
|
|
|
#endif
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
/* internal gnrc_pktbuf functions */
|
2018-06-15 00:43:18 +02:00
|
|
|
static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, const void *data, size_t size,
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_nettype_t type);
|
2015-07-24 17:29:29 +02:00
|
|
|
static void *_pktbuf_alloc(size_t size);
|
|
|
|
|
2015-07-10 17:22:35 +02:00
|
|
|
static inline void _set_pktsnip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *next,
|
|
|
|
void *data, size_t size, gnrc_nettype_t type)
|
|
|
|
{
|
|
|
|
pkt->next = next;
|
|
|
|
pkt->data = data;
|
|
|
|
pkt->size = size;
|
|
|
|
pkt->type = type;
|
|
|
|
pkt->users = 1;
|
|
|
|
#ifdef MODULE_GNRC_NETERR
|
|
|
|
pkt->err_sub = KERNEL_PID_UNDEF;
|
|
|
|
#endif
|
|
|
|
}
|
2015-07-24 17:29:29 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
void gnrc_pktbuf_init(void)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_lock(&gnrc_pktbuf_mutex);
|
2020-09-22 15:03:24 +02:00
|
|
|
_first_unused = (_unused_t *)_pktbuf_buf;
|
2015-07-24 17:29:29 +02:00
|
|
|
_first_unused->next = NULL;
|
2020-09-22 15:03:24 +02:00
|
|
|
_first_unused->size = sizeof(_pktbuf_buf);
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
|
2018-06-15 00:43:18 +02:00
|
|
|
gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, const void *data, size_t size,
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_nettype_t type)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *pkt;
|
2015-07-10 17:22:35 +02:00
|
|
|
|
2020-05-11 15:44:40 +02:00
|
|
|
if (size > CONFIG_GNRC_PKTBUF_SIZE) {
|
|
|
|
DEBUG("pktbuf: size (%u) > CONFIG_GNRC_PKTBUF_SIZE (%u)\n",
|
|
|
|
(unsigned)size, CONFIG_GNRC_PKTBUF_SIZE);
|
2015-07-24 17:29:29 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_lock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
pkt = _create_snip(next, data, size, type);
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_t type)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *marked_snip;
|
2015-07-24 17:29:29 +02:00
|
|
|
/* size required for chunk */
|
2018-06-27 16:49:33 +02:00
|
|
|
size_t required_new_size = _align(size);
|
2015-07-10 17:22:35 +02:00
|
|
|
void *new_data_marked;
|
|
|
|
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_lock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
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",
|
2015-09-15 15:07:29 +02:00
|
|
|
(unsigned)size, (void *)pkt, (pkt ? (unsigned)pkt->size : 0),
|
|
|
|
(pkt ? pkt->data : NULL));
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-07-26 19:53:48 +02:00
|
|
|
/* create new snip descriptor for marked data */
|
2015-08-17 15:41:29 +02:00
|
|
|
marked_snip = _pktbuf_alloc(sizeof(gnrc_pktsnip_t));
|
2015-07-24 17:29:29 +02:00
|
|
|
if (marked_snip == NULL) {
|
|
|
|
DEBUG("pktbuf: could not reallocate marked section.\n");
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-07-26 19:53:48 +02:00
|
|
|
/* marked data would not fit _unused_t marker => move data around to allow
|
|
|
|
* for proper free */
|
2018-06-27 16:49:33 +02:00
|
|
|
if ((pkt->size != size) && (size < required_new_size)) {
|
2015-07-10 17:22:35 +02:00
|
|
|
void *new_data_rest;
|
2015-07-24 17:29:29 +02:00
|
|
|
new_data_marked = _pktbuf_alloc(size);
|
|
|
|
if (new_data_marked == NULL) {
|
|
|
|
DEBUG("pktbuf: could not reallocate marked section.\n");
|
2021-01-22 18:00:34 +01:00
|
|
|
gnrc_pktbuf_free_internal(marked_snip, sizeof(gnrc_pktsnip_t));
|
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
new_data_rest = _pktbuf_alloc(pkt->size - size);
|
|
|
|
if (new_data_rest == NULL) {
|
|
|
|
DEBUG("pktbuf: could not reallocate remaining section.\n");
|
2021-01-22 18:00:34 +01:00
|
|
|
gnrc_pktbuf_free_internal(marked_snip, sizeof(gnrc_pktsnip_t));
|
|
|
|
gnrc_pktbuf_free_internal(new_data_marked, size);
|
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memcpy(new_data_marked, pkt->data, size);
|
|
|
|
memcpy(new_data_rest, ((uint8_t *)pkt->data) + size, pkt->size - size);
|
2021-01-22 18:00:34 +01:00
|
|
|
gnrc_pktbuf_free_internal(pkt->data, pkt->size);
|
2015-07-24 17:29:29 +02:00
|
|
|
marked_snip->data = new_data_marked;
|
|
|
|
pkt->data = new_data_rest;
|
|
|
|
}
|
|
|
|
else {
|
2015-07-10 17:22:35 +02:00
|
|
|
new_data_marked = pkt->data;
|
2016-07-26 19:53:48 +02:00
|
|
|
/* if (pkt->size - size) != 0 take remainder of data, otherwise set NULL */
|
|
|
|
pkt->data = (pkt->size != size) ? (((uint8_t *)pkt->data) + size) :
|
|
|
|
NULL;
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
pkt->size -= size;
|
2015-07-10 17:22:35 +02:00
|
|
|
_set_pktsnip(marked_snip, pkt->next, new_data_marked, size, type);
|
2015-07-24 17:29:29 +02:00
|
|
|
pkt->next = marked_snip;
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return marked_snip;
|
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
int gnrc_pktbuf_realloc_data(gnrc_pktsnip_t *pkt, size_t size)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2018-06-27 16:49:33 +02:00
|
|
|
size_t aligned_size = _align(size);
|
2015-07-10 17:22:35 +02:00
|
|
|
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_lock(&gnrc_pktbuf_mutex);
|
2016-07-26 19:53:48 +02:00
|
|
|
assert(pkt != NULL);
|
|
|
|
assert(((pkt->size == 0) && (pkt->data == NULL)) ||
|
2021-01-22 18:00:34 +01:00
|
|
|
((pkt->size > 0) && (pkt->data != NULL) && gnrc_pktbuf_contains(pkt->data)));
|
2016-07-26 19:53:48 +02:00
|
|
|
/* new size and old size are equal */
|
2015-07-24 17:29:29 +02:00
|
|
|
if (size == pkt->size) {
|
2016-07-26 19:53:48 +02:00
|
|
|
/* nothing to do */
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2016-07-26 19:53:48 +02:00
|
|
|
/* new size is 0 and data pointer isn't already NULL */
|
|
|
|
if ((size == 0) && (pkt->data != NULL)) {
|
|
|
|
/* set data pointer to NULL */
|
2021-01-22 18:00:34 +01:00
|
|
|
gnrc_pktbuf_free_internal(pkt->data, pkt->size);
|
2016-07-26 19:53:48 +02:00
|
|
|
pkt->data = NULL;
|
|
|
|
}
|
|
|
|
/* if new size is bigger than old size */
|
2018-06-27 16:49:33 +02:00
|
|
|
else if (size > pkt->size) { /* new size does not fit */
|
2015-07-24 17:29:29 +02:00
|
|
|
void *new_data = _pktbuf_alloc(size);
|
|
|
|
if (new_data == NULL) {
|
|
|
|
DEBUG("pktbuf: error allocating new data section\n");
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return ENOMEM;
|
|
|
|
}
|
2016-07-26 19:53:48 +02:00
|
|
|
if (pkt->data != NULL) { /* if old data exist */
|
|
|
|
memcpy(new_data, pkt->data, (pkt->size < size) ? pkt->size : size);
|
|
|
|
}
|
2021-01-22 18:00:34 +01:00
|
|
|
gnrc_pktbuf_free_internal(pkt->data, pkt->size);
|
2015-07-24 17:29:29 +02:00
|
|
|
pkt->data = new_data;
|
|
|
|
}
|
2016-07-26 19:53:48 +02:00
|
|
|
else if (_align(pkt->size) > aligned_size) {
|
2021-01-22 18:00:34 +01:00
|
|
|
gnrc_pktbuf_free_internal(((uint8_t *)pkt->data) + aligned_size,
|
2016-07-26 19:53:48 +02:00
|
|
|
pkt->size - aligned_size);
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
pkt->size = size;
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_lock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
while (pkt) {
|
|
|
|
pkt->users += num;
|
|
|
|
pkt = pkt->next;
|
|
|
|
}
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *gnrc_pktbuf_start_write(gnrc_pktsnip_t *pkt)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_lock(&gnrc_pktbuf_mutex);
|
2019-03-12 14:34:19 +01:00
|
|
|
if (pkt == NULL) {
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (pkt->users > 1) {
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *new;
|
2015-07-24 17:29:29 +02:00
|
|
|
new = _create_snip(pkt->next, pkt->data, pkt->size, pkt->type);
|
|
|
|
if (new != NULL) {
|
|
|
|
pkt->users--;
|
|
|
|
}
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return new;
|
|
|
|
}
|
2021-01-22 18:00:34 +01:00
|
|
|
mutex_unlock(&gnrc_pktbuf_mutex);
|
2015-07-24 17:29:29 +02:00
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEVELHELP
|
|
|
|
#ifdef MODULE_OD
|
2015-07-25 02:14:42 +02:00
|
|
|
static inline void _print_chunk(void *chunk, size_t size, int num)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2015-10-05 14:16:00 +02:00
|
|
|
printf("=========== chunk %3d (%-10p size: %4u) ===========\n", num, chunk,
|
2015-07-24 17:29:29 +02:00
|
|
|
(unsigned int)size);
|
2017-01-31 15:13:12 +01:00
|
|
|
od_hex_dump(chunk, size, OD_WIDTH_DEFAULT);
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
|
2019-10-23 14:52:21 +02:00
|
|
|
static inline void _print_ptr(_unused_t *ptr)
|
|
|
|
{
|
|
|
|
if (ptr == NULL) {
|
|
|
|
printf("(nil)");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("%p", (void *)ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-25 02:14:42 +02:00
|
|
|
static inline void _print_unused(_unused_t *ptr)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2019-10-23 14:52:21 +02:00
|
|
|
printf("~ unused: ");
|
|
|
|
_print_ptr(ptr);
|
|
|
|
printf(" (next: ");
|
|
|
|
_print_ptr(ptr->next);
|
|
|
|
printf(", size: %4u) ~\n", ptr->size);
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
void gnrc_pktbuf_stats(void)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
|
|
|
#ifdef MODULE_OD
|
|
|
|
_unused_t *ptr = _first_unused;
|
2021-01-22 18:00:34 +01:00
|
|
|
uint8_t *chunk = &gnrc_pktbuf_static_buf[0];
|
2015-07-24 17:29:29 +02:00
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
printf("packet buffer: first byte: %p, last byte: %p (size: %u)\n",
|
2021-01-22 18:00:34 +01:00
|
|
|
(void *)&gnrc_pktbuf_static_buf[0],
|
|
|
|
(void *)&gnrc_pktbuf_static_buf[CONFIG_GNRC_PKTBUF_SIZE],
|
|
|
|
CONFIG_GNRC_PKTBUF_SIZE);
|
2015-11-13 15:16:48 +01:00
|
|
|
printf(" position of last byte used: %" PRIu16 "\n", max_byte_count);
|
2015-07-24 17:29:29 +02:00
|
|
|
if (ptr == NULL) { /* packet buffer is completely full */
|
2020-05-11 15:44:40 +02:00
|
|
|
_print_chunk(chunk, CONFIG_GNRC_PKTBUF_SIZE, count++);
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (((void *)ptr) == ((void *)chunk)) { /* _first_unused is at the beginning */
|
|
|
|
_print_unused(ptr);
|
|
|
|
chunk += ptr->size;
|
|
|
|
ptr = ptr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (ptr) {
|
|
|
|
size_t size = ((uint8_t *)ptr) - chunk;
|
2021-01-22 18:00:34 +01:00
|
|
|
if ((size == 0) && (!gnrc_pktbuf_contains(ptr)) &&
|
|
|
|
(!gnrc_pktbuf_contains(chunk)) && (size > CONFIG_GNRC_PKTBUF_SIZE)) {
|
2015-07-24 17:29:29 +02:00
|
|
|
puts("ERROR");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_print_chunk(chunk, size, count++);
|
|
|
|
chunk += (size + ptr->size);
|
|
|
|
_print_unused(ptr);
|
2015-09-29 15:27:49 +02:00
|
|
|
ptr = ptr->next;
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
|
2021-01-22 18:00:34 +01:00
|
|
|
if (chunk <= &gnrc_pktbuf_static_buf[CONFIG_GNRC_PKTBUF_SIZE - 1]) {
|
|
|
|
_print_chunk(chunk, &gnrc_pktbuf_static_buf[CONFIG_GNRC_PKTBUF_SIZE] - chunk, count);
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
DEBUG("pktbuf: needs od module\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef TEST_SUITES
|
2015-08-17 15:41:29 +02:00
|
|
|
bool gnrc_pktbuf_is_empty(void)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2021-01-22 18:00:34 +01:00
|
|
|
return (_first_unused == (_unused_t *)gnrc_pktbuf_static_buf) &&
|
2020-09-22 15:03:24 +02:00
|
|
|
(_first_unused->size == sizeof(_pktbuf_buf));
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
bool gnrc_pktbuf_is_sane(void)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
|
|
|
_unused_t *ptr = _first_unused;
|
|
|
|
|
|
|
|
/* Invariants of this implementation:
|
|
|
|
* - the head of _unused_t list is _first_unused
|
|
|
|
* - if _unused_t list is empty the packet buffer is full and _first_unused is NULL
|
2021-01-22 18:00:34 +01:00
|
|
|
* - forall ptr_in _unused_t list: &gnrc_pktbuf_static_buf[0] < ptr
|
|
|
|
* && ptr < &gnrc_pktbuf_static_buf[CONFIG_GNRC_PKTBUF_SIZE]
|
2015-07-24 17:29:29 +02:00
|
|
|
* - forall ptr in _unused_t list: ptr->next == NULL || ptr < ptr->next
|
|
|
|
* - forall ptr in _unused_t list: (ptr->next != NULL && ptr->size <= (ptr->next - ptr)) ||
|
2021-01-22 18:00:34 +01:00
|
|
|
* (ptr->next == NULL
|
|
|
|
* && ptr->size == (CONFIG_GNRC_PKTBUF_SIZE - pos_in_buf))
|
2015-07-24 17:29:29 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
while (ptr) {
|
2021-01-22 18:00:34 +01:00
|
|
|
if ((&gnrc_pktbuf_static_buf[0] >= (uint8_t *)ptr)
|
|
|
|
&& ((uint8_t *)ptr >= &gnrc_pktbuf_static_buf[CONFIG_GNRC_PKTBUF_SIZE])) {
|
2015-07-24 17:29:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ((ptr->next != NULL) && (ptr >= ptr->next)) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-01-22 18:00:34 +01:00
|
|
|
size_t pos_in_buf = (uint8_t *)ptr - &gnrc_pktbuf_static_buf[0];
|
|
|
|
if (((ptr->next == NULL) || (ptr->size > (size_t)((uint8_t *)(ptr->next) - (uint8_t *)ptr)))
|
|
|
|
&& ((ptr->next != NULL) || (ptr->size != CONFIG_GNRC_PKTBUF_SIZE - pos_in_buf))) {
|
2015-07-24 17:29:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ptr = ptr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-06-15 00:43:18 +02:00
|
|
|
static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, const void *data, size_t size,
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_nettype_t type)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *pkt = _pktbuf_alloc(sizeof(gnrc_pktsnip_t));
|
2016-07-26 19:53:48 +02:00
|
|
|
void *_data = NULL;
|
2015-07-10 17:22:35 +02:00
|
|
|
|
2015-07-24 17:29:29 +02:00
|
|
|
if (pkt == NULL) {
|
|
|
|
DEBUG("pktbuf: error allocating new packet snip\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-07-26 19:53:48 +02:00
|
|
|
if (size > 0) {
|
|
|
|
_data = _pktbuf_alloc(size);
|
|
|
|
if (_data == NULL) {
|
|
|
|
DEBUG("pktbuf: error allocating data for new packet snip\n");
|
2021-01-22 18:00:34 +01:00
|
|
|
gnrc_pktbuf_free_internal(pkt, sizeof(gnrc_pktsnip_t));
|
2016-07-26 19:53:48 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-01-16 15:38:20 +01:00
|
|
|
if (data != NULL) {
|
|
|
|
memcpy(_data, data, size);
|
|
|
|
}
|
2015-07-24 17:29:29 +02:00
|
|
|
}
|
2015-07-10 17:22:35 +02:00
|
|
|
_set_pktsnip(pkt, next, _data, size, type);
|
2015-07-24 17:29:29 +02:00
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *_pktbuf_alloc(size_t size)
|
|
|
|
{
|
|
|
|
_unused_t *prev = NULL, *ptr = _first_unused;
|
2015-07-10 17:22:35 +02:00
|
|
|
|
2018-06-27 16:49:33 +02:00
|
|
|
size = _align(size);
|
2015-10-02 12:10:43 +02:00
|
|
|
while (ptr && (size > ptr->size)) {
|
2015-07-24 17:29:29 +02:00
|
|
|
prev = ptr;
|
|
|
|
ptr = ptr->next;
|
|
|
|
}
|
|
|
|
if (ptr == NULL) {
|
|
|
|
DEBUG("pktbuf: no space left in packet buffer\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-11-08 19:18:42 +01:00
|
|
|
/* _unused_t struct would fit => add new space at ptr */
|
2015-07-24 17:29:29 +02:00
|
|
|
if (sizeof(_unused_t) > (ptr->size - size)) {
|
|
|
|
if (prev == NULL) { /* ptr was _first_unused */
|
|
|
|
_first_unused = ptr->next;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
prev->next = ptr->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-09-22 15:03:24 +02:00
|
|
|
/* alignment is ensured by rounding size up in the _align() function.
|
|
|
|
* We cast to uintptr_t as intermediate step to silence -Wcast-align */
|
|
|
|
_unused_t *new = (_unused_t *)((uintptr_t)ptr + size);
|
2016-11-08 19:18:42 +01:00
|
|
|
|
2021-01-22 18:00:34 +01:00
|
|
|
if (((((uint8_t *)new) - &(gnrc_pktbuf_static_buf[0])) + sizeof(_unused_t))
|
|
|
|
> CONFIG_GNRC_PKTBUF_SIZE) {
|
2016-11-08 19:18:42 +01:00
|
|
|
/* content of new would exceed packet buffer size so set to NULL */
|
|
|
|
_first_unused = NULL;
|
|
|
|
}
|
|
|
|
else if (prev == NULL) { /* ptr was _first_unused */
|
2015-07-24 17:29:29 +02:00
|
|
|
_first_unused = new;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
prev->next = new;
|
|
|
|
}
|
|
|
|
new->next = ptr->next;
|
|
|
|
new->size = ptr->size - size;
|
|
|
|
}
|
2015-11-13 15:16:48 +01:00
|
|
|
#ifdef DEVELHELP
|
2021-01-22 18:00:34 +01:00
|
|
|
uint16_t last_byte = (uint16_t)((((uint8_t *)ptr) + size) - &(gnrc_pktbuf_static_buf[0]));
|
2015-11-13 15:16:48 +01:00
|
|
|
if (last_byte > max_byte_count) {
|
|
|
|
max_byte_count = last_byte;
|
|
|
|
}
|
|
|
|
#endif
|
2015-07-24 17:29:29 +02:00
|
|
|
return (void *)ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool _too_small_hole(_unused_t *a, _unused_t *b)
|
|
|
|
{
|
|
|
|
return sizeof(_unused_t) > (size_t)(((uint8_t *)b) - (((uint8_t *)a) + a->size));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline _unused_t *_merge(_unused_t *a, _unused_t *b)
|
|
|
|
{
|
2015-08-18 14:19:23 +02:00
|
|
|
assert(b != NULL);
|
|
|
|
|
2015-07-24 17:29:29 +02:00
|
|
|
a->next = b->next;
|
|
|
|
a->size = b->size + ((uint8_t *)b - (uint8_t *)a);
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2021-01-22 18:00:34 +01:00
|
|
|
void gnrc_pktbuf_free_internal(void *data, size_t size)
|
2015-07-24 17:29:29 +02:00
|
|
|
{
|
2016-11-08 19:18:42 +01:00
|
|
|
size_t bytes_at_end;
|
2015-07-24 17:29:29 +02:00
|
|
|
_unused_t *new = (_unused_t *)data, *prev = NULL, *ptr = _first_unused;
|
2015-07-10 17:22:35 +02:00
|
|
|
|
2021-01-22 18:00:34 +01:00
|
|
|
if (!gnrc_pktbuf_contains(data)) {
|
2015-07-24 17:29:29 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (ptr && (((void *)ptr) < data)) {
|
|
|
|
prev = ptr;
|
|
|
|
ptr = ptr->next;
|
|
|
|
}
|
|
|
|
new->next = ptr;
|
2018-06-27 16:49:33 +02:00
|
|
|
new->size = _align(size);
|
2016-11-08 19:18:42 +01:00
|
|
|
/* calculate number of bytes between new _unused_t chunk and end of packet
|
|
|
|
* buffer */
|
2021-01-22 18:00:34 +01:00
|
|
|
bytes_at_end = ((&gnrc_pktbuf_static_buf[0] + CONFIG_GNRC_PKTBUF_SIZE)
|
|
|
|
- (((uint8_t *)new) + new->size));
|
2018-06-27 16:49:33 +02:00
|
|
|
if (bytes_at_end < sizeof(_unused_t)) {
|
2016-11-08 19:18:42 +01:00
|
|
|
/* new is very last segment and there is a little bit of memory left
|
|
|
|
* that wouldn't fit _unused_t (cut of in _pktbuf_alloc()) => re-add it */
|
|
|
|
new->size += bytes_at_end;
|
|
|
|
}
|
2015-07-24 17:29:29 +02:00
|
|
|
if (prev == NULL) { /* ptr was _first_unused or data before _first_unused */
|
|
|
|
_first_unused = new;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
prev->next = new;
|
|
|
|
if (_too_small_hole(prev, new)) {
|
|
|
|
new = _merge(prev, new);
|
|
|
|
}
|
|
|
|
}
|
2015-08-18 15:27:14 +02:00
|
|
|
if ((new->next != NULL) && (_too_small_hole(new, new->next))) {
|
2015-07-24 17:29:29 +02:00
|
|
|
_merge(new, new->next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|