From 5dad8f1edd104278aa726dcb946572baee3f1959 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Tue, 26 Jul 2016 19:53:48 +0200 Subject: [PATCH] gnrc_pktbuf: allow for 0-sized payload snips --- sys/include/net/gnrc/pktbuf.h | 23 +++++-- .../gnrc/pktbuf_static/gnrc_pktbuf_static.c | 66 +++++++++++-------- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/sys/include/net/gnrc/pktbuf.h b/sys/include/net/gnrc/pktbuf.h index f7e1117283..7453457f4b 100644 --- a/sys/include/net/gnrc/pktbuf.h +++ b/sys/include/net/gnrc/pktbuf.h @@ -71,16 +71,19 @@ void gnrc_pktbuf_init(void); * function externally. This will most likely create memory leaks or * not allowed memory access. * + * @pre size < GNRC_PKTBUF_SIZE + * * @param[in] next Next gnrc_pktsnip_t in the packet. Leave NULL if you * want to create a new packet. * @param[in] data Data of the new gnrc_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] size Length of @p data. If this value is 0 the + * gnrc_pktsnip::data field of the newly created snip will + * be NULL. * @param[in] type Protocol type of the gnrc_pktsnip_t. * * @return Pointer to the packet part that represents the new gnrc_pktsnip_t. * @return NULL, if no space is left in the packet buffer. - * @return NULL, if @p size == 0. */ gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, void *data, size_t size, gnrc_nettype_t type); @@ -89,8 +92,9 @@ gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, void *data, size_t size, * @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 + * Graphically this can be represented as follows: + * + * ~~~~~~~~~~~~~~~~~~~ * Before After * ====== ===== * (next) @@ -99,7 +103,10 @@ gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, void *data, size_t size, * +--------------------------------+ +----------------+---------------+ * +--------------------------------+ +----------------+---------------+ * \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ - * @endcode + * ~~~~~~~~~~~~~~~~~~~ + * + * If `size == pkt->size` then the resulting snip will point to NULL in its + * gnrc_pktsnip_t::data field and its gnrc_pktsnip_t::size field will be 0. * * @pre @p pkt != NULL && @p size != 0 * @@ -117,7 +124,9 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_ * @brief Reallocates gnrc_pktsnip_t::data of @p pkt in the packet buffer, without * changing the content. * - * @pre gnrc_pktsnip_t::data of @p pkt is in the packet buffer. + * @pre `pkt != NULL` + * @pre `(pkt->size > 0) <=> (pkt->data != NULL)` + * @pre gnrc_pktsnip_t::data of @p pkt is in the packet buffer if it is not NULL. * * @details If enough memory is available behind it or @p size is smaller than * the original size of the packet then gnrc_pktsnip_t::data of @p pkt will @@ -128,7 +137,7 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_ * @param[in] size The size for @p pkt. * * @return 0, on success - * @return ENOMEM, if no space is left in the packet buffer or size was 0. + * @return ENOMEM, if no space is left in the packet buffer. */ int gnrc_pktbuf_realloc_data(gnrc_pktsnip_t *pkt, size_t size); diff --git a/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c b/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c index 298aa2abab..f8762b3001 100644 --- a/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c +++ b/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c @@ -94,8 +94,8 @@ gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, void *data, size_t size, { gnrc_pktsnip_t *pkt; - if ((size == 0) || (size > GNRC_PKTBUF_SIZE)) { - DEBUG("pktbuf: size (%u) == 0 || size == GNRC_PKTBUF_SIZE (%u)\n", + if (size > GNRC_PKTBUF_SIZE) { + DEBUG("pktbuf: size (%u) > GNRC_PKTBUF_SIZE (%u)\n", (unsigned)size, GNRC_PKTBUF_SIZE); return NULL; } @@ -122,19 +122,17 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_ mutex_unlock(&_mutex); return NULL; } - else if (size == pkt->size) { - pkt->type = type; - mutex_unlock(&_mutex); - return pkt; - } + /* create new snip descriptor for marked data */ marked_snip = _pktbuf_alloc(sizeof(gnrc_pktsnip_t)); if (marked_snip == NULL) { DEBUG("pktbuf: could not reallocate marked section.\n"); mutex_unlock(&_mutex); return NULL; } - /* would not fit unused marker => move data around */ - if ((size < required_new_size) || ((pkt->size - size) < sizeof(_unused_t))) { + /* marked data would not fit _unused_t marker => move data around to allow + * for proper free */ + if ((pkt->size != size) && + ((size < required_new_size) || ((pkt->size - size) < sizeof(_unused_t)))) { void *new_data_rest; new_data_marked = _pktbuf_alloc(size); if (new_data_marked == NULL) { @@ -159,7 +157,9 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_ } else { new_data_marked = pkt->data; - pkt->data = ((uint8_t *)pkt->data) + size; + /* if (pkt->size - size) != 0 take remainder of data, otherwise set NULL */ + pkt->data = (pkt->size != size) ? (((uint8_t *)pkt->data) + size) : + NULL; } pkt->size -= size; _set_pktsnip(marked_snip, pkt->next, new_data_marked, size, type); @@ -174,17 +174,23 @@ int gnrc_pktbuf_realloc_data(gnrc_pktsnip_t *pkt, size_t size) _align(sizeof(_unused_t)) : _align(size); mutex_lock(&_mutex); - assert((pkt != NULL) && (pkt->data != NULL) && _pktbuf_contains(pkt->data)); - if (size == 0) { - DEBUG("pktbuf: size == 0\n"); - mutex_unlock(&_mutex); - return ENOMEM; - } + assert(pkt != NULL); + assert(((pkt->size == 0) && (pkt->data == NULL)) || + ((pkt->size > 0) && (pkt->data != NULL) && _pktbuf_contains(pkt->data))); + /* new size and old size are equal */ if (size == pkt->size) { + /* nothing to do */ mutex_unlock(&_mutex); return 0; } - if ((size > pkt->size) || /* new size does not fit */ + /* new size is 0 and data pointer isn't already NULL */ + if ((size == 0) && (pkt->data != NULL)) { + /* set data pointer to NULL */ + _pktbuf_free(pkt->data, pkt->size); + pkt->data = NULL; + } + /* if new size is bigger than old size */ + else if ((size > pkt->size) || /* new size does not fit */ ((pkt->size - aligned_size) < sizeof(_unused_t))) { /* resulting hole would not fit marker */ void *new_data = _pktbuf_alloc(size); if (new_data == NULL) { @@ -192,15 +198,15 @@ int gnrc_pktbuf_realloc_data(gnrc_pktsnip_t *pkt, size_t size) mutex_unlock(&_mutex); return ENOMEM; } - memcpy(new_data, pkt->data, (pkt->size < size) ? pkt->size : size); + if (pkt->data != NULL) { /* if old data exist */ + memcpy(new_data, pkt->data, (pkt->size < size) ? pkt->size : size); + } _pktbuf_free(pkt->data, pkt->size); pkt->data = new_data; } - else { - if (_align(pkt->size) > aligned_size) { - _pktbuf_free(((uint8_t *)pkt->data) + aligned_size, - pkt->size - aligned_size); - } + else if (_align(pkt->size) > aligned_size) { + _pktbuf_free(((uint8_t *)pkt->data) + aligned_size, + pkt->size - aligned_size); } pkt->size = size; mutex_unlock(&_mutex); @@ -397,17 +403,19 @@ static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, void *data, size_t siz gnrc_nettype_t type) { gnrc_pktsnip_t *pkt = _pktbuf_alloc(sizeof(gnrc_pktsnip_t)); - void *_data; + void *_data = NULL; if (pkt == NULL) { DEBUG("pktbuf: error allocating new packet snip\n"); return NULL; } - _data = _pktbuf_alloc(size); - if (_data == NULL) { - DEBUG("pktbuf: error allocating data for new packet snip\n"); - _pktbuf_free(pkt, sizeof(gnrc_pktsnip_t)); - return NULL; + if (size > 0) { + _data = _pktbuf_alloc(size); + if (_data == NULL) { + DEBUG("pktbuf: error allocating data for new packet snip\n"); + _pktbuf_free(pkt, sizeof(gnrc_pktsnip_t)); + return NULL; + } } _set_pktsnip(pkt, next, _data, size, type); if (data != NULL) {