From da23ffe0966079bcd9642766604c448b698d5f22 Mon Sep 17 00:00:00 2001 From: Martine Lenders <mail@martine-lenders.eu> Date: Fri, 10 Jul 2015 17:22:35 +0200 Subject: [PATCH] gnrc: initial import of an asynchroneous error reporting API --- Makefile.pseudomodules | 1 + sys/include/net/gnrc/neterr.h | 93 +++++++++++++++++++ sys/include/net/gnrc/pkt.h | 5 + sys/include/net/gnrc/pktbuf.h | 20 +++- .../gnrc/pktbuf_static/gnrc_pktbuf_static.c | 40 +++++--- 5 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 sys/include/net/gnrc/neterr.h diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules index 038de122c2..7ba7ff37e1 100644 --- a/Makefile.pseudomodules +++ b/Makefile.pseudomodules @@ -6,6 +6,7 @@ PSEUDOMODULES += gnrc_netif_default PSEUDOMODULES += gnrc_ipv6_default PSEUDOMODULES += gnrc_ipv6_router PSEUDOMODULES += gnrc_ipv6_router_default +PSEUDOMODULES += gnrc_neterr PSEUDOMODULES += gnrc_sixlowpan_default PSEUDOMODULES += gnrc_sixlowpan_border_router_default PSEUDOMODULES += gnrc_sixlowpan_nd_border_router diff --git a/sys/include/net/gnrc/neterr.h b/sys/include/net/gnrc/neterr.h new file mode 100644 index 0000000000..19d1c41ceb --- /dev/null +++ b/sys/include/net/gnrc/neterr.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 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. + */ + +/** + * @defgroup net_gnrc_neterr Error reporting + * @ingroup net + * @brief Allows for asynchronous error reporting in the network stack. + * @{ + * + * @file + * @brief Error reporting definitions. + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef GNRC_NETERR_H_ +#define GNRC_NETERR_H_ + +#include <errno.h> +#include <stdint.h> + +#include "kernel_types.h" +#include "msg.h" +#include "net/gnrc/pkt.h" +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief @ref core_msg type for reporting an error. + */ +#define GNRC_NETERR_MSG_TYPE (0x0206) + +/** + * @brief Error code to signalise success (no error occured) to an gnrc_neterr subscriber. + */ +#define GNRC_NETERR_SUCCESS (0) + +/** + * @brief Reports an error to all subscribers of errors to @p pkt. + * + * @param[in] pkt Packet snip to report on. + * @param[in] err The error code for the packet. + */ +#ifdef MODULE_GNRC_NETERR +static inline void gnrc_neterr_report(gnrc_pktsnip_t *pkt, uint32_t err) +{ + if (pkt->err_sub != KERNEL_PID_UNDEF) { + msg_t msg; + + msg.type = GNRC_NETERR_MSG_TYPE; + msg.content.value = err; + + msg_send(&msg, pkt->err_sub); + } +} +#else +#define gnrc_neterr_report(pkt, err) (void)pkt; (void)err +#endif + +/** + * @brief Registers the current thread for errors on a @ref gnrc_pktsnip_t. + * + * @param[in] pkt Packet snip to register for errors. + * + * @return 0, on success. + * @return EALREADY, if there already someone registered to errors on @p pkt. + */ +#ifdef MODULE_GNRC_NETERR +static inline int gnrc_neterr_reg(gnrc_pktsnip_t *pkt) +{ + if (pkt->err_sub != KERNEL_PID_UNDEF) { + return EALREADY; + } + pkt->err_sub = sched_active_pid; + return 0; +} +#else +#define gnrc_neterr_reg(pkt) (0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_NETERR_H_ */ +/** @} */ diff --git a/sys/include/net/gnrc/pkt.h b/sys/include/net/gnrc/pkt.h index 6d2475ad42..7d4ab80dd2 100644 --- a/sys/include/net/gnrc/pkt.h +++ b/sys/include/net/gnrc/pkt.h @@ -25,6 +25,7 @@ #include <inttypes.h> #include <stdlib.h> +#include "kernel_types.h" #include "net/gnrc/nettype.h" #ifdef __cplusplus @@ -110,6 +111,10 @@ typedef struct gnrc_pktsnip { void *data; /**< pointer to the data of the snip */ size_t size; /**< the length of the snip in byte */ gnrc_nettype_t type; /**< protocol of the packet snip */ +#ifdef MODULE_GNRC_NETERR + kernel_pid_t err_sub; /**< subscriber to errors related to this + * packet snip */ +#endif } gnrc_pktsnip_t; /** diff --git a/sys/include/net/gnrc/pktbuf.h b/sys/include/net/gnrc/pktbuf.h index 6234e1c0e7..e1ddfc7815 100644 --- a/sys/include/net/gnrc/pktbuf.h +++ b/sys/include/net/gnrc/pktbuf.h @@ -37,6 +37,7 @@ #include "atomic.h" #include "cpu_conf.h" #include "net/gnrc/pkt.h" +#include "net/gnrc/neterr.h" #include "net/gnrc/nettype.h" #include "utlist.h" @@ -141,13 +142,26 @@ void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num); /** * @brief Decreases gnrc_pktsnip_t::users of @p pkt atomically and removes it if it - * reaches 0. + * reaches 0 and reports a possible error through an error code, if + * @ref net_gnrc_neterr is included. * * @pre All snips of @p pkt must be in the packet buffer. * * @param[in] pkt A packet. + * @param[in] err An error code. */ -void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt); +void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err); + +/** + * @brief Decreases gnrc_pktsnip_t::users of @p pkt atomically and removes it if it + * reaches 0 and reports @ref GNRC_NETERR_SUCCESS. + * + * @param[in] pkt A packet. + */ +static inline void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt) +{ + gnrc_pktbuf_release_error(pkt, GNRC_NETERR_SUCCESS); +} /** * @brief Must be called once before there is a write operation in a thread. @@ -189,7 +203,7 @@ gnrc_pktsnip_t *gnrc_pktbuf_get_iovec(gnrc_pktsnip_t *pkt, size_t *len); * @return The new reference to @p pkt. */ static inline gnrc_pktsnip_t *gnrc_pktbuf_remove_snip(gnrc_pktsnip_t *pkt, - gnrc_pktsnip_t *snip) + gnrc_pktsnip_t *snip) { LL_DELETE(pkt, snip); snip->next = NULL; diff --git a/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c b/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c index edc2858157..76887217e8 100644 --- a/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c +++ b/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c @@ -59,9 +59,21 @@ static inline bool _pktbuf_contains(void *ptr) /* fits size to byte alignment */ static inline size_t _align(size_t size) { - return ((size + _ALIGNMENT_MASK) & ~(_ALIGNMENT_MASK)); + return (size + _ALIGNMENT_MASK) & ~(_ALIGNMENT_MASK); } +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 +} void gnrc_pktbuf_init(void) { @@ -76,6 +88,7 @@ gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, void *data, size_t size, gnrc_nettype_t type) { gnrc_pktsnip_t *pkt; + if ((size == 0) || (size > GNRC_PKTBUF_SIZE)) { DEBUG("pktbuf: size (%u) == 0 || size == GNRC_PKTBUF_SIZE (%u)\n", (unsigned)size, GNRC_PKTBUF_SIZE); @@ -93,6 +106,8 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_ /* size required for chunk */ size_t required_new_size = (size < sizeof(_unused_t)) ? _align(sizeof(_unused_t)) : _align(size); + void *new_data_marked; + 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 " @@ -115,7 +130,7 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_ } /* would not fit unused marker => move data around */ if ((size < required_new_size) || ((pkt->size - size) < sizeof(_unused_t))) { - void *new_data_marked, *new_data_rest; + void *new_data_rest; new_data_marked = _pktbuf_alloc(size); if (new_data_marked == NULL) { DEBUG("pktbuf: could not reallocate marked section.\n"); @@ -138,14 +153,11 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_ pkt->data = new_data_rest; } else { - marked_snip->data = pkt->data; + new_data_marked = pkt->data; pkt->data = ((uint8_t *)pkt->data) + size; } pkt->size -= size; - marked_snip->next = pkt->next; - marked_snip->size = size; - marked_snip->type = type; - marked_snip->users = 1; + _set_pktsnip(marked_snip, pkt->next, new_data_marked, size, type); pkt->next = marked_snip; mutex_unlock(&_mutex); return marked_snip; @@ -155,6 +167,7 @@ int gnrc_pktbuf_realloc_data(gnrc_pktsnip_t *pkt, size_t size) { size_t aligned_size = (size < sizeof(_unused_t)) ? _align(sizeof(_unused_t)) : _align(size); + mutex_lock(&_mutex); assert((pkt != NULL) && (pkt->data != NULL) && _pktbuf_contains(pkt->data)); if (size == 0) { @@ -199,7 +212,7 @@ void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num) mutex_unlock(&_mutex); } -void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt) +void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err) { mutex_lock(&_mutex); while (pkt) { @@ -214,6 +227,8 @@ void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt) else { pkt->users--; } + DEBUG("pktbuf: report status code %" PRIu32 "\n", err); + gnrc_neterr_report(pkt, err); pkt = tmp; } mutex_unlock(&_mutex); @@ -372,6 +387,7 @@ static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, void *data, size_t siz { gnrc_pktsnip_t *pkt = _pktbuf_alloc(sizeof(gnrc_pktsnip_t)); void *_data; + if (pkt == NULL) { DEBUG("pktbuf: error allocating new packet snip\n"); return NULL; @@ -382,11 +398,7 @@ static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, void *data, size_t siz _pktbuf_free(pkt, sizeof(gnrc_pktsnip_t)); return NULL; } - pkt->next = next; - pkt->size = size; - pkt->data = _data; - pkt->type = type; - pkt->users = 1; + _set_pktsnip(pkt, next, _data, size, type); if (data != NULL) { memcpy(_data, data, size); } @@ -396,6 +408,7 @@ static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, void *data, size_t siz static void *_pktbuf_alloc(size_t size) { _unused_t *prev = NULL, *ptr = _first_unused; + size = (size < sizeof(_unused_t)) ? _align(sizeof(_unused_t)) : _align(size); while (ptr && (size > ptr->size)) { prev = ptr; @@ -444,6 +457,7 @@ static inline _unused_t *_merge(_unused_t *a, _unused_t *b) static void _pktbuf_free(void *data, size_t size) { _unused_t *new = (_unused_t *)data, *prev = NULL, *ptr = _first_unused; + if (!_pktbuf_contains(data)) { return; } -- GitLab