void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, size_t frag_size, size_t offset) { rbuf_t *entry; /* cppcheck-suppress variableScope * (reason: cppcheck is clearly wrong here) */ unsigned int data_offset = 0; size_t original_size = frag_size; sixlowpan_frag_t *frag = pkt->data; rbuf_int_t *ptr; uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t); _rbuf_gc(); entry = _rbuf_get(gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len, gnrc_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len, byteorder_ntohs(frag->disp_size) & SIXLOWPAN_FRAG_SIZE_MASK, byteorder_ntohs(frag->tag)); if (entry == NULL) { DEBUG("6lo rbuf: reassembly buffer full.\n"); return; } ptr = entry->ints; /* dispatches in the first fragment are ignored */ if (offset == 0) { if (data[0] == SIXLOWPAN_UNCOMP) { data++; /* skip 6LoWPAN dispatch */ frag_size--; } #ifdef MODULE_GNRC_SIXLOWPAN_IPHC else if (sixlowpan_iphc_is(data)) { size_t iphc_len, nh_len = 0; iphc_len = gnrc_sixlowpan_iphc_decode(&entry->pkt, pkt, entry->pkt->size, sizeof(sixlowpan_frag_t), &nh_len); if (iphc_len == 0) { DEBUG("6lo rfrag: could not decode IPHC dispatch\n"); gnrc_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } data += iphc_len; /* take remaining data as data */ frag_size -= iphc_len; /* and reduce frag size by IPHC dispatch length */ /* but add IPv6 header + next header lengths */ frag_size += sizeof(ipv6_hdr_t) + nh_len; /* start copying after IPv6 header and next headers */ data_offset += sizeof(ipv6_hdr_t) + nh_len; } #endif } else { data++; /* FRAGN header is one byte longer (offset) */ } if ((offset + frag_size) > entry->pkt->size) { DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n"); gnrc_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } /* If the fragment overlaps another fragment and differs in either the size * or the offset of the overlapped fragment, discards the datagram * https://tools.ietf.org/html/rfc4944#section-5.3 */ while (ptr != NULL) { if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) { DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n"); gnrc_pktbuf_release(entry->pkt); _rbuf_rem(entry); /* "A fresh reassembly may be commenced with the most recently * received link fragment" * https://tools.ietf.org/html/rfc4944#section-5.3 */ rbuf_add(netif_hdr, pkt, original_size, offset); return; } ptr = ptr->next; } if (_rbuf_update_ints(entry, offset, frag_size)) { DEBUG("6lo rbuf: add fragment data\n"); entry->cur_size += (uint16_t)frag_size; memcpy(((uint8_t *)entry->pkt->data) + offset + data_offset, data, frag_size - data_offset); } if (entry->cur_size == entry->pkt->size) { gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(entry->src, entry->src_len, entry->dst, entry->dst_len); if (netif == NULL) { DEBUG("6lo rbuf: error allocating netif header\n"); gnrc_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } /* copy the transmit information of the latest fragment into the newly * created header to have some link_layer information. The link_layer * info of the previous fragments is discarded. */ gnrc_netif_hdr_t *new_netif_hdr = netif->data; new_netif_hdr->if_pid = netif_hdr->if_pid; new_netif_hdr->flags = netif_hdr->flags; new_netif_hdr->lqi = netif_hdr->lqi; new_netif_hdr->rssi = netif_hdr->rssi; LL_APPEND(entry->pkt, netif); if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, entry->pkt)) { DEBUG("6lo rbuf: No receivers for this packet found\n"); gnrc_pktbuf_release(entry->pkt); } _rbuf_rem(entry); } }
static void _receive(ng_pktsnip_t *pkt) { ng_pktsnip_t *payload; uint8_t *dispatch; /* seize payload as a temporary variable */ payload = ng_pktbuf_start_write(pkt); /* need to duplicate since pkt->next * might get replaced */ if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && ENABLE_DEBUG ng_pktbuf_stats(); #endif ng_pktbuf_release(pkt); return; } pkt = payload; /* reset pkt from temporary variable */ LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_SIXLOWPAN); if ((payload == NULL) || (payload->size < 1)) { DEBUG("6lo: Received packet has no 6LoWPAN payload\n"); ng_pktbuf_release(pkt); return; } dispatch = payload->data; if (dispatch[0] == SIXLOWPAN_UNCOMP) { ng_pktsnip_t *sixlowpan; DEBUG("6lo: received uncompressed IPv6 packet\n"); payload = ng_pktbuf_start_write(payload); if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && ENABLE_DEBUG ng_pktbuf_stats(); #endif ng_pktbuf_release(pkt); return; } /* packet is uncompressed: just mark and remove the dispatch */ sixlowpan = ng_pktbuf_mark(payload, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN); if (sixlowpan == NULL) { DEBUG("6lo: can not mark 6LoWPAN dispatch\n"); ng_pktbuf_release(pkt); return; } pkt = ng_pktbuf_remove_snip(pkt, sixlowpan); } #ifdef MODULE_NG_SIXLOWPAN_FRAG else if (sixlowpan_frag_is((sixlowpan_frag_t *)dispatch)) { DEBUG("6lo: received 6LoWPAN fragment\n"); ng_sixlowpan_frag_handle_pkt(pkt); return; } #endif #ifdef MODULE_NG_SIXLOWPAN_IPHC else if (sixlowpan_iphc_is(dispatch)) { size_t dispatch_size; ng_pktsnip_t *sixlowpan; ng_pktsnip_t *ipv6 = ng_pktbuf_add(NULL, NULL, sizeof(ipv6_hdr_t), NG_NETTYPE_IPV6); if ((ipv6 == NULL) || (dispatch_size = ng_sixlowpan_iphc_decode(ipv6, pkt, 0)) == 0) { DEBUG("6lo: error on IPHC decoding\n"); if (ipv6 != NULL) { ng_pktbuf_release(ipv6); } ng_pktbuf_release(pkt); return; } sixlowpan = ng_pktbuf_mark(pkt, dispatch_size, NG_NETTYPE_SIXLOWPAN); if (sixlowpan == NULL) { DEBUG("6lo: error on marking IPHC dispatch\n"); ng_pktbuf_release(ipv6); ng_pktbuf_release(pkt); return; } /* Remove IPHC dispatch */ ng_pktbuf_remove_snip(pkt, sixlowpan); /* Insert IPv6 header instead */ ipv6->next = pkt->next; pkt->next = ipv6; } #endif else { DEBUG("6lo: dispatch %02" PRIx8 " ... is not supported\n", dispatch[0]); ng_pktbuf_release(pkt); return; } payload->type = NG_NETTYPE_IPV6; if (!ng_netapi_dispatch_receive(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("6lo: No receivers for this packet found\n"); ng_pktbuf_release(pkt); } }
static void _receive(gnrc_pktsnip_t *pkt) { gnrc_pktsnip_t *payload; uint8_t *dispatch; /* seize payload as a temporary variable */ payload = gnrc_pktbuf_start_write(pkt); /* need to duplicate since pkt->next * might get replaced */ if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && ENABLE_DEBUG gnrc_pktbuf_stats(); #endif gnrc_pktbuf_release(pkt); return; } pkt = payload; /* reset pkt from temporary variable */ payload = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_SIXLOWPAN); if ((payload == NULL) || (payload->size < 1)) { DEBUG("6lo: Received packet has no 6LoWPAN payload\n"); gnrc_pktbuf_release(pkt); return; } dispatch = payload->data; if (dispatch[0] == SIXLOWPAN_UNCOMP) { gnrc_pktsnip_t *sixlowpan; DEBUG("6lo: received uncompressed IPv6 packet\n"); payload = gnrc_pktbuf_start_write(payload); if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && ENABLE_DEBUG gnrc_pktbuf_stats(); #endif gnrc_pktbuf_release(pkt); return; } /* packet is uncompressed: just mark and remove the dispatch */ sixlowpan = gnrc_pktbuf_mark(payload, sizeof(uint8_t), GNRC_NETTYPE_SIXLOWPAN); if (sixlowpan == NULL) { DEBUG("6lo: can not mark 6LoWPAN dispatch\n"); gnrc_pktbuf_release(pkt); return; } pkt = gnrc_pktbuf_remove_snip(pkt, sixlowpan); payload->type = GNRC_NETTYPE_IPV6; } #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); return; } #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; } #endif else { DEBUG("6lo: dispatch %02" PRIx8 " ... is not supported\n", dispatch[0]); gnrc_pktbuf_release(pkt); return; } if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("6lo: No receivers for this packet found\n"); gnrc_pktbuf_release(pkt); } }
void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, size_t offset, unsigned page) { rbuf_t *entry; sixlowpan_frag_t *frag = pkt->data; rbuf_int_t *ptr; uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t); size_t frag_size; rbuf_gc(); entry = _rbuf_get(gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len, gnrc_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len, byteorder_ntohs(frag->disp_size) & SIXLOWPAN_FRAG_SIZE_MASK, byteorder_ntohs(frag->tag), page); if (entry == NULL) { DEBUG("6lo rbuf: reassembly buffer full.\n"); return; } ptr = entry->ints; /* dispatches in the first fragment are ignored */ if (offset == 0) { frag_size = pkt->size - sizeof(sixlowpan_frag_t); if (data[0] == SIXLOWPAN_UNCOMP) { frag_size--; } } else { frag_size = pkt->size - sizeof(sixlowpan_frag_n_t); data++; /* FRAGN header is one byte longer (offset) */ } if ((offset + frag_size) > entry->super.pkt->size) { DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n"); gnrc_pktbuf_release(entry->super.pkt); rbuf_rm(entry); return; } /* If the fragment overlaps another fragment and differs in either the size * or the offset of the overlapped fragment, discards the datagram * https://tools.ietf.org/html/rfc4944#section-5.3 */ while (ptr != NULL) { if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) { DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n"); gnrc_pktbuf_release(entry->super.pkt); rbuf_rm(entry); /* "A fresh reassembly may be commenced with the most recently * received link fragment" * https://tools.ietf.org/html/rfc4944#section-5.3 */ rbuf_add(netif_hdr, pkt, offset, page); return; } ptr = ptr->next; } if (_rbuf_update_ints(entry, offset, frag_size)) { DEBUG("6lo rbuf: add fragment data\n"); entry->super.current_size += (uint16_t)frag_size; if (offset == 0) { #ifdef MODULE_GNRC_SIXLOWPAN_IPHC if (sixlowpan_iphc_is(data)) { gnrc_pktsnip_t *frag_hdr = gnrc_pktbuf_mark(pkt, sizeof(sixlowpan_frag_t), GNRC_NETTYPE_SIXLOWPAN); if (frag_hdr == NULL) { gnrc_pktbuf_release(entry->super.pkt); rbuf_rm(entry); return; } gnrc_sixlowpan_iphc_recv(pkt, &entry->super, 0); return; } else #endif if (data[0] == SIXLOWPAN_UNCOMP) { data++; } } memcpy(((uint8_t *)entry->super.pkt->data) + offset, data, frag_size); } gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(&entry->super, netif_hdr); gnrc_pktbuf_release(pkt); }