diff --git a/sys/include/net/gnrc/sixlowpan/iphc.h b/sys/include/net/gnrc/sixlowpan/iphc.h index a754dd84d6db2..1c44704d41d05 100644 --- a/sys/include/net/gnrc/sixlowpan/iphc.h +++ b/sys/include/net/gnrc/sixlowpan/iphc.h @@ -30,36 +30,30 @@ extern "C" { #endif /** - * @brief Decompresses a received 6LoWPAN IPHC frame. + * @brief Decompresses a received 6Lo IPHC frame and delegates the + * uncompressed packet to the next 6Lo sub-layer. * - * @pre (dec_hdr != NULL) && (*dec_hdr != NULL) && ((*dec_hdr)->size >= sizeof(gnrc_ipv6_hdr_t)) + * @pre (pkt != NULL) * - * @param[out] dec_hdr A pre-allocated IPv6 header. Will not be inserted into - * @p pkt. May change due to next headers being added in NHC. - * @param[in] pkt A received 6LoWPAN IPHC frame. IPHC dispatch will not - * be marked. - * @param[in] datagram_size Size of the full uncompressed IPv6 datagram. May be 0, if @p pkt - * contains the full (unfragmented) IPv6 datagram. - * @param[in] offset Offset of the IPHC dispatch in 6LoWPaN frame. - * @param[in, out] nh_len Pointer to next header length - * - * @return length of the HC dispatches + inline values on success. - * @return 0 on error. + * @param[in] pkt A received 6Lo IPHC frame. + * @param[in] context Context for the packet. May be `NULL`. If not `NULL` it + * *must* point to an instance of a reassembly buffer. + * @param[in] page Current 6Lo dispatch parsing page. */ -size_t gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t **dec_hdr, gnrc_pktsnip_t *pkt, - size_t datagram_size, size_t offset, - size_t *nh_len); +void gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t *pkt, void *context, + unsigned page); /** - * @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. + * @brief Compresses a 6LoWPAN for IPHC and delegates the compressed packet + * to the next 6Lo sub-layer. * - * @return true, on success - * @return false, on error. + * @param[in] pkt A 6LoWPAN frame with an uncompressed IPv6 header to + * send. + * @param[in] context Context for the packet. May be `NULL`. + * @param[in] page Current 6Lo dispatch parsing page. */ -bool gnrc_sixlowpan_iphc_encode(gnrc_pktsnip_t *pkt); +void gnrc_sixlowpan_iphc_encode(gnrc_pktsnip_t *pkt, void *context, + 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 ff69d1ba21d3a..7af3f803f6bd1 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c +++ b/sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c @@ -160,6 +160,7 @@ static void _receive(gnrc_pktsnip_t *pkt) pkt = gnrc_pktbuf_remove_snip(pkt, sixlowpan); payload->type = GNRC_NETTYPE_IPV6; + gnrc_sixlowpan_dispatch_recv(pkt, NULL, 0); } #ifdef MODULE_GNRC_SIXLOWPAN_FRAG else if (sixlowpan_frag_is((sixlowpan_frag_t *)dispatch)) { @@ -170,32 +171,7 @@ static void _receive(gnrc_pktsnip_t *pkt) #endif #ifdef MODULE_GNRC_SIXLOWPAN_IPHC else if (sixlowpan_iphc_is(dispatch)) { - size_t dispatch_size, nh_len; - gnrc_pktsnip_t *sixlowpan; - gnrc_pktsnip_t *dec_hdr = gnrc_pktbuf_add(NULL, NULL, sizeof(ipv6_hdr_t), - GNRC_NETTYPE_IPV6); - if ((dec_hdr == NULL) || - (dispatch_size = gnrc_sixlowpan_iphc_decode(&dec_hdr, pkt, 0, 0, - &nh_len)) == 0) { - DEBUG("6lo: error on IPHC decoding\n"); - if (dec_hdr != NULL) { - gnrc_pktbuf_release(dec_hdr); - } - gnrc_pktbuf_release(pkt); - return; - } - sixlowpan = gnrc_pktbuf_mark(pkt, dispatch_size, GNRC_NETTYPE_SIXLOWPAN); - if (sixlowpan == NULL) { - DEBUG("6lo: error on marking IPHC dispatch\n"); - gnrc_pktbuf_release(dec_hdr); - gnrc_pktbuf_release(pkt); - return; - } - - /* Remove IPHC dispatches */ - /* Insert decoded header instead */ - pkt = gnrc_pktbuf_replace_snip(pkt, sixlowpan, dec_hdr); - payload->type = GNRC_NETTYPE_UNDEF; + gnrc_sixlowpan_iphc_decode(pkt, NULL, 0); } #endif else { @@ -204,7 +180,6 @@ static void _receive(gnrc_pktsnip_t *pkt) gnrc_pktbuf_release(pkt); return; } - gnrc_sixlowpan_dispatch_recv(pkt, NULL, 0); } static inline bool _add_uncompr_disp(gnrc_pktsnip_t *pkt) @@ -266,7 +241,7 @@ static void _send(gnrc_pktsnip_t *pkt) #ifdef MODULE_GNRC_SIXLOWPAN_IPHC if (iface->flags & GNRC_NETIF_FLAGS_6LO_HC) { - if (!gnrc_sixlowpan_iphc_encode(pkt2)) { + if (!gnrc_sixlowpan_iphc_encode(pkt2, NULL, 0)) { DEBUG("6lo: error on IPHC encoding\n"); gnrc_pktbuf_release(pkt2); return; 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 28df9ee0b8984..bbcec24b340de 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 @@ -481,42 +481,65 @@ size_t gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t **dec_hdr, gnrc_pktsnip_t *pkt, default: DEBUG("6lo iphc: unspecified or reserved M, DAC, DAM combination\n"); - return 0; + gnrc_pktsnip_release(ipv6); + gnrc_pktsnip_release(pkt); + return; } - /* set IPv6 header payload length field to the length of whatever is left - * after removing the 6LoWPAN header */ - if (datagram_size == 0) { + /* if no reassembly buffer entry is provided */ + if (layer_context == NULL) { + /* set IPv6 header payload length field to the length of whatever is left + * after removing the 6LoWPAN header */ ipv6_hdr->len = byteorder_htons((uint16_t)(pkt->size - payload_offset)); } else { - ipv6_hdr->len = byteorder_htons((uint16_t)(datagram_size - sizeof(ipv6_hdr_t))); + rbuf_t *rbuf_entry = layer_context; + ipv6_hdr->len = byteorder_htons((uint16_t)(rbuf_entry->pkt->size - + sizeof(ipv6_hdr_t))); } #ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC if (iphc_hdr[IPHC1_IDX] & SIXLOWPAN_IPHC1_NH) { switch (iphc_hdr[payload_offset] & NHC_ID_MASK) { case NHC_UDP_ID: - payload_offset = iphc_nhc_udp_decode(pkt, dec_hdr, datagram_size, - payload_offset + offset); - - if (payload_offset != 0) { - payload_offset -= offset; - } + // TODO: transform datagram_size to rbuf, add of UDP snip? + payload_offset = iphc_nhc_udp_decode(pkt, &ipv6, datagram_size, + payload_offset); - *nh_len += sizeof(udp_hdr_t); + hdr_len += sizeof(udp_hdr_t); break; default: break; } } -#else - (void)nh_len; #endif - return payload_offset; + if (layered_context == NULL) { + sixlowpan = gnrc_pktbuf_mark(pkt, payload_offset, GNRC_NETTYPE_SIXLOWPAN); + if (sixlowpan == NULL) { + DEBUG("6lo iphc: error marking IPHC dispatch\n"); + gnrc_pktbuf_release(ipv6); + gnrc_pktbuf_release(pkt); + return; + } + /* Remove IPHC dispatches */ + /* Insert decoded header instead */ + pkt = gnrc_pktbuf_replace_snip(pkt, sixlowpan, ipv6); + pkt->type = GNRC_NETTYPE_UNDEF; + } + else { + rbuf_t *rbuf_entry = layered_context; + uint8_t *data_out = entry->pkt->data; + uint8_t *data_in = pkt->data; + + /* was fragmented => copy rest of fragment into reassem bly buffer */ + memcpy(data_out + sizeof(ipv6_hdr_t) + hdr_len, data_in + payload_offset, + pkt->size - payload_offset); + pkt = rbuf_entry->pkt; + } + gnrc_sixlowpan_dispatch_recv(pkt, layer_context, page); } #ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC @@ -581,7 +604,8 @@ 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_encode(gnrc_pktsnip_t *pkt, void *context, + unsigned page) { gnrc_netif_hdr_t *netif_hdr = pkt->data; ipv6_hdr_t *ipv6_hdr = pkt->next->data;