diff --git a/sys/include/net/gnrc/pkt.h b/sys/include/net/gnrc/pkt.h index 2fb788c5389ce5f2acfba8e6ed5b4e0574ff7503..b068ca3b00c56d7848d5126c6f14887e497e19e1 100644 --- a/sys/include/net/gnrc/pkt.h +++ b/sys/include/net/gnrc/pkt.h @@ -136,6 +136,31 @@ static inline size_t gnrc_pkt_len(gnrc_pktsnip_t *pkt) return len; } +/** + * @brief Calculates length of a packet in byte upto (including) a snip with the given type. + * + * @param[in] pkt list of packet snips. + * @param[in] type type of snip to stop calculation. + * + * @return length of the list of headers. + */ +static inline size_t gnrc_pkt_len_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type) +{ + size_t len = 0; + + while (pkt) { + len += pkt->size; + + if (pkt->type == type) { + break; + } + + pkt = pkt->next; + } + + return len; +} + /** * @brief Count the numbers of snips in the given packet * diff --git a/sys/include/net/gnrc/pktbuf.h b/sys/include/net/gnrc/pktbuf.h index 420b59c538e67130e5eff3b3d6d8232db4851bcf..f7e11172836dfe26964db5e7e717c3a9203ebeaa 100644 --- a/sys/include/net/gnrc/pktbuf.h +++ b/sys/include/net/gnrc/pktbuf.h @@ -215,6 +215,56 @@ gnrc_pktsnip_t *gnrc_pktbuf_remove_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *sni */ gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *old, gnrc_pktsnip_t *add); +/** + * @brief Duplicates pktsnip chain upto (including) a snip with the given type + * as a continuous snip. + * + * Example: + * Input: + * buffer + * +---------------------------+ +------+ + * | size = 8 | data +-------->| | + * | type = NETTYPE_IPV6_EXT |------------+ +------+ + * +---------------------------+ . . + * | next . . + * v . . + * +---------------------------+ +------+ + * | size = 40 | data +----------->| | + * | type = NETTYPE_IPV6 |---------+ +------+ + * +---------------------------+ . . + * | next . . + * v + * +---------------------------+ +------+ + * | size = 14 | data +-------------->| | + * | type = NETTYPE_NETIF |------+ +------+ + * +---------------------------+ . . + * + * + * Output: + * buffer + * +---------------------------+ +------+ + * | size = 48 | data +-------->| | + * | type = NETTYPE_IPV6 |------------+ | | + * +---------------------------+ | | + * | +------+ + * | . . + * | next . . + * v + * +---------------------------+ +------+ + * | size = 14 | data +-------------->| | + * | type = NETTYPE_NETIF |------+ +------+ + * +---------------------------+ . . + * + * The original snip is keeped as is except `users` decremented. + * + * @param[in,out] pkt The snip to duplicate. + * @param[in] type The type of snip to stop duplication. + * + * @return The duplicated snip, if succeeded. + * @return NULL, if no space is left in the packet buffer. + */ +gnrc_pktsnip_t *gnrc_pktbuf_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type); + #ifdef DEVELHELP /** * @brief Prints some statistics about the packet buffer to stdout. diff --git a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c index 054c97ae4a55edc888b8e231e22f2b321f65b3d1..fe0936f29fd668f19f75bcc715790c4707ec50e0 100644 --- a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c +++ b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c @@ -25,114 +25,6 @@ #ifdef MODULE_GNRC_RPL_SRH -static size_t _cumulate_size_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type) -{ - size_t sum = 0; - - for (; pkt != NULL; pkt = pkt->next) { - sum += pkt->size; - - if (pkt->type == type) { - break; - } - } - - return sum; -} - -/** - * @brief duplicates pktsnip chain upto (including) a snip with the given type - * as a continuous snip. - * - * Example: - * Input: - * buffer - * +---------------------------+ +------+ - * | size = 8 | data +-------->| | - * | type = NETTYPE_IPV6_EXT |------------+ +------+ - * +---------------------------+ . . - * | next . . - * v . . - * +---------------------------+ +------+ - * | size = 40 | data +----------->| | - * | type = NETTYPE_IPV6 |---------+ +------+ - * +---------------------------+ . . - * | next . . - * v - * +---------------------------+ +------+ - * | size = 14 | data +-------------->| | - * | type = NETTYPE_NETIF |------+ +------+ - * +---------------------------+ . . - * - * - * Output: - * buffer - * +---------------------------+ +------+ - * | size = 48 | data +-------->| | - * | type = NETTYPE_IPV6 |------------+ | | - * +---------------------------+ | | - * | +------+ - * | . . - * | next . . - * v - * +---------------------------+ +------+ - * | size = 14 | data +-------------->| | - * | type = NETTYPE_NETIF |------+ +------+ - * +---------------------------+ . . - * - * The original snip is keeped as is except `users` decremented. - * - * @param[in,out] pkt The snip to duplicate. - * @param[in] type The type of snip to stop duplication. - * - * @return The duplicated snip, if succeeded. - * @return NULL, if no space is left in the packet buffer. - */ -static gnrc_pktsnip_t *_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type) -{ - bool is_shared = pkt->users > 1; - size_t size = _cumulate_size_upto(pkt, type); - - DEBUG("ipv6_ext: duplicating %d octets\n", (int) size); - - gnrc_pktsnip_t *tmp; - gnrc_pktsnip_t *target = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); - gnrc_pktsnip_t *next = (target == NULL) ? NULL : target->next; - gnrc_pktsnip_t *new = gnrc_pktbuf_add(next, NULL, size, type); - - if (new == NULL) { - return NULL; - } - - /* copy payloads */ - for (tmp = pkt; tmp != NULL; tmp = tmp->next) { - uint8_t *dest = ((uint8_t *)new->data) + (size - tmp->size); - - memcpy(dest, tmp->data, tmp->size); - - size -= tmp->size; - - if (tmp->type == type) { - break; - } - } - - /* decrements reference counters */ - - if (target != NULL) { - target->next = NULL; - } - - gnrc_pktbuf_release(pkt); - - if (is_shared && (target != NULL)) { - target->next = next; - } - - return new; -} - - enum gnrc_ipv6_ext_demux_status { GNRC_IPV6_EXT_OK, GNRC_IPV6_EXT_FORWARDED, @@ -155,10 +47,10 @@ static enum gnrc_ipv6_ext_demux_status _handle_rh(gnrc_pktsnip_t *current, gnrc_ the head. `ipv6_ext_rh_process` modifies the IPv6 header as well as the extension header */ - current_offset = _cumulate_size_upto(current->next, GNRC_NETTYPE_IPV6); + current_offset = gnrc_pkt_len_upto(current->next, GNRC_NETTYPE_IPV6); if (pkt->users != 1) { - if ((ipv6 = _duplicate_upto(pkt, GNRC_NETTYPE_IPV6)) == NULL) { + if ((ipv6 = gnrc_pktbuf_duplicate_upto(pkt, GNRC_NETTYPE_IPV6)) == NULL) { DEBUG("ipv6: could not get a copy of pkt\n"); gnrc_pktbuf_release(pkt); return GNRC_IPV6_EXT_ERROR; diff --git a/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c b/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c index 0bc89cc127dec2d42fc96036377e603dea1bad00..298aa2abab26dae2771da3a86b56b93ae38bdfcf 100644 --- a/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c +++ b/sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c @@ -217,9 +217,8 @@ void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num) mutex_unlock(&_mutex); } -void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err) +static void _release_error_locked(gnrc_pktsnip_t *pkt, uint32_t err) { - mutex_lock(&_mutex); while (pkt) { gnrc_pktsnip_t *tmp; assert(_pktbuf_contains(pkt)); @@ -236,6 +235,12 @@ void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err) gnrc_neterr_report(pkt, err); pkt = tmp; } +} + +void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err) +{ + mutex_lock(&_mutex); + _release_error_locked(pkt, err); mutex_unlock(&_mutex); } @@ -526,4 +531,54 @@ gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *ol return pkt; } +gnrc_pktsnip_t *gnrc_pktbuf_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type) +{ + mutex_lock(&_mutex); + + bool is_shared = pkt->users > 1; + size_t size = gnrc_pkt_len_upto(pkt, type); + + DEBUG("ipv6_ext: duplicating %d octets\n", (int) size); + + gnrc_pktsnip_t *tmp; + gnrc_pktsnip_t *target = gnrc_pktsnip_search_type(pkt, type); + gnrc_pktsnip_t *next = (target == NULL) ? NULL : target->next; + gnrc_pktsnip_t *new = _create_snip(next, NULL, size, type); + + if (new == NULL) { + mutex_unlock(&_mutex); + + return NULL; + } + + /* copy payloads */ + for (tmp = pkt; tmp != NULL; tmp = tmp->next) { + uint8_t *dest = ((uint8_t *)new->data) + (size - tmp->size); + + memcpy(dest, tmp->data, tmp->size); + + size -= tmp->size; + + if (tmp->type == type) { + break; + } + } + + /* decrements reference counters */ + + if (target != NULL) { + target->next = NULL; + } + + _release_error_locked(pkt, GNRC_NETERR_SUCCESS); + + if (is_shared && (target != NULL)) { + target->next = next; + } + + mutex_unlock(&_mutex); + + return new; +} + /** @} */