1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #1638 from authmillenon/packetbuf2

net: Initial import of a global packet buffer
This commit is contained in:
Martine Lenders 2014-10-16 14:01:56 +02:00
commit 0812d4789a
11 changed files with 1280 additions and 1 deletions

View File

@ -29,6 +29,11 @@
#ifndef UART0_BUFSIZE
#define UART0_BUFSIZE (32)
#endif
#ifndef PKTBUF_SIZE
#define PKTBUF_SIZE (2560) /* TODO: Make this value
overall MTU dependent */
#endif
/** @} */
#endif /* CPUCONF_H_ */

View File

@ -13,6 +13,9 @@ endif
ifneq (,$(filter ping,$(USEMODULE)))
DIRS += ping
endif
ifneq (,$(filter pktbuf,$(USEMODULE)))
DIRS += net/crosslayer/pktbuf
endif
ifneq (,$(filter ps,$(USEMODULE)))
DIRS += ps
endif

View File

@ -18,6 +18,9 @@ endif
ifneq (,$(filter net_if,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
endif
ifneq (,$(filter pktbuf,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
endif
ifneq (,$(filter pktqueue,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
endif

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,509 @@
/*
* Copyright (C) 2014 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.
*/
/**
* @{
*
* @file pktbuf.c
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "mutex.h"
#include "pktbuf.h"
typedef struct __attribute__((packed)) _packet_t {
volatile struct _packet_t *next;
uint8_t processing;
size_t size;
} _packet_t;
static uint8_t _pktbuf[PKTBUF_SIZE];
static mutex_t _pktbuf_mutex = MUTEX_INIT;
/**
* @brief Get first element in packet buffer.
*/
static inline _packet_t *_pktbuf_head(void)
{
return (_packet_t *)(&(_pktbuf[0]));
}
/**
* @brief Get data part (memory behind `_packet_t` descriptive header) of a packet
*
* @param[in] pkt A packet
*
* @return Data part of the packet.
*/
static inline void *_pkt_data(_packet_t *pkt)
{
return (void *)(((_packet_t *)pkt) + 1);
}
/**
* @brief Calculates total size (*size* + size of `_packet_t` descriptive header) of a
* packet in memory
*
* @param[in] size A given packet size
*
* @return Total size of a packet in memory.
*/
static inline size_t _pkt_total_sz(size_t size)
{
return sizeof(_packet_t) + size;
}
/**
* @brief Get pointer to the byte after the last byte of a packet.
*
* @param[in] pkt A packet
*
* @return Pointer to the last byte of a packet
*/
static inline void *_pkt_end(_packet_t *pkt)
{
return (void *)((uint8_t *)pkt + _pkt_total_sz(pkt->size));
}
/**
* @brief Get index in packet buffer of the first byte of a packet's data part
*
* @param[in] pkt A packet
*
* @return Index in packet buffer of the first byte of *pkt*'s data part.
*/
static inline size_t _pktbuf_start_idx(_packet_t *pkt)
{
return (size_t)(((uint8_t *)pkt) - (&(_pktbuf[0])));
}
/**
* @brief Get index in packet buffer of the last byte of a packet's data part
*
* @param[in] pkt A packet
*
* @return Index in packet buffer of the last byte of *pkt*'s data part.
*/
static inline size_t _pktbuf_end_idx(_packet_t *pkt)
{
return _pktbuf_start_idx(pkt) + _pkt_total_sz(pkt->size) - 1;
}
static _packet_t *_pktbuf_find_with_prev(_packet_t **prev_ptr,
_packet_t **packet_ptr, const void *pkt)
{
_packet_t *packet = _pktbuf_head(), *prev = NULL;
while (packet != NULL) {
if (_pkt_data(packet) == pkt) {
*prev_ptr = prev;
*packet_ptr = packet;
return packet;
}
prev = packet;
packet = (_packet_t *)packet->next;
}
*prev_ptr = NULL;
*packet_ptr = NULL;
return NULL;
}
static _packet_t *_pktbuf_find(const void *pkt)
{
_packet_t *packet = _pktbuf_head();
#ifdef DEVELHELP
if (pkt == NULL) {
return NULL;
}
#endif /* DEVELHELP */
while (packet != NULL) {
if ((_pkt_data(packet) <= pkt) && (pkt < _pkt_end(packet))) {
mutex_unlock(&_pktbuf_mutex);
return packet;
}
packet = (_packet_t *)packet->next;
}
return NULL;
}
static _packet_t *_pktbuf_alloc(size_t size)
{
_packet_t *packet = _pktbuf_head(), *old_next;
if ((size == 0) || (size > PKTBUF_SIZE)) {
return NULL;
}
if ((packet->size == 0) /* if first packet is currently not initialized
* but next packet and no space between first
* and next in its slot */
&& (packet->processing == 0)
&& (packet->next != NULL)
&& ((_pktbuf_start_idx((_packet_t *)(packet->next)) - _pkt_total_sz(packet->size)) < size)) {
packet = (_packet_t *)packet->next;
}
/* while packet is not initialized */
while ((packet->processing > 0) || (packet->size > size)) {
old_next = (_packet_t *)packet->next;
/* if current packet is the last in buffer, but buffer space is exceeded */
if ((old_next == NULL)
&& ((_pktbuf_end_idx(packet) + _pkt_total_sz(size)) > PKTBUF_SIZE)) {
return NULL;
}
/* if current packet is the last in the buffer or if space between
* current packet and next packet is big enough */
if ((old_next == NULL)
|| ((_pktbuf_start_idx((_packet_t *)(packet->next)) - _pktbuf_end_idx(packet)) >= _pkt_total_sz(
size))) {
_packet_t *new_next = (_packet_t *)(((uint8_t *)packet) + _pkt_total_sz(packet->size));
/* jump ahead size of current packet. */
packet->next = new_next;
packet->next->next = old_next;
packet = new_next;
break;
}
packet = old_next;
}
packet->size = size;
packet->processing = 1;
return packet;
}
static void _pktbuf_free(_packet_t *prev, _packet_t *packet)
{
if ((packet->processing)-- > 1) { /* `> 1` because packet->processing may already
* be 0 in which case --(packet->processing)
* would wrap to 255. */
return;
}
if (prev == NULL) { /* packet is _pktbuf_head() */
packet->size = 0;
}
else {
prev->next = packet->next;
}
}
int pktbuf_contains(const void *pkt)
{
return ((&(_pktbuf[0]) < ((uint8_t *)pkt)) && (((uint8_t *)pkt) <= &(_pktbuf[PKTBUF_SIZE - 1])));
}
void *pktbuf_alloc(size_t size)
{
_packet_t *packet;
mutex_lock(&_pktbuf_mutex);
packet = _pktbuf_alloc(size);
if (packet == NULL) {
mutex_unlock(&_pktbuf_mutex);
return NULL;
}
mutex_unlock(&_pktbuf_mutex);
return _pkt_data(packet);
}
void *pktbuf_realloc(const void *pkt, size_t size)
{
_packet_t *new, *prev, *orig;
mutex_lock(&_pktbuf_mutex);
if ((size == 0) || (size > PKTBUF_SIZE)) {
mutex_unlock(&_pktbuf_mutex);
return NULL;
}
_pktbuf_find_with_prev(&prev, &orig, pkt);
if ((orig != NULL) &&
((orig->size >= size) /* and *orig* is last packet, and space in
* _pktbuf is sufficient */
|| ((orig->next == NULL)
&& ((_pktbuf_start_idx(orig) + _pkt_total_sz(size)) < PKTBUF_SIZE))
|| ((orig->next != NULL) /* or space between pointer and the next is big enough: */
&& ((_pktbuf_start_idx((_packet_t *)(orig->next)) - _pktbuf_start_idx(orig))
>= _pkt_total_sz(size))))) {
orig->size = size;
mutex_unlock(&_pktbuf_mutex);
return (void *)pkt;
}
new = _pktbuf_alloc(size);
if (new == NULL) {
mutex_unlock(&_pktbuf_mutex);
return NULL;
}
if (orig != NULL) {
memcpy(_pkt_data(new), _pkt_data(orig), orig->size);
_pktbuf_free(prev, orig);
}
else {
memcpy(_pkt_data(new), pkt, size);
}
mutex_unlock(&_pktbuf_mutex);
return _pkt_data(new);
}
void *pktbuf_insert(const void *data, size_t size)
{
_packet_t *packet;
if ((data == NULL) || (size == 0)) {
return NULL;
}
mutex_lock(&_pktbuf_mutex);
packet = _pktbuf_alloc(size);
if (packet == NULL) {
mutex_unlock(&_pktbuf_mutex);
return NULL;
}
memcpy(_pkt_data(packet), data, size);
mutex_unlock(&_pktbuf_mutex);
return _pkt_data(packet);
}
int pktbuf_copy(void *pkt, const void *data, size_t data_len)
{
_packet_t *packet;
mutex_lock(&_pktbuf_mutex);
#ifdef DEVELHELP
if (data == NULL) {
mutex_unlock(&_pktbuf_mutex);
return -EFAULT;
}
if (pkt == NULL) {
mutex_unlock(&_pktbuf_mutex);
return -EINVAL;
}
#endif /* DEVELHELP */
packet = _pktbuf_find(pkt);
if ((packet != NULL) && (packet->size > 0) && (packet->processing > 0)) {
/* packet space not engough? */
if (data_len > (size_t)(((uint8_t *)_pkt_end(packet)) - ((uint8_t *)pkt))) {
mutex_unlock(&_pktbuf_mutex);
return -ENOMEM;
}
}
memcpy(pkt, data, data_len);
mutex_unlock(&_pktbuf_mutex);
return data_len;
}
void pktbuf_hold(const void *pkt)
{
_packet_t *packet;
mutex_lock(&_pktbuf_mutex);
packet = _pktbuf_find(pkt);
if (packet != NULL) {
packet->processing++;
}
mutex_unlock(&_pktbuf_mutex);
}
void pktbuf_release(const void *pkt)
{
_packet_t *packet = _pktbuf_head(), *prev = NULL;
mutex_lock(&_pktbuf_mutex);
while (packet != NULL) {
if ((_pkt_data(packet) <= pkt) && (pkt < _pkt_end(packet))) {
_pktbuf_free(prev, packet);
mutex_unlock(&_pktbuf_mutex);
return;
}
prev = packet;
packet = (_packet_t *)packet->next;
}
mutex_unlock(&_pktbuf_mutex);
}
#ifdef DEVELHELP
#include <stdio.h>
void pktbuf_print(void)
{
_packet_t *packet = _pktbuf_head();
int i = 0;
mutex_lock(&_pktbuf_mutex);
printf("current pktbuf allocations:\n");
printf("===================================================\n");
if (packet->next == NULL && packet->size == 0) {
printf("empty\n");
printf("===================================================\n");
printf("\n");
mutex_unlock(&_pktbuf_mutex);
return;
}
else if (packet->next != NULL && packet->size == 0) {
packet = (_packet_t *)packet->next;
}
while (packet != NULL) {
uint8_t *data = (uint8_t *)_pkt_data(packet);
printf("packet %d (%p):\n", i, (void *)packet);
printf(" next: %p\n", (void *)(packet->next));
printf(" size: %" PRIu32 "\n", (uint32_t)packet->size);
printf(" processing: %" PRIu8 "\n", packet->processing);
if (packet->next != NULL) {
printf(" free data after: %" PRIu32 "\n",
(uint32_t)(_pktbuf_start_idx((_packet_t *)(packet->next)) - _pktbuf_end_idx(packet) - 1));
}
else {
printf(" free data after: %" PRIu32 "\n", (uint32_t)(PKTBUF_SIZE - _pktbuf_end_idx(packet) - 1));
}
printf(" data: (start address: %p)\n ", data);
if (packet->size > PKTBUF_SIZE) {
printf(" We have a problem: packet->size (%" PRIu32 ") > PKTBUF_SIZE (%" PRIu32 ")\n",
(uint32_t)(packet->size), (uint32_t)PKTBUF_SIZE);
}
else {
for (size_t j = 0; j < packet->size; j++) {
printf(" %02x", data[j]);
if (((j + 1) % 16) == 0) {
printf("\n ");
}
}
printf("\n\n");
}
packet = (_packet_t *)packet->next;
i++;
}
printf("===================================================\n");
printf("\n");
mutex_unlock(&_pktbuf_mutex);
}
#endif
#ifdef TEST_SUITES
size_t pktbuf_bytes_allocated(void)
{
_packet_t *packet = _pktbuf_head();
size_t bytes = 0;
mutex_lock(&_pktbuf_mutex);
while (packet != NULL) {
bytes += packet->size;
packet = (_packet_t *)(packet->next);
}
mutex_unlock(&_pktbuf_mutex);
return bytes;
}
unsigned int pktbuf_packets_allocated(void)
{
_packet_t *packet = _pktbuf_head();
unsigned int packets = 0;
mutex_lock(&_pktbuf_mutex);
while (packet != NULL) {
if ((packet != _pktbuf_head()) || (packet->size > 0)) { /* ignore head if head->size == 0 */
packets++;
}
packet = (_packet_t *)(packet->next);
}
mutex_unlock(&_pktbuf_mutex);
return packets;
}
int pktbuf_is_empty(void)
{
return ((_pktbuf_head()->next == NULL) && (_pktbuf_head()->size == 0));
}
void pktbuf_reset(void)
{
memset(_pktbuf, 0, PKTBUF_SIZE);
mutex_init(&_pktbuf_mutex);
}
#endif
/** @} */

187
sys/net/include/pktbuf.h Normal file
View File

@ -0,0 +1,187 @@
/*
* Copyright (C) 2014 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.
*/
/**
* @defgroup pktbuf Packet buffer
* @ingroup net
* @brief A global network packet buffer.
* @{
*
* @file pktbuf.h
* @brief Interface definition for the global network buffer. Network devices
* and layers can allocate space for packets here.
*
* @note **WARNING!!** Do not store data structures that are not packed
* (defined with `__attribute__((packed))`) or enforce alignment in
* in any way in here. On some RISC architectures this *will* lead to
* alignment problems and can potentially result in segmentation/hard
* faults and other unexpected behaviour.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef __PKTBUF_H_
#define __PKTBUF_H_
#include <stdlib.h>
#include "cpu-conf.h"
#ifndef PKTBUF_SIZE
/**
* @brief Maximum size of the packet buffer.
*
* @detail The rational here is to have at least space for 4 full-MTU IPv6
* packages (2 incoming, 2 outgoing; 2 * 2 * 1280 B = 5 KiB) +
* Meta-Data (roughly estimated to 1 KiB; might be smaller)
*/
#define PKTBUF_SIZE (6144)
#endif /* PKTBUF_SIZE */
/**
* @brief Allocates new packet data in the packet buffer. This also marks the
* allocated data as processed.
*
* @see @ref pktbuf_hold()
*
* @param[in] size The length of the packet you want to allocate
*
* @return Pointer to the start of the data in the packet buffer, on success.
* @return NULL, if no space is left in the packet buffer or size was 0.
*/
void *pktbuf_alloc(size_t size);
/**
* @brief Reallocates new space in the packet buffer, without changing the
* content.
*
* @datail If enough memory is available behind it or *size* is smaller than
* the original size the packet will not be moved. Otherwise, it will
* be moved. If no space is available nothing happens.
*
* @param[in] pkt Old position of the packet in the packet buffer
* @param[in] size New amount of data you want to allocate
*
* @return Pointer to the (maybe new) position of the packet in the packet buffer,
* on success.
* @return NULL, if no space is left in the packet buffer or size was 0.
* The packet will remain at *ptr*.
*/
void *pktbuf_realloc(const void *pkt, size_t size);
/**
* @brief Allocates and copies new packet data into the packet buffer.
* This also marks the allocated data as processed for the current
* thread.
*
* @see @ref pktbuf_hold()
*
* @param[in] data Data you want to copy into the new packet.
* @param[in] size The length of the packet you want to allocate
*
* @return Pointer to the start of the data in the packet buffer, on success.
* @return NULL, if no space is left in the packet buffer.
*/
void *pktbuf_insert(const void *data, size_t size);
/**
* @brief Copies packet data into the packet buffer, safely.
*
* @detail Use this instead of memcpy, since it is thread-safe and checks if
* *pkt* is
*
* -# in the buffer at all
* -# its *size* is smaller or equal to the data allocated at *pkt*
*
* If the *pkt* is not in the buffer the data is just copied as
* memcpy would do.
*
* @param[in,out] pkt The packet you want to set the data for.
* @param[in] data The data you want to copy into the packet.
* @param[in] data_len The length of the data you want to copy.
*
* @return *data_len*, on success.
* @return -EFAULT, if *data* is NULL and DEVELHELP is defined.
* @return -EINVAL, if *pkt* is NULL and DEVELHELP is defined.
* @return -ENOBUFS, if *data_len* was greater than the packet size of *pkt*.
*/
int pktbuf_copy(void *pkt, const void *data, size_t data_len);
/**
* @brief Marks the data as being processed.
*
* @detail Internally this increments just a counter on the data.
* @ref pktbuf_release() decrements it. If the counter is <=0 the
* reserved data block in the buffer will be made available again.
*
* @param[in] pkt The packet you want mark as being processed.
*/
void pktbuf_hold(const void *pkt);
/**
* @brief Marks the data as not being processed.
*
* @param[in] pkt The packet you want mark as not being processed anymore.
*
* @detail Internally this decrements just a counter on the data.
* @ref pktbuf_hold() increments and any allocation
* operation initializes it. If the counter is <=0 the reserved data
* block in the buffer will be made available again.
*/
void pktbuf_release(const void *pkt);
/**
* @brief Prints current packet buffer to stdout if DEVELHELP is defined.
*/
#ifdef DEVELHELP
void pktbuf_print(void);
#else
#define pktbuf_print() ;
#endif
/* for testing */
#ifdef TEST_SUITES
/**
* @brief Counts the number of allocated bytes
*
* @return Number of allocated bytes
*/
size_t pktbuf_bytes_allocated(void);
/**
* @brief Counts the number of allocated packets
*
* @return Number of allocated packets
*/
size_t pktbuf_packets_allocated(void);
/**
* @brief Checks if packet buffer is empty
*
* @return 1, if packet buffer is empty
* @return 0, if packet buffer is not empty
*/
int pktbuf_is_empty(void);
/**
* @brief Checks if a given pointer is stored in the packet buffer
*
* @param[in] pkt Pointer to be checked
*
* @return 1, if *pkt* is in packet buffer
* @return 0, otherwise
*/
int pktbuf_contains(const void *pkt);
/**
* @brief Sets the whole packet buffer to 0
*/
void pktbuf_reset(void);
#endif
#endif /* __PKTBUF_H_ */
/** @} */

View File

@ -1,7 +1,7 @@
APPLICATION = unittests
include ../Makefile.tests_common
BOARD_INSUFFICIENT_RAM := chronos redbee-econotag stm32f0discovery
BOARD_INSUFFICIENT_RAM := chronos msb-430 msb-430h redbee-econotag stm32f0discovery
USEMODULE += embunit

View File

@ -0,0 +1,3 @@
MODULE = tests-pktbuf
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
USEMODULE += pktbuf

View File

@ -0,0 +1,538 @@
/*
* Copyright (C) 2014 Martine Lenders <mail@martine-lenders.eu>
*
* 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.
*/
/**
* @{
*
* @file tests-pktbuf.c
*/
#include <errno.h>
#include <stdint.h>
#include "embUnit/embUnit.h"
#include "pktbuf.h"
#include "tests-pktbuf.h"
typedef struct __attribute__((packed)) {
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
int8_t s8;
int16_t s16;
int32_t s32;
int64_t s64;
} test_pktbuf_struct_t;
static void tear_down(void)
{
pktbuf_reset();
}
static void test_pktbuf_alloc_0(void)
{
TEST_ASSERT_NULL(pktbuf_alloc(0));
}
static void test_pktbuf_alloc_memfull(void)
{
for (int i = 0; i < 9; i++) {
TEST_ASSERT_NOT_NULL(pktbuf_alloc((PKTBUF_SIZE / 10) + 4));
/* Why 4? Because: http://xkcd.com/221/, thats why ;-) */
}
TEST_ASSERT_NULL(pktbuf_alloc((PKTBUF_SIZE / 10) + 4));
}
static void test_pktbuf_alloc_success(void)
{
void *data, *data_prev = NULL;
for (int i = 0; i < 9; i++) {
data = pktbuf_alloc((PKTBUF_SIZE / 10) + 4);
TEST_ASSERT(data_prev < data);
data_prev = data;
}
}
static void test_pktbuf_realloc_0(void)
{
void *data = pktbuf_alloc(512);
TEST_ASSERT_NULL(pktbuf_realloc(data, 0));
}
static void test_pktbuf_realloc_memfull(void)
{
void *data = pktbuf_alloc(512);
TEST_ASSERT_NULL(pktbuf_realloc(data, PKTBUF_SIZE + 1));
}
static void test_pktbuf_realloc_memfull2(void)
{
void *data = pktbuf_alloc(512);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(512));
TEST_ASSERT_NULL(pktbuf_realloc(data, PKTBUF_SIZE - 512));
}
static void test_pktbuf_realloc_memfull3(void)
{
void *data;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = pktbuf_alloc(512);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(73));
TEST_ASSERT_NULL(pktbuf_realloc(data, PKTBUF_SIZE - 512));
}
static void test_pktbuf_realloc_smaller(void)
{
void *data;
data = pktbuf_alloc(512);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
TEST_ASSERT(data == pktbuf_realloc(data, 128));
}
static void test_pktbuf_realloc_memenough(void)
{
void *data;
data = pktbuf_alloc(128);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT(data == pktbuf_realloc(data, 200));
}
static void test_pktbuf_realloc_memenough2(void)
{
void *data, *data2;
data = pktbuf_alloc(128);
TEST_ASSERT_NOT_NULL(data);
data2 = pktbuf_alloc(128);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
pktbuf_release(data2);
TEST_ASSERT(data == pktbuf_realloc(data, 200));
}
static void test_pktbuf_realloc_nomemenough(void)
{
void *data, *data2;
data = pktbuf_alloc(128);
TEST_ASSERT_NOT_NULL(data);
data2 = pktbuf_alloc(128);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
pktbuf_release(data2);
TEST_ASSERT(data != pktbuf_realloc(data, 512));
}
static void test_pktbuf_realloc_unknown_ptr(void)
{
char *data = "abcd", *new_data = pktbuf_realloc(data, 5);
TEST_ASSERT_NOT_NULL(new_data);
TEST_ASSERT(data != new_data);
TEST_ASSERT_EQUAL_STRING(data, new_data);
}
static void test_pktbuf_insert_size_0(void)
{
TEST_ASSERT_NULL(pktbuf_insert("", 0));
}
static void test_pktbuf_insert_data_NULL(void)
{
TEST_ASSERT_NULL(pktbuf_insert(NULL, 4));
}
static void test_pktbuf_insert_memfull(void)
{
while (pktbuf_insert("abc", 4));
TEST_ASSERT_NULL(pktbuf_insert("abc", 4));
}
static void test_pktbuf_insert_success(void)
{
char *data, *data_prev = NULL;
for (int i = 0; i < 10; i++) {
data = (char *)pktbuf_insert("abc", 4);
TEST_ASSERT(data_prev < data);
TEST_ASSERT_EQUAL_STRING("abc", data);
data_prev = data;
}
}
#ifdef DEVELHELP
static void test_pktbuf_copy_efault(void)
{
char *data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_EQUAL_INT(-EFAULT, pktbuf_copy(data, NULL, 3));
TEST_ASSERT_EQUAL_STRING("abcd", data);
}
#endif
static void test_pktbuf_copy_data_len_too_long(void)
{
char *data = (char *)pktbuf_insert("ab", 3);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_EQUAL_INT(-ENOMEM, pktbuf_copy(data, "cdef", 5));
TEST_ASSERT_EQUAL_STRING("ab", data);
}
static void test_pktbuf_copy_data_len_too_long2(void)
{
char *data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_EQUAL_INT(-ENOMEM, pktbuf_copy(data + 2, "efgh", 5));
TEST_ASSERT_EQUAL_STRING("abcd", data);
}
static void test_pktbuf_copy_data_len_0(void)
{
char *data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_EQUAL_INT(0, pktbuf_copy(data, "ef", 0));
TEST_ASSERT_EQUAL_STRING("abcd", data);
}
static void test_pktbuf_copy_success(void)
{
char *data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_EQUAL_INT(3, pktbuf_copy(data, "ef", 3));
TEST_ASSERT_EQUAL_STRING("ef", data);
}
static void test_pktbuf_copy_success2(void)
{
char *data = (char *)pktbuf_insert("abcdef", 7);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_EQUAL_INT(2, pktbuf_copy(data + 3, "gh", 2));
TEST_ASSERT_EQUAL_STRING("abcghf", data);
}
static void test_pktbuf_hold_ptr_null(void)
{
char *data;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(16));
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
pktbuf_hold(NULL);
pktbuf_release(data);
TEST_ASSERT_EQUAL_INT(2, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_STRING("abcd", data);
}
static void test_pktbuf_hold_wrong_ptr(void)
{
char *data, wrong;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(16));
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
pktbuf_hold(&wrong);
pktbuf_release(data);
TEST_ASSERT_EQUAL_INT(2, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_STRING("abcd", data);
}
static void test_pktbuf_hold_success(void)
{
char *data;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(16));
pktbuf_hold(data);
pktbuf_release(data);
TEST_ASSERT_EQUAL_INT(3, pktbuf_copy(data, "ef", 3));
TEST_ASSERT_EQUAL_STRING("ef", data);
}
static void test_pktbuf_hold_success2(void)
{
char *data;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(16));
pktbuf_hold(data + 4);
pktbuf_release(data + 4);
TEST_ASSERT_EQUAL_INT(3, pktbuf_copy(data, "ef", 3));
TEST_ASSERT_EQUAL_STRING("ef", data);
}
static void test_pktbuf_release_ptr_null(void)
{
char *data;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(16));
pktbuf_release(NULL);
TEST_ASSERT_EQUAL_INT(3, pktbuf_copy(data, "ef", 3));
TEST_ASSERT_EQUAL_STRING("ef", data);
}
static void test_pktbuf_release_wrong_ptr(void)
{
char *data, wrong;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(16));
pktbuf_release(&wrong);
TEST_ASSERT_EQUAL_INT(3, pktbuf_copy(data, "ef", 3));
TEST_ASSERT_EQUAL_STRING("ef", data);
}
static void test_pktbuf_release_success(void)
{
char *data;
TEST_ASSERT_NOT_NULL(pktbuf_alloc(25));
data = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data);
TEST_ASSERT_NOT_NULL(pktbuf_alloc(16));
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
pktbuf_hold(data);
pktbuf_hold(data);
pktbuf_release(data + 3);
pktbuf_release(data + 4);
pktbuf_release(data + 2);
TEST_ASSERT_EQUAL_INT(2, pktbuf_packets_allocated());
}
static void test_pktbuf_release_success2(void)
{
char *data1, *data2, *data3;
data1 = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data1);
data2 = (char *)pktbuf_insert("ef", 3);
TEST_ASSERT_NOT_NULL(data2);
data3 = (char *)pktbuf_insert("ghijkl", 7);
TEST_ASSERT_NOT_NULL(data3);
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
pktbuf_release(data2);
TEST_ASSERT_EQUAL_INT(2, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_INT(2, pktbuf_copy(data1, "m", 2));
TEST_ASSERT_EQUAL_STRING("m", data1);
TEST_ASSERT_EQUAL_INT(4, pktbuf_copy(data3, "nop", 4));
TEST_ASSERT_EQUAL_STRING("nop", data3);
}
static void test_pktbuf_release_success3(void)
{
char *data1, *data2, *data3;
data1 = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data1);
data2 = (char *)pktbuf_insert("ef", 3);
TEST_ASSERT_NOT_NULL(data2);
data3 = (char *)pktbuf_insert("ghijkl", 7);
TEST_ASSERT_NOT_NULL(data3);
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
pktbuf_release(data1);
TEST_ASSERT_EQUAL_INT(2, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_INT(2, pktbuf_copy(data2, "m", 2));
TEST_ASSERT_EQUAL_STRING("m", data2);
TEST_ASSERT_EQUAL_INT(4, pktbuf_copy(data3, "nop", 4));
TEST_ASSERT_EQUAL_STRING("nop", data3);
}
static void test_pktbuf_release_success4(void)
{
char *data1, *data2, *data3;
data1 = (char *)pktbuf_insert("abcd", 5);
TEST_ASSERT_NOT_NULL(data1);
data2 = (char *)pktbuf_insert("ef", 3);
TEST_ASSERT_NOT_NULL(data2);
data3 = (char *)pktbuf_insert("ghijkl", 7);
TEST_ASSERT_NOT_NULL(data3);
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
pktbuf_release(data3);
TEST_ASSERT_EQUAL_INT(2, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_INT(2, pktbuf_copy(data1, "m", 2));
TEST_ASSERT_EQUAL_STRING("m", data1);
TEST_ASSERT_EQUAL_INT(1, pktbuf_copy(data2, "", 1));
TEST_ASSERT_EQUAL_STRING("", data2);
}
static void test_pktbuf_insert_packed_struct(void)
{
test_pktbuf_struct_t data = { 0x4d, 0xef43, 0xacdef574, 0x43644305695afde5,
34, -4469, 149699748, -46590430597
};
test_pktbuf_struct_t *data_cpy;
data_cpy = (test_pktbuf_struct_t *)pktbuf_insert(&data, sizeof(test_pktbuf_struct_t));
TEST_ASSERT_EQUAL_INT(data.u8, data_cpy->u8);
TEST_ASSERT_EQUAL_INT(data.u16, data_cpy->u16);
TEST_ASSERT_EQUAL_INT(data.u32, data_cpy->u32);
TEST_ASSERT_EQUAL_INT(data.u64, data_cpy->u64);
TEST_ASSERT_EQUAL_INT(data.s8, data_cpy->s8);
TEST_ASSERT_EQUAL_INT(data.s16, data_cpy->s16);
TEST_ASSERT_EQUAL_INT(data.s32, data_cpy->s32);
TEST_ASSERT_EQUAL_INT(data.s64, data_cpy->s64);
}
static void test_pktbuf_alloc_off_by_one1(void)
{
char *data1, *data2, *data3, *data4;
data1 = (char *)pktbuf_insert("1234567890a", 12);
TEST_ASSERT_NOT_NULL(data1);
data2 = (char *)pktbuf_alloc(44);
TEST_ASSERT_NOT_NULL(data2);
data4 = (char *)pktbuf_alloc(4);
TEST_ASSERT_NOT_NULL(data4);
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_INT(12 + 44 + 4, pktbuf_bytes_allocated());
pktbuf_release(data1);
TEST_ASSERT_EQUAL_INT(2, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_INT(44 + 4, pktbuf_bytes_allocated());
data3 = (char *)pktbuf_insert("bcdefghijklm", 13);
TEST_ASSERT_NOT_NULL(data3);
TEST_ASSERT(data1 != data3);
TEST_ASSERT_EQUAL_INT(3, pktbuf_packets_allocated());
TEST_ASSERT_EQUAL_INT(44 + 4 + 13, pktbuf_bytes_allocated());
}
Test *tests_pktbuf_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_pktbuf_alloc_0),
new_TestFixture(test_pktbuf_alloc_memfull),
new_TestFixture(test_pktbuf_alloc_success),
new_TestFixture(test_pktbuf_realloc_0),
new_TestFixture(test_pktbuf_realloc_memfull),
new_TestFixture(test_pktbuf_realloc_memfull2),
new_TestFixture(test_pktbuf_realloc_memfull3),
new_TestFixture(test_pktbuf_realloc_smaller),
new_TestFixture(test_pktbuf_realloc_memenough),
new_TestFixture(test_pktbuf_realloc_memenough2),
new_TestFixture(test_pktbuf_realloc_nomemenough),
new_TestFixture(test_pktbuf_realloc_unknown_ptr),
new_TestFixture(test_pktbuf_insert_size_0),
new_TestFixture(test_pktbuf_insert_data_NULL),
new_TestFixture(test_pktbuf_insert_memfull),
new_TestFixture(test_pktbuf_insert_success),
#ifdef DEVELHELP
new_TestFixture(test_pktbuf_copy_efault),
#endif
new_TestFixture(test_pktbuf_copy_data_len_too_long),
new_TestFixture(test_pktbuf_copy_data_len_too_long2),
new_TestFixture(test_pktbuf_copy_data_len_0),
new_TestFixture(test_pktbuf_copy_success),
new_TestFixture(test_pktbuf_copy_success2),
new_TestFixture(test_pktbuf_hold_ptr_null),
new_TestFixture(test_pktbuf_hold_wrong_ptr),
new_TestFixture(test_pktbuf_hold_success),
new_TestFixture(test_pktbuf_hold_success2),
new_TestFixture(test_pktbuf_release_ptr_null),
new_TestFixture(test_pktbuf_release_wrong_ptr),
new_TestFixture(test_pktbuf_release_success),
new_TestFixture(test_pktbuf_release_success2),
new_TestFixture(test_pktbuf_release_success3),
new_TestFixture(test_pktbuf_release_success4),
new_TestFixture(test_pktbuf_insert_packed_struct),
new_TestFixture(test_pktbuf_alloc_off_by_one1),
};
EMB_UNIT_TESTCALLER(pktbuf_tests, NULL, tear_down, fixtures);
return (Test *)&pktbuf_tests;
}
void tests_pktbuf(void)
{
TESTS_RUN(tests_pktbuf_tests());
}
/** @} */

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2014 Martin Lenders
*
* 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.
*/
/**
* @addtogroup unittests
* @{
*
* @file tests-pktbuf.h
* @brief Unittests for the ``pktbuf`` module
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef __TESTS_PKTBUF_H_
#define __TESTS_PKTBUF_H_
#include "../unittests.h"
/**
* @brief The entry point of this test suite.
*/
void tests_pktbuf(void);
#endif /* __TESTS_PKTBUF_H_ */
/** @} */