From a2eb3c7f15f128bdc6d11ca063b4fe57d938608c Mon Sep 17 00:00:00 2001
From: Martine Lenders <m.lenders@fu-berlin.de>
Date: Tue, 19 Jun 2018 14:59:49 +0200
Subject: [PATCH] gnrc_sixlowpan_frag: adapt for #8511

This refactors the `gnrc_sixlowpan_frag` module for the API proposed
in #8511.

The `ctx` for `gnrc_sixlowpan_frag_send()` is required to be a
`gnrc_sixlowpan_msg_frag_t` object, so IPHC can later on use it to
provide the *original* datagram size (otherwise, we would need to adapt
the API just for that, which seems to me as convoluted as this
proposal).

I also provide an expose function with a future possibility to provide
more than just one `gnrc_sixlowpan_msg_frag_t` object later on (plus
having cleaner module separation in general).
---
 sys/include/net/gnrc/sixlowpan/frag.h         | 35 ++++++++++++++-----
 .../sixlowpan/frag/gnrc_sixlowpan_frag.c      | 20 +++++++++--
 .../network_layer/sixlowpan/gnrc_sixlowpan.c  | 35 ++++++++-----------
 3 files changed, 59 insertions(+), 31 deletions(-)

diff --git a/sys/include/net/gnrc/sixlowpan/frag.h b/sys/include/net/gnrc/sixlowpan/frag.h
index 96841b882e..f557470ebc 100644
--- a/sys/include/net/gnrc/sixlowpan/frag.h
+++ b/sys/include/net/gnrc/sixlowpan/frag.h
@@ -74,26 +74,45 @@ typedef struct {
  */
 typedef struct {
     gnrc_pktsnip_t *pkt;    /**< Pointer to the IPv6 packet to be fragmented */
-    size_t datagram_size;   /**< Length of just the IPv6 packet to be fragmented */
+    size_t datagram_size;   /**< Length of just the (uncompressed) IPv6 packet to be fragmented */
     uint16_t offset;        /**< Offset of the Nth fragment from the beginning of the
                              *   payload datagram */
     kernel_pid_t pid;       /**< PID of the interface */
 } gnrc_sixlowpan_msg_frag_t;
 
 /**
- * @brief   Sends a packet fragmented.
+ * @brief   Allocates a @ref gnrc_sixlowpan_msg_frag_t object
  *
- * @param[in] fragment_msg    Message containing status of the 6LoWPAN
- *                            fragmentation progress
+ * @return  A @ref gnrc_sixlowpan_msg_frag_t if available
+ * @return  NULL, otherwise
  */
-void gnrc_sixlowpan_frag_send(gnrc_sixlowpan_msg_frag_t *fragment_msg);
+gnrc_sixlowpan_msg_frag_t *gnrc_sixlowpan_msg_frag_get(void);
 
 /**
- * @brief   Handles a packet containing a fragment header.
+ * @brief   Sends a packet fragmented
  *
- * @param[in] pkt   The packet to handle.
+ * @pre `ctx != NULL`
+ * @pre gnrc_sixlowpan_msg_frag_t::pkt of @p ctx is equal to @p pkt or
+ *      `pkt == NULL`.
+ *
+ * @param[in] pkt       A packet. May be NULL.
+ * @param[in] ctx       Message containing status of the 6LoWPAN fragmentation
+ *                      progress. Expected to be of type
+ *                      @ref gnrc_sixlowpan_msg_frag_t, with
+ *                      gnrc_sixlowpan_msg_frag_t set to @p pkt. Must not be
+ *                      NULL.
+ * @param[in] page      Current 6Lo dispatch parsing page.
+ */
+void gnrc_sixlowpan_frag_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page);
+
+/**
+ * @brief   Handles a packet containing a fragment header
+ *
+ * @param[in] pkt       The packet to handle
+ * @param[in] ctx       Context for the packet. May be NULL.
+ * @param[in] page      Current 6Lo dispatch parsing page.
  */
-void gnrc_sixlowpan_frag_handle_pkt(gnrc_pktsnip_t *pkt);
+void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page);
 
 #ifdef __cplusplus
 }
diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c b/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c
index ce137cdd73..6724dc929a 100644
--- a/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c
+++ b/sys/net/gnrc/network_layer/sixlowpan/frag/gnrc_sixlowpan_frag.c
@@ -31,6 +31,10 @@
 #define ENABLE_DEBUG    (0)
 #include "debug.h"
 
+static gnrc_sixlowpan_msg_frag_t _fragment_msg = {
+        NULL, 0, 0, KERNEL_PID_UNDEF
+    };
+
 #if ENABLE_DEBUG
 /* For PRIu16 etc. */
 #include <inttypes.h>
@@ -209,8 +213,15 @@ static uint16_t _send_nth_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt,
     return local_offset;
 }
 
