From 82a3aae8be2ae16cd1b81c0f755fe8b66cc60b0f Mon Sep 17 00:00:00 2001 From: Martine Lenders <mlenders@inf.fu-berlin.de> Date: Sat, 9 Apr 2016 22:11:21 +0200 Subject: [PATCH] gnrc_ipv6: fix asserts for NHC --- .../network_layer/ipv6/ext/gnrc_ipv6_ext.c | 160 ++++++++++------- sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c | 161 ++++++++++-------- 2 files changed, 183 insertions(+), 138 deletions(-) diff --git a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c index fe0936f29f..b86d035e7d 100644 --- a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c +++ b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c @@ -89,6 +89,56 @@ static enum gnrc_ipv6_ext_demux_status _handle_rh(gnrc_pktsnip_t *current, gnrc_ #endif +/** + * @brief marks IPv6 extension header if needed. + * updates pkt and returns next header. + * @param[in] current The current header + * @param[in,out] pkt The whole packet + * @return The next header + * @return NULL on error + */ +static gnrc_pktsnip_t *_mark_extension_header(gnrc_pktsnip_t *current, + gnrc_pktsnip_t **pkt) +{ + gnrc_pktsnip_t *ext_snip, *tmp, *next; + ipv6_ext_t *ext = (ipv6_ext_t *) current->data; + size_t offset = ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT); + + if (current == *pkt) { + if ((tmp = gnrc_pktbuf_start_write(*pkt)) == NULL) { + DEBUG("ipv6: could not get a copy of pkt\n"); + gnrc_pktbuf_release(*pkt); + return NULL; + } + *pkt = tmp; + + ext_snip = gnrc_pktbuf_mark(*pkt, offset, GNRC_NETTYPE_IPV6_EXT); + next = *pkt; + + if (ext_snip == NULL) { + gnrc_pktbuf_release(*pkt); + return NULL; + } + } + else { + /* the header is already marked */ + + next = NULL; + + for (tmp = *pkt; tmp != NULL; tmp = tmp->next) { + if (tmp->next == current) { + next = tmp; + break; + } + } + + assert(next != NULL); + } + + return next; +} + + /* * current pkt * | | @@ -100,86 +150,68 @@ void gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh) { - gnrc_pktsnip_t *ext_snip, *tmp, *next; ipv6_ext_t *ext; - size_t offset = 0; - ext = (ipv6_ext_t *) current->data; + while (true) { + ext = (ipv6_ext_t *) current->data; - switch (nh) { - case PROTNUM_IPV6_EXT_RH: + switch (nh) { + case PROTNUM_IPV6_EXT_RH: #ifdef MODULE_GNRC_RPL_SRH - switch (_handle_rh(current, pkt)) { - case GNRC_IPV6_EXT_OK: - /* We are the final destination. So proceeds like normal packet. */ - nh = ext->nh; - DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); - offset = ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT); - break; - - case GNRC_IPV6_EXT_ERROR: - /* already released by _handle_rh, so no release here */ - return; + switch (_handle_rh(current, pkt)) { + case GNRC_IPV6_EXT_OK: + /* We are the final destination. So proceeds like normal packet. */ + nh = ext->nh; + DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); - case GNRC_IPV6_EXT_FORWARDED: - return; - } + if ((current = _mark_extension_header(current, &pkt)) == NULL) { + return; + } - break; -#endif + gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */ - case PROTNUM_IPV6_EXT_HOPOPT: - case PROTNUM_IPV6_EXT_DST: - case PROTNUM_IPV6_EXT_FRAG: - case PROTNUM_IPV6_EXT_AH: - case PROTNUM_IPV6_EXT_ESP: - case PROTNUM_IPV6_EXT_MOB: - /* TODO: add handling of types */ - nh = ext->nh; - DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); - offset = ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT); - break; - - default: - DEBUG("ipv6_ext: unknown next header: %" PRIu8 "\n", nh); - gnrc_pktbuf_release(pkt); - return; - } + return; - if (current == pkt) { - if ((tmp = gnrc_pktbuf_start_write(pkt)) == NULL) { - DEBUG("ipv6: could not get a copy of pkt\n"); - gnrc_pktbuf_release(pkt); - return; - } - pkt = tmp; + case GNRC_IPV6_EXT_ERROR: + /* already released by _handle_rh, so no release here */ + return; - ext_snip = gnrc_pktbuf_mark(pkt, offset, GNRC_NETTYPE_IPV6_EXT); - next = pkt; + case GNRC_IPV6_EXT_FORWARDED: + /* the packet is forwarded and released. finish processing */ + return; + } - if (ext_snip == NULL) { - gnrc_pktbuf_release(pkt); - return; - } - } - else { - /* the header is already marked */ + break; +#endif - next = NULL; + case PROTNUM_IPV6_EXT_HOPOPT: + case PROTNUM_IPV6_EXT_DST: + case PROTNUM_IPV6_EXT_FRAG: + case PROTNUM_IPV6_EXT_AH: + case PROTNUM_IPV6_EXT_ESP: + case PROTNUM_IPV6_EXT_MOB: + /* TODO: add handling of types */ + nh = ext->nh; + DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); + + if ((current = _mark_extension_header(current, &pkt)) == NULL) { + return; + } + + gnrc_pktbuf_hold(pkt, 1); /* don't release on next dispatch */ + if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) { + gnrc_pktbuf_release(pkt); + } - for (tmp = pkt; tmp != NULL; tmp = tmp->next) { - if (tmp->next == current) { - next = tmp; break; - } - } - assert(next != NULL); + default: + gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */ + return; + } } - gnrc_ipv6_demux(iface, next, pkt, nh); /* demultiplex next header */ - - return; + assert(false); /* never reaches here */ } gnrc_pktsnip_t *gnrc_ipv6_ext_build(gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *next, diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index d608dcd3e8..b09cde2d3c 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -69,9 +69,6 @@ kernel_pid_t gnrc_ipv6_pid = KERNEL_PID_UNDEF; /* handles GNRC_NETAPI_MSG_TYPE_RCV commands */ static void _receive(gnrc_pktsnip_t *pkt); -/* dispatches received IPv6 packet for upper layer */ -static void _dispatch_rcv_pkt(gnrc_nettype_t type, uint32_t demux_ctx, - gnrc_pktsnip_t *pkt); /* Sends packet over the appropriate interface(s). * prep_hdr: prepare header for sending (call to _fill_ipv6_hdr()), otherwise * assume it is already prepared */ @@ -100,6 +97,9 @@ kernel_pid_t gnrc_ipv6_init(void) return gnrc_ipv6_pid; } +static void _dispatch_next_header(gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, + uint8_t nh, bool interested); + /* * current pkt * | | @@ -108,10 +108,9 @@ kernel_pid_t gnrc_ipv6_init(void) */ void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh) { - int receiver_num; bool interested = false; - pkt->type = gnrc_nettype_from_protnum(nh); + current->type = gnrc_nettype_from_protnum(nh); switch (nh) { #ifdef MODULE_GNRC_ICMPV6 @@ -139,76 +138,106 @@ void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t break; default: (void)iface; - break; - } - - DEBUG("ipv6: forward nh = %u to other threads\n", nh); - receiver_num = gnrc_netreg_num(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL) + - gnrc_netreg_num(GNRC_NETTYPE_IPV6, nh); - - if (receiver_num == 0) { - DEBUG("ipv6: unable to forward packet as no one is interested in it\n"); - - if (!interested) { +#ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC + /* second statement is true for small 6LoWPAN NHC decompressed frames + * since in this case it looks like + * + * * GNRC_NETTYPE_UNDEF <- pkt + * v + * * GNRC_NETTYPE_UDP <- current + * v + * * GNRC_NETTYPE_EXT + * v + * * GNRC_NETTYPE_IPV6 + */ + assert((current == pkt) || (current == pkt->next)); +#else assert(current == pkt); - gnrc_pktbuf_release(pkt); - return; - } +#endif + break; } - else { - if (!interested) { - assert(current == pkt); - /* IPv6 is not interested anymore so `- 1` */ - receiver_num--; - } - - gnrc_pktbuf_hold(current, receiver_num); - /* XXX can't use gnrc_netapi_dispatch_receive() twice here since a call to that function - * implicitly hands all rights to the packet to one of the receiving threads. As a - * result, the second call to gnrc_netapi_dispatch_receive() would be invalid */ - _dispatch_rcv_pkt(current->type, GNRC_NETREG_DEMUX_CTX_ALL, current); - _dispatch_rcv_pkt(GNRC_NETTYPE_IPV6, nh, current); + _dispatch_next_header(current, pkt, nh, interested); - if (!interested) { - return; - } + if (!interested) { + return; } switch (nh) { #ifdef MODULE_GNRC_ICMPV6 - case PROTNUM_ICMPV6: - DEBUG("ipv6: handle ICMPv6 packet (nh = %u)\n", nh); - gnrc_icmpv6_demux(iface, pkt); - break; + case PROTNUM_ICMPV6: + DEBUG("ipv6: handle ICMPv6 packet (nh = %u)\n", nh); + gnrc_icmpv6_demux(iface, pkt); + gnrc_pktbuf_release(pkt); + return; #endif #ifdef MODULE_GNRC_IPV6_EXT - case PROTNUM_IPV6_EXT_HOPOPT: - case PROTNUM_IPV6_EXT_DST: - case PROTNUM_IPV6_EXT_RH: - case PROTNUM_IPV6_EXT_FRAG: - case PROTNUM_IPV6_EXT_AH: - case PROTNUM_IPV6_EXT_ESP: - case PROTNUM_IPV6_EXT_MOB: - DEBUG("ipv6: handle extension header (nh = %u)\n", nh); + case PROTNUM_IPV6_EXT_HOPOPT: + case PROTNUM_IPV6_EXT_DST: + case PROTNUM_IPV6_EXT_RH: + case PROTNUM_IPV6_EXT_FRAG: + case PROTNUM_IPV6_EXT_AH: + case PROTNUM_IPV6_EXT_ESP: + case PROTNUM_IPV6_EXT_MOB: + DEBUG("ipv6: handle extension header (nh = %u)\n", nh); - gnrc_ipv6_ext_demux(iface, current, pkt, nh); + gnrc_ipv6_ext_demux(iface, current, pkt, nh); - return; + return; #endif - case PROTNUM_IPV6: - DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %u)\n", nh); - _decapsulate(pkt); - return; - default: - break; + case PROTNUM_IPV6: + DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %u)\n", nh); + _decapsulate(pkt); + return; + default: + assert(false); + break; } - assert(current == pkt); - gnrc_pktbuf_release(pkt); + assert(false); } /* internal functions */ +static void _dispatch_next_header(gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, + uint8_t nh, bool interested) +{ +#ifdef MODULE_GNRC_IPV6_EXT + const bool should_dispatch_current_type = ((current->type != GNRC_NETTYPE_IPV6_EXT) || + (current->next->type == GNRC_NETTYPE_IPV6)); +#else + const bool should_dispatch_current_type = (current->next->type == GNRC_NETTYPE_IPV6); +#endif + + DEBUG("ipv6: forward nh = %u to other threads\n", nh); + + /* dispatch IPv6 extension header only once */ + if (should_dispatch_current_type) { + bool should_release = (gnrc_netreg_num(GNRC_NETTYPE_IPV6, nh) == 0) && + (!interested); + + if (!should_release) { + gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in + * next dispatch */ + } + if (gnrc_netapi_dispatch_receive(current->type, + GNRC_NETREG_DEMUX_CTX_ALL, + pkt) == 0) { + gnrc_pktbuf_release(pkt); + } + + if (should_release) { + return; + } + } + if (interested) { + gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in + * next dispatch */ + } + if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) { + gnrc_pktbuf_release(pkt); + } +} + static void *_event_loop(void *args) { msg_t msg, reply, msg_q[GNRC_IPV6_MSG_QUEUE_SIZE]; @@ -743,22 +772,6 @@ static inline bool _pkt_not_for_me(kernel_pid_t *iface, ipv6_hdr_t *hdr) } } -static void _dispatch_rcv_pkt(gnrc_nettype_t type, uint32_t demux_ctx, - gnrc_pktsnip_t *pkt) -{ - gnrc_netreg_entry_t *entry = gnrc_netreg_lookup(type, demux_ctx); - - while (entry) { - DEBUG("ipv6: Send receive command for %p to %" PRIu16 "\n", (void *)pkt, - entry->pid); - if (gnrc_netapi_receive(entry->pid, pkt) < 1) { - DEBUG("ipv6: unable to deliver packet\n"); - gnrc_pktbuf_release(pkt); - } - entry = gnrc_netreg_getnext(entry); - } -} - static void _receive(gnrc_pktsnip_t *pkt) { kernel_pid_t iface = KERNEL_PID_UNDEF; @@ -868,7 +881,7 @@ static void _receive(gnrc_pktsnip_t *pkt) * links." */ if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) { - DEBUG("ipv6: do not forward packets with link-local source or"\ + DEBUG("ipv6: do not forward packets with link-local source or" " destination address\n"); gnrc_pktbuf_release(pkt); return; -- GitLab