diff --git a/sys/include/net/gnrc/sixlowpan/frag.h b/sys/include/net/gnrc/sixlowpan/frag.h index 971038d9ab..47bc406063 100644 --- a/sys/include/net/gnrc/sixlowpan/frag.h +++ b/sys/include/net/gnrc/sixlowpan/frag.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Martine Lenders + * Copyright (C) 2015 Hamburg University of Applied Sciences * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -19,6 +20,7 @@ * @brief 6LoWPAN Fragmentation definitions * * @author Martine Lenders + * @author Peter Kietzmann */ #ifndef GNRC_SIXLOWPAN_FRAG_H_ #define GNRC_SIXLOWPAN_FRAG_H_ @@ -35,17 +37,29 @@ extern "C" { #endif +/** + * @brief Message type for passing one 6LoWPAN fragment down the network stack + */ +#define GNRC_SIXLOWPAN_MSG_FRAG_SND (0x0225) + +/** + * @brief Definition of 6LoWPAN fragmentation type. + */ +typedef struct { + kernel_pid_t pid; /**< PID of the interface */ + 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 */ + uint16_t offset; /**< Offset of the Nth fragment from the beginning of the + * payload datagram */ +} gnrc_sixlowpan_msg_frag_t; + /** * @brief Sends a packet fragmented. * - * @param[in] pid The interface to send the packet over. - * @param[in] pkt The packet to send. - * @param[in] datagram_size The length of just the IPv6 packet. It is the value - * that the gnrc_sixlowpan_frag_t::disp_size field will be - * set to. + * @param[in] fragment_msg Message containing status of the 6LoWPAN + * fragmentation progress */ -void gnrc_sixlowpan_frag_send(kernel_pid_t pid, gnrc_pktsnip_t *pkt, - size_t datagram_size); +void gnrc_sixlowpan_frag_send(gnrc_sixlowpan_msg_frag_t *fragment_msg); /** * @brief Handles a packet containing a fragment header. 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 9cc407a619..d3c89a1046 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 @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Martine Lenders + * Copyright (C) 2015 Hamburg University of Applied Sciences * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -10,6 +11,9 @@ * @{ * * @file + * + * @author Martine Lenders + * @author Peter Kietzmann */ #include "kernel_types.h" @@ -212,51 +216,70 @@ static uint16_t _send_nth_fragment(gnrc_sixlowpan_netif_t *iface, gnrc_pktsnip_t return local_offset; } -void gnrc_sixlowpan_frag_send(kernel_pid_t pid, gnrc_pktsnip_t *pkt, - size_t datagram_size) +void gnrc_sixlowpan_frag_send(gnrc_sixlowpan_msg_frag_t *fragment_msg) { - gnrc_sixlowpan_netif_t *iface = gnrc_sixlowpan_netif_get(pid); - uint16_t offset = 0, res; + gnrc_sixlowpan_netif_t *iface = gnrc_sixlowpan_netif_get(fragment_msg->pid); + uint16_t res; /* payload_len: actual size of the packet vs * datagram_size: size of the uncompressed IPv6 packet */ - size_t payload_len = gnrc_pkt_len(pkt->next); + size_t payload_len = gnrc_pkt_len(fragment_msg->pkt->next); + msg_t msg; #if defined(DEVELHELP) && defined(ENABLE_DEBUG) if (iface == NULL) { DEBUG("6lo frag: iface == NULL, expect segmentation fault.\n"); - gnrc_pktbuf_release(pkt); + /* remove original packet from packet buffer */ + gnrc_pktbuf_release(fragment_msg->pkt); + /* 6LoWPAN free for next fragmentation */ + fragment_msg->pkt = NULL; return; } #endif - if ((res = _send_1st_fragment(iface, pkt, payload_len, datagram_size)) == 0) { - /* error sending first fragment */ - DEBUG("6lo frag: error sending 1st fragment\n"); - gnrc_pktbuf_release(pkt); - return; - } - - offset += res; - thread_yield(); - - /* (offset + (datagram_size - payload_len) < datagram_size) simplified */ - while (offset < payload_len) { - if ((res = _send_nth_fragment(iface, pkt, payload_len, datagram_size, - offset)) == 0) { - /* error sending subsequent fragment */ - DEBUG("6lo frag: error sending subsequent fragment (offset = %" PRIu16 - ")\n", offset); - gnrc_pktbuf_release(pkt); + /* Check weater to send the first or an Nth fragment */ + if (fragment_msg->offset == 0) { + /* increment tag for successive, fragmented datagrams */ + _tag++; + if ((res = _send_1st_fragment(iface, fragment_msg->pkt, payload_len, fragment_msg->datagram_size)) == 0) { + /* error sending first fragment */ + DEBUG("6lo frag: error sending 1st fragment\n"); + gnrc_pktbuf_release(fragment_msg->pkt); + fragment_msg->pkt = NULL; return; } + fragment_msg->offset += res; - offset += res; + /* send message to self*/ + msg.type = GNRC_SIXLOWPAN_MSG_FRAG_SND; + msg.content.ptr = (void *)fragment_msg; + msg_send_to_self(&msg); thread_yield(); } + else { + /* (offset + (datagram_size - payload_len) < datagram_size) simplified */ + if (fragment_msg->offset < payload_len) { + if ((res = _send_nth_fragment(iface, fragment_msg->pkt, payload_len, fragment_msg->datagram_size, + fragment_msg->offset)) == 0) { + /* error sending subsequent fragment */ + DEBUG("6lo frag: error sending subsequent fragment (offset = %" PRIu16 + ")\n", fragment_msg->offset); + gnrc_pktbuf_release(fragment_msg->pkt); + fragment_msg->pkt = NULL; + return; + } + fragment_msg->offset += res; - /* remove original packet from packet buffer */ - gnrc_pktbuf_release(pkt); - _tag++; + /* send message to self*/ + msg.type = GNRC_SIXLOWPAN_MSG_FRAG_SND; + msg.content.ptr = (void *)fragment_msg; + msg_send_to_self(&msg); + thread_yield(); + } + else { + gnrc_pktbuf_release(fragment_msg->pkt); + fragment_msg->pkt = NULL; + } + } } void gnrc_sixlowpan_frag_handle_pkt(gnrc_pktsnip_t *pkt) diff --git a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c index 648d62e78f..62952a3906 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c +++ b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c @@ -34,6 +34,8 @@ static kernel_pid_t _pid = KERNEL_PID_UNDEF; +static gnrc_sixlowpan_msg_frag_t fragment_msg = {KERNEL_PID_UNDEF, NULL, 0, 0}; + #if ENABLE_DEBUG static char _stack[GNRC_SIXLOWPAN_STACK_SIZE + THREAD_EXTRA_STACKSIZE_PRINTF]; #else @@ -270,10 +272,27 @@ 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 > %" PRIu16 ")\n", (unsigned int)datagram_size, iface->max_frag_size); - gnrc_sixlowpan_frag_send(hdr->if_pid, pkt2, datagram_size); + msg_t msg; + + 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; + + /* set the outgoing message's fields */ + msg.type = GNRC_SIXLOWPAN_MSG_FRAG_SND; + msg.content.ptr = (void *)&fragment_msg; + /* send message to self */ + msg_send_to_self(&msg); } else { DEBUG("6lo: packet too big (%u > %" PRIu16 ")\n", @@ -327,6 +346,12 @@ static void *_event_loop(void *args) reply.content.value = -ENOTSUP; msg_reply(&msg, &reply); break; +#ifdef MODULE_GNRC_SIXLOWPAN_FRAG + case GNRC_SIXLOWPAN_MSG_FRAG_SND: + DEBUG("6lo: send fragmented event received\n"); + gnrc_sixlowpan_frag_send((gnrc_sixlowpan_msg_frag_t *)msg.content.ptr); + break; +#endif default: DEBUG("6lo: operation not supported\n");