Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gnrc_sixlowpan_iphc_nhc: fix NHC UDP decoding for fragmented packets #4935

Merged
merged 1 commit into from
Mar 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion sys/include/net/gnrc/sixlowpan/iphc.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ extern "C" {
* @return 0 on error.
*/
size_t gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t **dec_hdr, gnrc_pktsnip_t *pkt,
size_t datagram_size, size_t offset);
size_t datagram_size, size_t offset,
size_t *nh_len);

/**
* @brief Compresses a 6LoWPAN for IPHC.
Expand Down
10 changes: 6 additions & 4 deletions sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
}
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
else if (sixlowpan_iphc_is(data)) {
size_t iphc_len;
size_t iphc_len, nh_len = 0;
iphc_len = gnrc_sixlowpan_iphc_decode(&entry->pkt, pkt, entry->pkt->size,
sizeof(sixlowpan_frag_t));
sizeof(sixlowpan_frag_t), &nh_len);
if (iphc_len == 0) {
DEBUG("6lo rfrag: could not decode IPHC dispatch\n");
gnrc_pktbuf_release(entry->pkt);
Expand All @@ -112,8 +112,10 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
}
data += iphc_len; /* take remaining data as data */
frag_size -= iphc_len; /* and reduce frag size by IPHC dispatch length */
frag_size += sizeof(ipv6_hdr_t); /* but add IPv6 header length */
data_offset += sizeof(ipv6_hdr_t); /* start copying after IPv6 header */
/* 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
}
Expand Down
5 changes: 3 additions & 2 deletions sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,13 @@ static void _receive(gnrc_pktsnip_t *pkt)
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
else if (sixlowpan_iphc_is(dispatch)) {
size_t dispatch_size;
size_t dispatch_size, nh_len;
gnrc_pktsnip_t *sixlowpan, *tmp;
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)) == 0) {
(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);
Expand Down
47 changes: 34 additions & 13 deletions sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static inline bool _context_overlaps_iid(gnrc_sixlowpan_ctx_t *ctx,

#ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC
inline static size_t iphc_nhc_udp_decode(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t **dec_hdr,
size_t offset)
size_t datagram_size, size_t offset)
{
uint8_t *payload = pkt->data;
gnrc_pktsnip_t *ipv6 = *dec_hdr;
Expand All @@ -122,16 +122,25 @@ inline static size_t iphc_nhc_udp_decode(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t **d
#else
const gnrc_nettype_t snip_type = GNRC_NETTYPE_UNDEF;
#endif
gnrc_pktsnip_t *udp = gnrc_pktbuf_add(NULL, NULL, sizeof(udp_hdr_t),
snip_type);
gnrc_pktsnip_t *udp = NULL;
uint8_t udp_nhc = payload[offset++];
uint8_t tmp;
udp_hdr_t *udp_hdr;

if (udp == NULL) {
DEBUG("6lo: error on IPHC NHC UDP decoding\n");
return 0;
if (datagram_size == 0) { /* received packet is not fragmented */
udp = gnrc_pktbuf_add(NULL, NULL, sizeof(udp_hdr_t),
snip_type);
if (udp == NULL) {
DEBUG("6lo: error on IPHC NHC UDP decoding\n");
return 0;
}
udp_hdr = udp->data;
}
else { /* received packet is fragmented */
/* reassembly is in-place => don't allocate new packet snip */
/* TODO: account for extension headers */
udp_hdr = (udp_hdr_t *)(ipv6_hdr + 1);
}
udp_hdr_t *udp_hdr = udp->data;
network_uint16_t *src_port = &(udp_hdr->src_port);
network_uint16_t *dst_port = &(udp_hdr->dst_port);

Expand Down Expand Up @@ -180,19 +189,28 @@ inline static size_t iphc_nhc_udp_decode(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t **d
udp_hdr->checksum.u8[1] = payload[offset++];
}

udp_hdr->length = byteorder_htons(pkt->size - offset + sizeof(udp_hdr_t));
/* TODO subtract extension header length */
if (udp != NULL) {
udp_hdr->length = byteorder_htons(pkt->size - offset + sizeof(udp_hdr_t));
}
else {
udp_hdr->length = byteorder_htons(datagram_size - sizeof(ipv6_hdr_t));
}
ipv6_hdr->nh = PROTNUM_UDP;
ipv6_hdr->len = udp_hdr->length;

udp->next = ipv6;
*dec_hdr = udp;
if (udp != NULL) { /* prepend udp header in case of packet not being fragmented */
udp->next = ipv6;
*dec_hdr = udp;
}

return offset;
}
#endif

size_t gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t **dec_hdr, gnrc_pktsnip_t *pkt,
size_t datagram_size, size_t offset)
size_t datagram_size, size_t offset,
size_t *nh_len)
{
gnrc_pktsnip_t *ipv6;
gnrc_netif_hdr_t *netif_hdr = pkt->next->data;
Expand Down Expand Up @@ -457,7 +475,6 @@ size_t gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t **dec_hdr, gnrc_pktsnip_t *pkt,
memcpy(ipv6_hdr->dst.u8 + 12, iphc_hdr + payload_offset + 2, 4);

payload_offset += 4;

ctx->prefix_len = orig_ctx_len;
} while (0); /* ANSI-C compatible block creation for orig_ctx_len allocation */
break;
Expand All @@ -481,13 +498,17 @@ size_t gnrc_sixlowpan_iphc_decode(gnrc_pktsnip_t **dec_hdr, gnrc_pktsnip_t *pkt,
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, payload_offset);
payload_offset = iphc_nhc_udp_decode(pkt, dec_hdr, datagram_size,
payload_offset + offset) - offset;
*nh_len += sizeof(udp_hdr_t);
break;

default:
break;
}
}
#else
(void)nh_len;
#endif

return payload_offset;
Expand Down