diff --git a/sys/include/net/gnrc/sixlowpan/internal.h b/sys/include/net/gnrc/sixlowpan/internal.h index 144a54bb7fc9..45a5414596a7 100644 --- a/sys/include/net/gnrc/sixlowpan/internal.h +++ b/sys/include/net/gnrc/sixlowpan/internal.h @@ -18,7 +18,10 @@ #ifndef NET_GNRC_SIXLOWPAN_INTERNAL_H #define NET_GNRC_SIXLOWPAN_INTERNAL_H +#include + #include "net/gnrc/pkt.h" +#include "net/gnrc/netif.h" #ifdef __cplusplus extern "C" { @@ -44,6 +47,24 @@ void gnrc_sixlowpan_dispatch_recv(gnrc_pktsnip_t *pkt, void *context, void gnrc_sixlowpan_dispatch_send(gnrc_pktsnip_t *pkt, void *context, unsigned page); + +/** + * @brief Checks if packet fits over interface (and fragments if @ref + * net_gnrc_sixlowpan_frag is available and required) + * + * @param[in] pkt The packet to fit. Must not be NULL. + * @param[in] orig_datagram_size The original (uncompressed) datagram size. + * Must be greater or equal to the length of + * @p pkt as of `pkt->next` (i.e. without + * the @ref gnrc_netif_hdr_t). + * @param[in] netif The interface to fit @p pkt over. Must not + * be NULL. + * @param[in] page Current 6Lo dispatch parsing page + */ +void gnrc_sixlowpan_multiplex_by_size(gnrc_pktsnip_t *pkt, + size_t orig_datagram_size, + gnrc_netif_t *netif, + unsigned page); #ifdef __cplusplus } #endif diff --git a/sys/include/net/gnrc/sixlowpan/iphc.h b/sys/include/net/gnrc/sixlowpan/iphc.h index a754dd84d6db..2280ea970c2f 100644 --- a/sys/include/net/gnrc/sixlowpan/iphc.h +++ b/sys/include/net/gnrc/sixlowpan/iphc.h @@ -53,13 +53,15 @@ size_t gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t **dec_hdr, gnrc_pktsnip_t *pkt, /** * @brief Compresses a 6LoWPAN for IPHC. * - * @param[in,out] pkt A 6LoWPAN frame with an uncompressed IPv6 header to - * send. Will be translated to an 6LoWPAN IPHC frame. + * @pre (pkt != NULL) + * + * @param[in] pkt A 6LoWPAN frame with an uncompressed IPv6 header to send. + * Will be translated to an 6LoWPAN IPHC frame. + * @param[in] ctx Context for the packet. May be NULL. + * @param[in] page Current 6Lo dispatch parsing page. * - * @return true, on success - * @return false, on error. */ -bool gnrc_sixlowpan_iphc_encode(gnrc_pktsnip_t *pkt); +void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page); #ifdef __cplusplus } diff --git a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c index bc1ff176fd56..592f6fcf0574 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c +++ b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c @@ -101,6 +101,51 @@ void gnrc_sixlowpan_dispatch_send(gnrc_pktsnip_t *pkt, void *context, } } +void gnrc_sixlowpan_multiplex_by_size(gnrc_pktsnip_t *pkt, + size_t orig_datagram_size, + gnrc_netif_t *netif, + unsigned page) +{ + assert(pkt != NULL); + assert(netif != NULL); + size_t datagram_size = gnrc_pkt_len(pkt->next); + DEBUG("6lo: iface->sixlo.max_frag_size = %u for interface %i\n", + netif->sixlo.max_frag_size, netif->pid); + if ((netif->sixlo.max_frag_size == 0) || + (datagram_size <= netif->sixlo.max_frag_size)) { + DEBUG("6lo: Dispatch for sending\n"); + gnrc_sixlowpan_dispatch_send(pkt, NULL, page); + } +#ifdef MODULE_GNRC_SIXLOWPAN_FRAG + else if (orig_datagram_size <= SIXLOWPAN_FRAG_MAX_LEN) { + DEBUG("6lo: Send fragmented (%u > %u)\n", + (unsigned int)datagram_size, netif->sixlo.max_frag_size); + gnrc_sixlowpan_msg_frag_t *fragment_msg; + + 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_error(pkt, ENOMEM); + return; + } + fragment_msg->pid = netif->pid; + fragment_msg->pkt = pkt; + fragment_msg->datagram_size = orig_datagram_size; + /* Sending the first fragment has an offset==0 */ + fragment_msg->offset = 0; + + gnrc_sixlowpan_frag_send(pkt, fragment_msg, page); + } +#endif + else { + (void)orig_datagram_size; + DEBUG("6lo: packet too big (%u > %u)\n", + (unsigned int)datagram_size, netif->sixlo.max_frag_size); + gnrc_pktbuf_release_error(pkt, EMSGSIZE); + } +} + static void _receive(gnrc_pktsnip_t *pkt) { gnrc_pktsnip_t *payload; @@ -225,8 +270,8 @@ static inline bool _add_uncompr_disp(gnrc_pktsnip_t *pkt) static void _send(gnrc_pktsnip_t *pkt) { gnrc_netif_hdr_t *hdr; - gnrc_pktsnip_t *pkt2; - gnrc_netif_t *iface; + gnrc_pktsnip_t *tmp; + gnrc_netif_t *netif; /* datagram_size: pure IPv6 packet without 6LoWPAN dispatches or compression */ size_t datagram_size; @@ -242,95 +287,37 @@ static void _send(gnrc_pktsnip_t *pkt) return; } - pkt2 = gnrc_pktbuf_start_write(pkt); + tmp = gnrc_pktbuf_start_write(pkt); - if (pkt2 == NULL) { + if (tmp == NULL) { DEBUG("6lo: no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return; } + pkt = tmp; + hdr = pkt->data; + netif = gnrc_netif_get_by_pid(hdr->if_pid); + datagram_size = gnrc_pkt_len(pkt->next); - hdr = pkt2->data; - iface = gnrc_netif_get_by_pid(hdr->if_pid); - datagram_size = gnrc_pkt_len(pkt2->next); - - if (iface == NULL) { + if (netif == NULL) { DEBUG("6lo: Can not get 6LoWPAN specific interface information.\n"); gnrc_pktbuf_release(pkt); return; } #ifdef MODULE_GNRC_SIXLOWPAN_IPHC - if (iface->flags & GNRC_NETIF_FLAGS_6LO_HC) { - if (!gnrc_sixlowpan_iphc_encode(pkt2)) { - DEBUG("6lo: error on IPHC encoding\n"); - gnrc_pktbuf_release(pkt2); - return; - } - /* IPHC dispatch does not count on dispatch length since it _shortens_ - * the datagram */ - } - else { - if (!_add_uncompr_disp(pkt2)) { - /* adding uncompressed dispatch failed */ - DEBUG("6lo: no space left in packet buffer\n"); - gnrc_pktbuf_release(pkt2); - return; - } - } -#else - /* suppress clang-analyzer report about iface being not read */ - (void) iface; - if (!_add_uncompr_disp(pkt2)) { - /* adding uncompressed dispatch failed */ - DEBUG("6lo: no space left in packet buffer\n"); - gnrc_pktbuf_release(pkt2); + if (netif->flags & GNRC_NETIF_FLAGS_6LO_HC) { + gnrc_sixlowpan_iphc_send(pkt, NULL, 0); return; } #endif - DEBUG("6lo: iface->sixlo.max_frag_size = %" PRIu8 " for interface %" - PRIkernel_pid "\n", iface->sixlo.max_frag_size, hdr->if_pid); - - /* Note, that datagram_size cannot be used here, because the header size - * might be changed by IPHC. */ - if ((iface->sixlo.max_frag_size == 0) || - (gnrc_pkt_len(pkt2->next) <= iface->sixlo.max_frag_size)) { - DEBUG("6lo: Send SND command for %p to %" PRIu16 "\n", - (void *)pkt2, hdr->if_pid); - gnrc_sixlowpan_dispatch_send(pkt2, NULL, 0); + if (!_add_uncompr_disp(pkt)) { + /* adding uncompressed dispatch failed */ + DEBUG("6lo: no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); return; } -#ifdef MODULE_GNRC_SIXLOWPAN_FRAG - else if (datagram_size <= SIXLOWPAN_FRAG_MAX_LEN) { - DEBUG("6lo: Send fragmented (%u > %" PRIu8 ")\n", - (unsigned int)datagram_size, iface->sixlo.max_frag_size); - gnrc_sixlowpan_msg_frag_t *fragment_msg; - - 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; - - gnrc_sixlowpan_frag_send(pkt2, fragment_msg, 0); - } - else { - DEBUG("6lo: packet too big (%u > %" PRIu16 ")\n", - (unsigned int)datagram_size, (uint16_t)SIXLOWPAN_FRAG_MAX_LEN); - gnrc_pktbuf_release(pkt2); - } -#else - (void) datagram_size; - DEBUG("6lo: packet too big (%u > %" PRIu8 ")\n", - (unsigned int)datagram_size, iface->sixlo.max_frag_size); - gnrc_pktbuf_release(pkt2); -#endif + gnrc_sixlowpan_multiplex_by_size(pkt, datagram_size, netif, 0); } static void *_event_loop(void *args) diff --git a/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c b/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c index 28df9ee0b898..b04718f54c6f 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c +++ b/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c @@ -23,6 +23,7 @@ #include "net/ipv6/hdr.h" #include "net/gnrc.h" #include "net/gnrc/sixlowpan/ctx.h" +#include "net/gnrc/sixlowpan/internal.h" #include "net/sixlowpan.h" #include "utlist.h" #include "net/gnrc/nettype.h" @@ -581,20 +582,25 @@ static inline size_t iphc_nhc_udp_encode(gnrc_pktsnip_t *udp, ipv6_hdr_t *ipv6_h } #endif -bool gnrc_sixlowpan_iphc_encode(gnrc_pktsnip_t *pkt) +void gnrc_sixlowpan_iphc_send(gnrc_pktsnip_t *pkt, void *ctx, unsigned page) { + assert(pkt != NULL); gnrc_netif_hdr_t *netif_hdr = pkt->data; ipv6_hdr_t *ipv6_hdr = pkt->next->data; uint8_t *iphc_hdr; - uint16_t inline_pos = SIXLOWPAN_IPHC_HDR_LEN; - bool addr_comp = false, nhc_comp = false; gnrc_sixlowpan_ctx_t *src_ctx = NULL, *dst_ctx = NULL; gnrc_pktsnip_t *dispatch = gnrc_pktbuf_add(NULL, NULL, pkt->next->size, GNRC_NETTYPE_SIXLOWPAN); + bool addr_comp = false, nhc_comp = false; + /* datagram size before compression */ + size_t orig_datagram_size = gnrc_pkt_len(pkt->next); + uint16_t inline_pos = SIXLOWPAN_IPHC_HDR_LEN; + (void)ctx; if (dispatch == NULL) { DEBUG("6lo iphc: error allocating dispatch space\n"); - return false; + gnrc_pktbuf_release(pkt); + return; } iphc_hdr = dispatch->data; @@ -892,7 +898,9 @@ bool gnrc_sixlowpan_iphc_encode(gnrc_pktsnip_t *pkt) dispatch->next = pkt->next; pkt->next = dispatch; - return true; + gnrc_netif_t *netif = gnrc_netif_get_by_pid(netif_hdr->if_pid); + assert(netif != NULL); + gnrc_sixlowpan_multiplex_by_size(pkt, orig_datagram_size, netif, page); } /** @} */