From 6443a2bb5ceab61b9f65a1ea1e7c5f6a72f889bb Mon Sep 17 00:00:00 2001
From: Yonezawa-T2 <Yonezawa-T2@mail.dnp.co.jp>
Date: Mon, 7 Mar 2016 16:33:21 +0900
Subject: [PATCH] gnrc_pktbuf: Adds a function to duplicate packet chain

---
 sys/include/net/gnrc/pkt.h                    |  25 ++++
 sys/include/net/gnrc/pktbuf.h                 |  50 ++++++++
 .../network_layer/ipv6/ext/gnrc_ipv6_ext.c    | 112 +-----------------
 .../gnrc/pktbuf_static/gnrc_pktbuf_static.c   |  59 ++++++++-
 4 files changed, 134 insertions(+), 112 deletions(-)

diff --git a/sys/include/net/gnrc/pkt.h b/sys/include/net/gnrc/pkt.h
index 2fb788c538..b068ca3b00 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 420b59c538..f7e1117283 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 054c97ae4a..fe0936f29f 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 0bc89cc127..298aa2abab 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;
+}
+
 /** @} */
-- 
GitLab