diff --git a/sys/net/gnrc/network_layer/icmpv6/error/gnrc_icmpv6_error.c b/sys/net/gnrc/network_layer/icmpv6/error/gnrc_icmpv6_error.c index 95d73a2ad0..bbe02165a5 100644 --- a/sys/net/gnrc/network_layer/icmpv6/error/gnrc_icmpv6_error.c +++ b/sys/net/gnrc/network_layer/icmpv6/error/gnrc_icmpv6_error.c @@ -234,7 +234,8 @@ static void _send(gnrc_pktsnip_t *pkt, const gnrc_pktsnip_t *orig_pkt, } } -static gnrc_pktsnip_t *_check_ipv6_hdr(const gnrc_pktsnip_t *orig_pkt) +static gnrc_pktsnip_t *_check_ipv6_hdr(const gnrc_pktsnip_t *orig_pkt, + uint8_t type, uint8_t code) { /* discarding const qualifier is safe here */ gnrc_pktsnip_t *ipv6 = gnrc_pktsnip_search_type((gnrc_pktsnip_t *)orig_pkt, @@ -242,16 +243,27 @@ static gnrc_pktsnip_t *_check_ipv6_hdr(const gnrc_pktsnip_t *orig_pkt) assert(ipv6 != NULL); const ipv6_hdr_t *ipv6_hdr = ipv6->data; + /* see https://tools.ietf.org/html/rfc4443#section-2.4 (e.6) */ if (ipv6_addr_is_unspecified(&ipv6_hdr->src) || - ipv6_addr_is_multicast(&ipv6_hdr->dst)) { + ipv6_addr_is_multicast(&ipv6_hdr->src)) { ipv6 = NULL; } + /* ipv6_hdr->dst may only be multicast for Packet Too Big Messages + * and Parameter Problem Messages with code 2, see + * https://tools.ietf.org/html/rfc4443#section-2.4 (e.3) */ + else if (ipv6_addr_is_multicast(&ipv6_hdr->dst)) { + if ((type != ICMPV6_PKT_TOO_BIG) && + ((type != ICMPV6_PARAM_PROB) || + (code != ICMPV6_ERROR_PARAM_PROB_OPT))) { + ipv6 = NULL; + } + } return ipv6; } void gnrc_icmpv6_error_dst_unr_send(uint8_t code, const gnrc_pktsnip_t *orig_pkt) { - gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt); + gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt, ICMPV6_DST_UNR, code); if (ipv6 != NULL) { gnrc_pktsnip_t *pkt = _dst_unr_build(code, orig_pkt); @@ -264,7 +276,7 @@ void gnrc_icmpv6_error_dst_unr_send(uint8_t code, const gnrc_pktsnip_t *orig_pkt void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu, const gnrc_pktsnip_t *orig_pkt) { - gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt); + gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt, ICMPV6_PKT_TOO_BIG, 0); if (ipv6 != NULL) { gnrc_pktsnip_t *pkt = _pkt_too_big_build(mtu, orig_pkt); @@ -277,7 +289,7 @@ void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu, void gnrc_icmpv6_error_time_exc_send(uint8_t code, const gnrc_pktsnip_t *orig_pkt) { - gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt); + gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt, ICMPV6_TIME_EXC, code); if (ipv6 != NULL) { gnrc_pktsnip_t *pkt = _time_exc_build(code, orig_pkt); @@ -290,7 +302,7 @@ void gnrc_icmpv6_error_time_exc_send(uint8_t code, void gnrc_icmpv6_error_param_prob_send(uint8_t code, void *ptr, const gnrc_pktsnip_t *orig_pkt) { - gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt); + gnrc_pktsnip_t *ipv6 = _check_ipv6_hdr(orig_pkt, ICMPV6_PARAM_PROB, code); if (ipv6 != NULL) { gnrc_pktsnip_t *pkt = _param_prob_build(code, ptr, orig_pkt);