void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh) { int receiver_num; pkt->type = gnrc_nettype_from_protnum(nh); switch (nh) { #ifdef MODULE_GNRC_ICMPV6 case PROTNUM_ICMPV6: DEBUG("ipv6: handle ICMPv6 packet (nh = %" PRIu8 ")\n", nh); gnrc_icmpv6_demux(iface, pkt); break; #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 = %" PRIu8 ")\n", nh); if (!gnrc_ipv6_ext_demux(iface, pkt, nh)) { DEBUG("ipv6: unable to parse extension headers.\n"); gnrc_pktbuf_release(pkt); return; } #endif case PROTNUM_IPV6: DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %" PRIu8 ")\n", nh); _decapsulate(pkt); break; default: (void)iface; break; } DEBUG("ipv6: forward nh = %" PRIu8 " 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"); gnrc_pktbuf_release(pkt); return; } gnrc_pktbuf_hold(pkt, receiver_num - 1); /* IPv6 is not interested anymore so `- 1` */ /* 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(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt); _dispatch_rcv_pkt(GNRC_NETTYPE_IPV6, nh, pkt); }
/* * current pkt * | | * v v * IPv6 <- IPv6_EXT <- IPv6_EXT <- UNDEF */ void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh) { bool interested = false; current->type = gnrc_nettype_from_protnum(nh); switch (nh) { #ifdef MODULE_GNRC_ICMPV6 case PROTNUM_ICMPV6: assert(current == pkt); interested = true; break; #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: interested = true; break; #endif case PROTNUM_IPV6: assert(current == pkt); interested = true; break; default: (void)iface; #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); #endif break; } _dispatch_next_header(current, pkt, nh, interested); 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); 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); gnrc_ipv6_ext_demux(iface, current, pkt, nh); return; #endif case PROTNUM_IPV6: DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %u)\n", nh); _decapsulate(pkt); return; default: assert(false); break; } assert(false); }