From dc2113d67a27ab3142c8f136408d330f6bfde5bb Mon Sep 17 00:00:00 2001
From: Martine Lenders <mail@martine-lenders.eu>
Date: Wed, 22 Jul 2015 20:56:17 +0200
Subject: [PATCH] ng_sixlowpan_frag: fixes

---
 .../ng_sixlowpan/frag/ng_sixlowpan_frag.c     |   7 +-
 .../network_layer/ng_sixlowpan/frag/rbuf.c    |  90 ++++++---------
 .../network_layer/ng_sixlowpan/frag/rbuf.h    |   2 +-
 .../network_layer/ng_sixlowpan/ng_sixlowpan.c | 107 ++++++++----------
 4 files changed, 89 insertions(+), 117 deletions(-)

diff --git a/sys/net/network_layer/ng_sixlowpan/frag/ng_sixlowpan_frag.c b/sys/net/network_layer/ng_sixlowpan/frag/ng_sixlowpan_frag.c
index e9bb35ecd8..c31a77600a 100644
--- a/sys/net/network_layer/ng_sixlowpan/frag/ng_sixlowpan_frag.c
+++ b/sys/net/network_layer/ng_sixlowpan/frag/ng_sixlowpan_frag.c
@@ -191,7 +191,7 @@ static uint16_t _send_nth_fragment(ng_sixlowpan_netif_t *iface, ng_pktsnip_t *pk
         }
     }
 
