diff --git a/sys/include/net/gnrc/pktbuf.h b/sys/include/net/gnrc/pktbuf.h
index f9f29850b7b213851ff8a3d549e2537c53db9f9a..ad109bb3ef055990c22349672c676926af04cb8a 100644
--- a/sys/include/net/gnrc/pktbuf.h
+++ b/sys/include/net/gnrc/pktbuf.h
@@ -298,6 +298,60 @@ 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;
+}
 
 /** @} */
diff --git a/tests/unittests/tests-pktbuf/tests-pktbuf.c b/tests/unittests/tests-pktbuf/tests-pktbuf.c
index 64d000b26ab127c9964b7de03b4c625fba7cc3c7..8f204afa85a9d79ab20bc88d4d68ea380e1c223a 100644
--- a/tests/unittests/tests-pktbuf/tests-pktbuf.c
+++ b/tests/unittests/tests-pktbuf/tests-pktbuf.c
@@ -653,6 +653,52 @@ static void test_pktbuf_realloc_data__success3(void)
     TEST_ASSERT(gnrc_pktbuf_is_empty());
 }
 
+static void test_pktbuf_merge_data__memfull(void)
+{
+    gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, (GNRC_PKTBUF_SIZE / 4),
+                                          GNRC_NETTYPE_TEST);
+
+    pkt = gnrc_pktbuf_add(pkt, NULL, (GNRC_PKTBUF_SIZE / 4) + 1,
+                          GNRC_NETTYPE_TEST);
+    TEST_ASSERT_EQUAL_INT(ENOMEM, gnrc_pktbuf_merge(pkt));
+    gnrc_pktbuf_release(pkt);
+    TEST_ASSERT(gnrc_pktbuf_is_empty());
+}
+
+static void test_pktbuf_merge_data__success1(void)
+{
+    gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, 0, GNRC_NETTYPE_TEST);
+
+    TEST_ASSERT_NOT_NULL(pkt);
+    TEST_ASSERT_NULL(pkt->data);
+
+    TEST_ASSERT_EQUAL_INT(0, gnrc_pktbuf_merge(pkt));
+    gnrc_pktbuf_release(pkt);
+    TEST_ASSERT(gnrc_pktbuf_is_empty());
+}
+
+static void test_pktbuf_merge_data__success2(void)
+{
+    gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, TEST_STRING4,
+                                          sizeof(TEST_STRING4),
+                                          GNRC_NETTYPE_TEST);
+
+    pkt = gnrc_pktbuf_add(pkt, TEST_STRING8, sizeof(TEST_STRING8), GNRC_NETTYPE_TEST);
+    pkt = gnrc_pktbuf_add(pkt, TEST_STRING16, sizeof(TEST_STRING16), GNRC_NETTYPE_TEST);
+
+    TEST_ASSERT_EQUAL_INT(0, gnrc_pktbuf_merge(pkt));
+    TEST_ASSERT_NULL(pkt->next);
+    TEST_ASSERT_EQUAL_STRING(TEST_STRING16, pkt->data);
+    TEST_ASSERT_EQUAL_STRING(TEST_STRING8,
+                             (char *) pkt->data + sizeof(TEST_STRING16));
+    TEST_ASSERT_EQUAL_STRING(TEST_STRING4,
+                             (char *) pkt->data + sizeof(TEST_STRING16) +
+                             sizeof(TEST_STRING8));
+    gnrc_pktbuf_release(pkt);
+    TEST_ASSERT(gnrc_pktbuf_is_empty());
+    TEST_ASSERT(gnrc_pktbuf_is_sane());
+}
+
 static void test_pktbuf_hold__pkt_null(void)
 {
     gnrc_pktbuf_hold(NULL, 1);
@@ -895,6 +941,9 @@ Test *tests_pktbuf_tests(void)
         new_TestFixture(test_pktbuf_realloc_data__success),
         new_TestFixture(test_pktbuf_realloc_data__success2),
         new_TestFixture(test_pktbuf_realloc_data__success3),
+        new_TestFixture(test_pktbuf_merge_data__memfull),
+        new_TestFixture(test_pktbuf_merge_data__success1),
+        new_TestFixture(test_pktbuf_merge_data__success2),
         new_TestFixture(test_pktbuf_hold__pkt_null),
         new_TestFixture(test_pktbuf_hold__pkt_external),
         new_TestFixture(test_pktbuf_hold__success),