diff --git a/sys/include/net/gnrc/pktbuf.h b/sys/include/net/gnrc/pktbuf.h index f9f29850b7b213851ff8a3d549e2537c53db9f9a..cf7a7a673639406769651866e2e207633e377ee8 100644 --- a/sys/include/net/gnrc/pktbuf.h +++ b/sys/include/net/gnrc/pktbuf.h @@ -298,6 +298,56 @@ gnrc_pktsnip_t *gnrc_pktbuf_reverse_snips(gnrc_pktsnip_t *pkt); */ gnrc_pktsnip_t *gnrc_pktbuf_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type); +/** + * @brief Merge pktsnip chain to single pktsnip. + * + * Specifically it calls @ref gnrc_pktbuf_realloc_data() on @p pkt, then copies + * the data of all following packet snips into that reallocated space, and + * removes the packet snip the data was copied from afterwards. + * + * Example: + * Input: + * buffer + * +---------------------------+ +------+ + * | size = 8 | data +-------->| | + * | type = NETTYPE_IPV6 |------------+ +------+ + * +---------------------------+ . . + * | next . . + * v . . + * +---------------------------+ +------+ + * | size = 40 | data +----------->| | + * | type = NETTYPE_UDP |---------+ +------+ + * +---------------------------+ . . + * | next . . + * v + * +---------------------------+ +------+ + * | size = 14 | data +-------------->| | + * | type = NETTYPE_UNDEF |------+ +------+ + * +---------------------------+ . . + * + * + * Output: + * buffer + * +---------------------------+ +------+ + * | size = 62 | data +-------->| | + * | type = NETTYPE_IPV6 |------------+ | | + * +---------------------------+ | | + * | | + * +------+ + * . . + * + * @warning @p pkt needs to write protected before calling this function. + * @note Packets in receive order need to call + * @ref gnrc_pktbuf_reverse_snips() first to get the data in the + * correct order. + * + * @param[in,out] pkt The snip to merge. + * + * @return 0, on success + * @return ENOMEM, if no space is left in the packet buffer. + */ +int gnrc_pktbuf_merge(gnrc_pktsnip_t *pkt); + #ifdef DEVELHELP /** * @brief Prints some statistics about the packet buffer to stdout. diff --git a/sys/net/gnrc/pktbuf/gnrc_pktbuf.c b/sys/net/gnrc/pktbuf/gnrc_pktbuf.c index 83e0a89e3121d9f6990b1136bd35d3ae63a37c5a..503e66c7b3806047fbc1fdecc152660ff64b58e6 100644 --- a/sys/net/gnrc/pktbuf/gnrc_pktbuf.c +++ b/sys/net/gnrc/pktbuf/gnrc_pktbuf.c @@ -109,5 +109,32 @@ gnrc_pktsnip_t *gnrc_pktbuf_reverse_snips(gnrc_pktsnip_t *pkt) return reversed; } +int gnrc_pktbuf_merge(gnrc_pktsnip_t *pkt) +{ + size_t offset = pkt->size; + size_t size = gnrc_pkt_len(pkt); + int res = 0; + + if (pkt->size == size) { + return res; + } + + /* Re-allocate data */ + res = gnrc_pktbuf_realloc_data(pkt, size); + if (res != 0) { + return res; + } + + /* Copy data to new buffer */ + for (gnrc_pktsnip_t *ptr = pkt->next; ptr != NULL; ptr = ptr->next) { + memcpy(((uint8_t *)pkt->data) + offset, ptr->data, ptr->size); + offset += ptr->size; + } + + /* Release old pktsnips and data*/ + gnrc_pktbuf_release(pkt->next); + pkt->next = NULL; + return res; +} /** @} */