-    DEBUG("6lo frag: send first fragment (datagram size: %u, "
+    DEBUG("6lo frag: send subsequent fragment (datagram size: %u, "
           "datagram tag: %" PRIu16 ", offset: %" PRIu8 " (%u bytes), "
           "fragment size: %" PRIu16 ")\n",
           (unsigned int)datagram_size, _tag, hdr->offset, hdr->offset << 3,
@@ -217,6 +217,7 @@ void ng_sixlowpan_frag_send(kernel_pid_t pid, ng_pktsnip_t *pkt,
 
     if ((res = _send_1st_fragment(iface, pkt, payload_len, datagram_size)) == 0) {
         /* error sending first fragment */
+        DEBUG("6lo frag: error sending 1st fragment\n");
         ng_pktbuf_release(pkt);
         return;
     }
@@ -226,7 +227,9 @@ void ng_sixlowpan_frag_send(kernel_pid_t pid, ng_pktsnip_t *pkt,
     while (offset < datagram_size) {
         if ((res = _send_nth_fragment(iface, pkt, payload_len, datagram_size,
                                       offset)) == 0) {
-            /* error sending first fragment */
+            /* error sending subsequent fragment */
+            DEBUG("6lo frag: error sending subsequent fragment (offset = %" PRIu16
+                  ")\n", offset);
             ng_pktbuf_release(pkt);
             return;
         }
diff --git a/sys/net/network_layer/ng_sixlowpan/frag/rbuf.c b/sys/net/network_layer/ng_sixlowpan/frag/rbuf.c
index 6ca8d22d16..7d6ac64dac 100644
--- a/sys/net/network_layer/ng_sixlowpan/frag/rbuf.c
+++ b/sys/net/network_layer/ng_sixlowpan/frag/rbuf.c
@@ -16,10 +16,7 @@
 #include <stdbool.h>
 
 #include "rbuf.h"
-#include "net/ng_netapi.h"
-#include "net/ng_netif.h"
-#include "net/ng_netif/hdr.h"
-#include "net/ng_pktbuf.h"
+#include "net/ng_netbase.h"
 #include "net/ng_ipv6/netif.h"
 #include "net/ng_sixlowpan.h"
 #include "net/ng_sixlowpan/frag.h"
@@ -67,7 +64,6 @@ void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
     rbuf_t *entry;
     rbuf_int_t *ptr;
     uint8_t *data = ((uint8_t *)frag) + sizeof(ng_sixlowpan_frag_t);
-    uint16_t dg_frag_size = frag_size; /* may differ on first fragment */
 
     _rbuf_gc();
     entry = _rbuf_get(ng_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len,
@@ -83,10 +79,12 @@ void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
     ptr = entry->ints;
 
     /* dispatches in the first fragment are ignored */
-    if (offset != 0) {
-        switch (((uint8_t *)(entry->pkt->data))[0]) {
+    if (offset == 0) {
+        switch (data[0]) {
             case NG_SIXLOWPAN_UNCOMPRESSED:
-                offset++;
+                data++;             /* skip 6LoWPAN dispatch */
+                frag_size--;
+                entry->compressed = 0;  /* datagram is not compressed */
 
                 break;
 
@@ -94,19 +92,9 @@ void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
                 break;
         }
 
-        data++;     /* also don't take offset field */
     }
     else {
-        switch (data[0]) {
-            case NG_SIXLOWPAN_UNCOMPRESSED:
-                dg_frag_size--;
-
-                break;
-
-            default:
-                break;
-        }
-
+        data++; /* FRAGN header is one byte longer (offset) */
     }
 
     if ((offset + frag_size) > entry->pkt->size) {
@@ -117,7 +105,7 @@ void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
     }
 
     while (ptr != NULL) {
-        if (_rbuf_int_in(ptr, offset, offset + dg_frag_size - 1)) {
+        if (_rbuf_int_in(ptr, offset, offset + frag_size - 1)) {
             DEBUG("6lo rfrag: overlapping or same intervals, discarding datagram\n");
             ng_pktbuf_release(entry->pkt);
             _rbuf_rem(entry);
@@ -127,31 +115,13 @@ void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
         ptr = ptr->next;
     }
 
-    if (_rbuf_update_ints(entry, offset, dg_frag_size)) {
-        if (dg_frag_size < frag_size) {
-            /* some dispatches do not count to datagram size and we need
-             * more space because of that */
-            if (ng_pktbuf_realloc_data(entry->pkt, entry->pkt->size +
-                                       (frag_size - dg_frag_size)) < 0) {
-                DEBUG("6lo rbuf: could not reallocate packet data.\n");
-                return;
-            }
-
-            /* move already inserted fragments (frag_size - dg_frag_size) to the right */
-            if (entry->cur_size > 0) {
-                for (int i = entry->pkt->size - (frag_size - dg_frag_size); i > 0; i--) {
-                    uint8_t *d = ((uint8_t *)(entry->pkt->data)) + i;
-                    *d = *(d - 1);
-                }
-            }
-        }
-
+    if (_rbuf_update_ints(entry, offset, frag_size)) {
         DEBUG("6lo rbuf: add fragment data\n");
-        entry->cur_size += (uint16_t)dg_frag_size;
+        entry->cur_size += (uint16_t)frag_size;
         memcpy(((uint8_t *)entry->pkt->data) + offset, data, frag_size);
     }
 
-    if (entry->cur_size == entry->datagram_size) {
+    if (entry->cur_size == entry->pkt->size) {
         kernel_pid_t iface = netif_hdr->if_pid;
         ng_pktsnip_t *netif = ng_netif_hdr_build(entry->src, entry->src_len,
                               entry->dst, entry->dst_len);
@@ -159,6 +129,7 @@ void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
         if (netif == NULL) {
             DEBUG("6lo rbuf: error allocating netif header\n");
             ng_pktbuf_release(entry->pkt);
+            _rbuf_rem(entry);
             return;
         }
 
@@ -166,8 +137,18 @@ void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
         netif_hdr->if_pid = iface;
         LL_APPEND(entry->pkt, netif);
 
-        DEBUG("6lo rbuf: datagram complete, send to self\n");
-        ng_netapi_receive(thread_getpid(), entry->pkt);
+        if (entry->compressed) {
+            DEBUG("6lo rbuf: datagram complete, send to self for decompression\n");
+            ng_netapi_receive(thread_getpid(), entry->pkt);
+        }
+        else {
+            DEBUG("6lo rbuf: datagram complete, send to IPv6 listeners\n");
+            if (!ng_netapi_dispatch_receive(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL,
+                                            entry->pkt)) {
+                DEBUG("6lo rbuf: No receivers for this packet found\n");
+                ng_pktbuf_release(entry->pkt);
+            }
+        }
         _rbuf_rem(entry);
     }
 }
@@ -222,9 +203,9 @@ static bool _rbuf_update_ints(rbuf_t *entry, uint16_t offset, size_t frag_size)
     DEBUG("6lo rfrag: add interval (%" PRIu16 ", %" PRIu16 ") to entry (%s, ",
           new->start, new->end, ng_netif_addr_to_str(l2addr_str,
                   sizeof(l2addr_str), entry->src, entry->src_len));
-    DEBUG("%s, %u, %" PRIu16 ")\n", ng_netif_addr_to_str(l2addr_str,
-          sizeof(l2addr_str), entry->dst, entry->dst_len), entry->datagram_size,
-          entry->tag);
+    DEBUG("%s, %u, %u)\n", ng_netif_addr_to_str(l2addr_str,
+          sizeof(l2addr_str), entry->dst, entry->dst_len),
+          (unsigned)entry->pkt->size, entry->tag);
 
     LL_PREPEND(entry->ints, new);
 
@@ -247,10 +228,10 @@ static void _rbuf_gc(void)
                  ((now.seconds - rbuf[i].arrival) > RBUF_TIMEOUT)) {
             DEBUG("6lo rfrag: entry (%s, ", ng_netif_addr_to_str(l2addr_str,
                   sizeof(l2addr_str), rbuf[i].src, rbuf[i].src_len));
-            DEBUG("%s, %u, %" PRIu16 ") timed out\n",
+            DEBUG("%s, %u, %u) timed out\n",
                   ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str), rbuf[i].dst,
                                        rbuf[i].dst_len),
-                  rbuf[i].datagram_size, rbuf[i].tag);
+                  (unsigned)rbuf[i].pkt->size, rbuf[i].tag);
 
             ng_pktbuf_release(rbuf[i].pkt);
             _rbuf_rem(&(rbuf[i]));
@@ -278,7 +259,7 @@ static rbuf_t *_rbuf_get(const void *src, size_t src_len,
 
     for (unsigned int i = 0; i < RBUF_SIZE; i++) {
         /* check first if entry already available */
-        if ((rbuf[i].pkt != NULL) && (rbuf[i].datagram_size == size) &&
+        if ((rbuf[i].pkt != NULL) && (rbuf[i].pkt->size == size) &&
             (rbuf[i].tag == tag) && (rbuf[i].src_len == src_len) &&
             (rbuf[i].dst_len == dst_len) &&
             (memcmp(rbuf[i].src, src, src_len) == 0) &&
@@ -286,10 +267,10 @@ static rbuf_t *_rbuf_get(const void *src, size_t src_len,
             DEBUG("6lo rfrag: entry %p (%s, ", (void *)(&rbuf[i]),
                   ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str),
                                        rbuf[i].src, rbuf[i].src_len));
-            DEBUG("%s, %u, %" PRIu16 ") found\n",
+            DEBUG("%s, %u, %u) found\n",
                   ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str),
                                        rbuf[i].dst, rbuf[i].dst_len),
-                  rbuf[i].datagram_size, rbuf[i].tag);
+                  (unsigned)rbuf[i].pkt->size, rbuf[i].tag);
             rbuf[i].arrival = now.seconds;
             return &(rbuf[i]);
         }
@@ -315,15 +296,16 @@ static rbuf_t *_rbuf_get(const void *src, size_t src_len,
         res->src_len = src_len;
         res->dst_len = dst_len;
         res->tag = tag;
-        res->datagram_size = size;
         res->cur_size = 0;
+        res->compressed = 1;
 
         DEBUG("6lo rfrag: entry %p (%s, ", (void *)res,
               ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str), res->src,
                                    res->src_len));
-        DEBUG("%s, %u, %" PRIu16 ") created\n",
+        DEBUG("%s, %u, %u) created\n",
               ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str), res->dst,
-                                   res->dst_len), res->datagram_size, res->tag);
+                                   res->dst_len), (unsigned)res->pkt->size,
+                                   res->tag);
     }
 
     return res;
diff --git a/sys/net/network_layer/ng_sixlowpan/frag/rbuf.h b/sys/net/network_layer/ng_sixlowpan/frag/rbuf.h
index 61675f856b..2a96ff6556 100644
--- a/sys/net/network_layer/ng_sixlowpan/frag/rbuf.h
+++ b/sys/net/network_layer/ng_sixlowpan/frag/rbuf.h
@@ -77,8 +77,8 @@ typedef struct {
     uint8_t src_len;                    /**< length of source address */
     uint8_t dst_len;                    /**< length of destination address */
     uint16_t tag;                       /**< the datagram's tag */
-    uint16_t datagram_size;             /**< the datagram's size (without 6lo dispatches) */
     uint16_t cur_size;                  /**< the datagram's current size */
+    uint16_t compressed;                /**< the datagram has a compressed header */
 } rbuf_t;
 
 /**
diff --git a/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
index 0acdd4f599..b89d48251e 100644
--- a/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
+++ b/sys/net/network_layer/ng_sixlowpan/ng_sixlowpan.c
@@ -146,18 +146,31 @@ static void _receive(ng_pktsnip_t *pkt)
     }
 }
 
+static inline bool _add_uncompr_disp(ng_pktsnip_t *pkt)
+{
+    ng_pktsnip_t *sixlowpan;
+    uint8_t *disp;
+
+    DEBUG("6lo: Send uncompressed\n");
+
+    sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN);
+
+    if (sixlowpan == NULL) {
+        return false;
+    }
+    sixlowpan->next = pkt->next;
+    pkt->next = sixlowpan;
+    disp = sixlowpan->data;
+    disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
+    return true;
+}
+
 static void _send(ng_pktsnip_t *pkt)
 {
     ng_netif_hdr_t *hdr;
-    ng_pktsnip_t *ipv6, *sixlowpan;
+    ng_pktsnip_t *pkt2;
     ng_sixlowpan_netif_t *iface;
-    /* cppcheck: datagram_size will be read by frag */
-    /* cppcheck-suppress unreadVariable */
-    size_t payload_len, datagram_size;
-    uint16_t max_frag_size;
-    /* cppcheck: disp is needed in other build paths on this level already */
-    /* cppcheck-suppress variableScope */
-    uint8_t *disp;
+    size_t datagram_size, dispatch_len = 0;
 
     if ((pkt == NULL) || (pkt->size < sizeof(ng_netif_hdr_t))) {
         DEBUG("6lo: Sending packet has no netif header\n");
@@ -165,33 +178,21 @@ static void _send(ng_pktsnip_t *pkt)
         return;
     }
 
-    hdr = pkt->data;
-    ipv6 = pkt->next;
-
-    if ((ipv6 == NULL) || (ipv6->type != NG_NETTYPE_IPV6)) {
+    if ((pkt->next == NULL) || (pkt->next->type != NG_NETTYPE_IPV6)) {
         DEBUG("6lo: Sending packet has no IPv6 header\n");
         ng_pktbuf_release(pkt);
         return;
     }
 
-    /* payload length and datagram size are different in that the payload
-     * length is the length of the IPv6 datagram + 6LoWPAN dispatches,
-     * while the datagram size is the size of only the IPv6 datagram */
-    payload_len = ng_pkt_len(ipv6);
-    /* cppcheck: datagram_size will be read by ng_sixlowpan_frag implementation */
-    /* cppcheck-suppress unreadVariable */
-    datagram_size = (uint16_t)payload_len;
+    pkt2 = ng_pktbuf_start_write(pkt);
 
-    /* use sixlowpan packet snip as temporary one */
-    sixlowpan = ng_pktbuf_start_write(pkt);
-
-    if (sixlowpan == NULL) {
+    if (pkt2 == NULL) {
         DEBUG("6lo: no space left in packet buffer\n");
         ng_pktbuf_release(pkt);
         return;
     }
 
-    pkt = sixlowpan;
+    hdr = pkt2->data;
     iface = ng_sixlowpan_netif_get(hdr->if_pid);
 
     if (iface == NULL) {
@@ -212,73 +213,59 @@ static void _send(ng_pktsnip_t *pkt)
 
 #ifdef MODULE_NG_SIXLOWPAN_IPHC
     if (iface->iphc_enabled) {
-        if (!ng_sixlowpan_iphc_encode(pkt)) {
+        if (!ng_sixlowpan_iphc_encode(pkt2)) {
             DEBUG("6lo: error on IPHC encoding\n");
-            ng_pktbuf_release(pkt);
+            ng_pktbuf_release(pkt2);
             return;
         }
+        /* IPHC dispatch does not count on dispatch length since it _shortens_
+         * the datagram */
     }
     else {
-        DEBUG("6lo: Send uncompressed\n");
-
-        sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t),
-                                  NG_NETTYPE_SIXLOWPAN);
-
-        if (sixlowpan == NULL) {
+        if (!_add_uncompr_disp(pkt2)) {
+            /* adding uncompressed dispatch failed */
             DEBUG("6lo: no space left in packet buffer\n");
-            ng_pktbuf_release(pkt);
+            ng_pktbuf_release(pkt2);
             return;
         }
-
-        sixlowpan->next = ipv6;
-        pkt->next = sixlowpan;
-        disp = sixlowpan->data;
-        disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
-        payload_len++;
+        dispatch_len += 1;
     }
 #else
     /* suppress clang-analyzer report about iface being not read */
     (void) iface;
-
-    DEBUG("6lo: Send uncompressed\n");
-
-    sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN);
-
-    if (sixlowpan == NULL) {
+    if (!_add_uncompr_disp(pkt2)) {
+        /* adding uncompressed dispatch failed */
         DEBUG("6lo: no space left in packet buffer\n");
-        ng_pktbuf_release(pkt);
+        ng_pktbuf_release(pkt2);
         return;
     }
-
-    sixlowpan->next = ipv6;
-    pkt->next = sixlowpan;
-    disp = sixlowpan->data;
-    disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
-    payload_len++;
+    dispatch_len += 1;
 #endif
+    datagram_size = ng_pkt_len(pkt2->next);
 
-    DEBUG("6lo: max_frag_size = %" PRIu16 " for interface %"
-          PRIkernel_pid "\n", max_frag_size, hdr->if_pid);
+    DEBUG("6lo: iface->max_frag_size = %" PRIu16 " for interface %"
+          PRIkernel_pid "\n", iface->max_frag_size, hdr->if_pid);
 
     /* IP should not send anything here if it is not a 6LoWPAN interface,
      * so we don't need to check for NULL pointers */
-    if (payload_len <= max_frag_size) {
+    if ((datagram_size + dispatch_len) <= iface->max_frag_size) {
         DEBUG("6lo: Send SND command for %p to %" PRIu16 "\n",
-              (void *)pkt, hdr->if_pid);
-        ng_netapi_send(hdr->if_pid, pkt);
+              (void *)pkt2, hdr->if_pid);
+        ng_netapi_send(hdr->if_pid, pkt2);
 
         return;
     }
 #ifdef MODULE_NG_SIXLOWPAN_FRAG
     else {
         DEBUG("6lo: Send fragmented (%u > %" PRIu16 ")\n",
-              (unsigned int)payload_len, max_frag_size);
-        ng_sixlowpan_frag_send(hdr->if_pid, pkt, payload_len, datagram_size);
+              (unsigned int)datagram_size + dispatch_len, iface->max_frag_size);
+        ng_sixlowpan_frag_send(hdr->if_pid, pkt2, datagram_size + dispatch_len,
+                               datagram_size);
     }
 #else
     (void)datagram_size;
     DEBUG("6lo: packet too big (%u> %" PRIu16 ")\n",
-          (unsigned int)payload_len, max_frag_size);
+          (unsigned int)(datagram_size + dispatch_len), iface->max_frag_size);
 #endif
 }
 
-- 
GitLab