-void gnrc_sixlowpan_frag_send(gnrc_sixlowpan_msg_frag_t *fragment_msg)
+gnrc_sixlowpan_msg_frag_t *gnrc_sixlowpan_msg_frag_get(void)
+{
+    return (_fragment_msg.pkt == NULL) ? &_fragment_msg : NULL;
+}
+
+void gnrc_sixlowpan_frag_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
 {
+    assert(ctx != NULL);
+    gnrc_sixlowpan_msg_frag_t *fragment_msg = ctx;
     gnrc_netif_t *iface = gnrc_netif_get_by_pid(fragment_msg->pid);
     uint16_t res;
     /* payload_len: actual size of the packet vs
@@ -218,6 +229,9 @@ void gnrc_sixlowpan_frag_send(gnrc_sixlowpan_msg_frag_t *fragment_msg)
     size_t payload_len = gnrc_pkt_len(fragment_msg->pkt->next);
     msg_t msg;
 
+    assert((fragment_msg->pkt == pkt) || (pkt == NULL));
+    (void)page;
+    (void)pkt;
 #if defined(DEVELHELP) && ENABLE_DEBUG
     if (iface == NULL) {
         DEBUG("6lo frag: iface == NULL, expect segmentation fault.\n");
@@ -275,13 +289,15 @@ void gnrc_sixlowpan_frag_send(gnrc_sixlowpan_msg_frag_t *fragment_msg)
     }
 }
 
-void gnrc_sixlowpan_frag_handle_pkt(gnrc_pktsnip_t *pkt)
+void gnrc_sixlowpan_frag_recv(gnrc_pktsnip_t *pkt, void *ctx, unsigned page)
 {
     gnrc_netif_hdr_t *hdr = pkt->next->data;
     sixlowpan_frag_t *frag = pkt->data;
     uint16_t offset = 0;
     size_t frag_size;
 
+    (void)ctx;
+    (void)page;
     switch (frag->disp_size.u8[0] & SIXLOWPAN_FRAG_DISP_MASK) {
         case SIXLOWPAN_FRAG_1_DISP:
             frag_size = (pkt->size - sizeof(sixlowpan_frag_t));
diff --git a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c
index cd744dd051..18c615851c 100644
--- a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c
+++ b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c
@@ -34,10 +34,6 @@
 
 static kernel_pid_t _pid = KERNEL_PID_UNDEF;
 
-#ifdef MODULE_GNRC_SIXLOWPAN_FRAG
-static gnrc_sixlowpan_msg_frag_t fragment_msg = {NULL, 0, 0, KERNEL_PID_UNDEF};
-#endif
-
 #if ENABLE_DEBUG
 static char _stack[GNRC_SIXLOWPAN_STACK_SIZE + THREAD_EXTRA_STACKSIZE_PRINTF];
 #else
@@ -164,7 +160,7 @@ static void _receive(gnrc_pktsnip_t *pkt)
 #ifdef MODULE_GNRC_SIXLOWPAN_FRAG
     else if (sixlowpan_frag_is((sixlowpan_frag_t *)dispatch)) {
         DEBUG("6lo: received 6LoWPAN fragment\n");
-        gnrc_sixlowpan_frag_handle_pkt(pkt);
+        gnrc_sixlowpan_frag_recv(pkt, NULL, 0);
         return;
     }
 #endif
@@ -305,27 +301,24 @@ static void _send(gnrc_pktsnip_t *pkt)
         return;
     }
 #ifdef MODULE_GNRC_SIXLOWPAN_FRAG
-    else if (fragment_msg.pkt != NULL) {
-        DEBUG("6lo: Fragmentation already ongoing. Dropping packet\n");
-        gnrc_pktbuf_release(pkt2);
-        return;
-    }
     else if (datagram_size <= SIXLOWPAN_FRAG_MAX_LEN) {
         DEBUG("6lo: Send fragmented (%u > %" PRIu8 ")\n",
               (unsigned int)datagram_size, iface->sixlo.max_frag_size);
-        msg_t msg;
+        gnrc_sixlowpan_msg_frag_t *fragment_msg;
 
-        fragment_msg.pid = hdr->if_pid;
-        fragment_msg.pkt = pkt2;
-        fragment_msg.datagram_size = datagram_size;
+        fragment_msg = gnrc_sixlowpan_msg_frag_get();
+        if (fragment_msg == NULL) {
+            DEBUG("6lo: Not enough resources to fragment packet. Dropping packet\n");
+            gnrc_pktbuf_release(pkt2);
+            return;
+        }
+        fragment_msg->pid = hdr->if_pid;
+        fragment_msg->pkt = pkt2;
+        fragment_msg->datagram_size = datagram_size;
         /* Sending the first fragment has an offset==0 */
-        fragment_msg.offset = 0;
+        fragment_msg->offset = 0;
 
-        /* set the outgoing message's fields */
-        msg.type = GNRC_SIXLOWPAN_MSG_FRAG_SND;
-        msg.content.ptr = &fragment_msg;
-        /* send message to self */
-        msg_send_to_self(&msg);
+        gnrc_sixlowpan_frag_send(pkt2, fragment_msg, 0);
     }
     else {
         DEBUG("6lo: packet too big (%u > %" PRIu16 ")\n",
@@ -380,7 +373,7 @@ static void *_event_loop(void *args)
 #ifdef MODULE_GNRC_SIXLOWPAN_FRAG
             case GNRC_SIXLOWPAN_MSG_FRAG_SND:
                 DEBUG("6lo: send fragmented event received\n");
-                gnrc_sixlowpan_frag_send(msg.content.ptr);
+                gnrc_sixlowpan_frag_send(NULL, msg.content.ptr, 0);
                 break;
 #endif
 
-- 
GitLab