mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
b180e80ee3
- Changing the name of variable 'new' solved the problem.
300 lines
6.4 KiB
C
300 lines
6.4 KiB
C
/*
|
|
* 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
|
|
|
|
/** @} */
|