diff --git a/examples/gnrc_networking/Makefile b/examples/gnrc_networking/Makefile index 4d361f8250fcb64b0ba40c8b3efca92be92daffc..7aac1aee1282c914dfe5e460be45a466d267c051 100644 --- a/examples/gnrc_networking/Makefile +++ b/examples/gnrc_networking/Makefile @@ -20,6 +20,8 @@ BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-mega2560 arduino-uno \ # NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present USEMODULE += gnrc_netdev_default USEMODULE += auto_init_gnrc_netif +# Activate ICMPv6 error messages +USEMODULE += gnrc_icmpv6_error # Specify the mandatory networking modules for IPv6 and UDP USEMODULE += gnrc_ipv6_router_default USEMODULE += gnrc_udp diff --git a/sys/include/net/gnrc/icmpv6/error.h b/sys/include/net/gnrc/icmpv6/error.h index 20d0343196f66b31ff8c648925b78ec9f572d949..7bd527e13162a71a217b8ecbc01ccf86de2c10fa 100644 --- a/sys/include/net/gnrc/icmpv6/error.h +++ b/sys/include/net/gnrc/icmpv6/error.h @@ -33,133 +33,63 @@ extern "C" { #endif -/** - * @brief Builds an ICMPv6 destination unreachable message for sending. - * - * @param[in] code The code for the message @see net/icmpv6.h. - * @param[in] orig_pkt The invoking packet. - * - * @return The destination unreachable message on success. - * @return NULL, on failure. - */ -gnrc_pktsnip_t *gnrc_icmpv6_error_dst_unr_build(uint8_t code, gnrc_pktsnip_t *orig_pkt); - -/** - * @brief Builds an ICMPv6 packet too big message for sending. - * - * @param[in] mtu The maximum transission unit of the next-hop link. - * @param[in] orig_pkt The invoking packet. - * - * @return The packet too big message on success. - * @return NULL, on failure. - */ -gnrc_pktsnip_t *gnrc_icmpv6_error_pkt_too_big_build(uint32_t mtu, gnrc_pktsnip_t *orig_pkt); - -/** - * @brief Builds an ICMPv6 time exceeded message for sending. - * - * @param[in] code The code for the message @see net/icmpv6.h. - * @param[in] orig_pkt The invoking packet. - * - * @return The time exceeded message on success. - * @return NULL, on failure. - */ -gnrc_pktsnip_t *gnrc_icmpv6_error_time_exc_build(uint8_t code, gnrc_pktsnip_t *orig_pkt); - -/** - * @brief Builds an ICMPv6 parameter problem message for sending. - * - * @param[in] code The code for the message @see net/icmpv6.h. - * @param[in] ptr Pointer to the errorneous octet in @p orig_pkt. - * @param[in] orig_pkt The invoking packet. - * - * @return The parameter problem message on success. - * @return NULL, on failure. - */ -gnrc_pktsnip_t *gnrc_icmpv6_error_param_prob_build(uint8_t code, void *ptr, - gnrc_pktsnip_t *orig_pkt); - +#if defined(MODULE_GNRC_ICMPV6_ERROR) || defined(DOXYGEN) /** * @brief Sends an ICMPv6 destination unreachable message for sending. * - * @param[in] code The code for the message @see net/icmpv6.h. + * @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6 + * + * @param[in] code The [code for the message](@ref net_icmpv6_error_dst_unr_codes). * @param[in] orig_pkt The invoking packet. */ -static inline void gnrc_icmpv6_error_dst_unr_send(uint8_t code, gnrc_pktsnip_t *orig_pkt) -{ - gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_dst_unr_build(code, orig_pkt); - - if (pkt != NULL) { - gnrc_netapi_send(gnrc_ipv6_pid, pkt); - } -#ifdef MODULE_GNRC_PKTBUF - gnrc_pktbuf_release_error(orig_pkt, EHOSTUNREACH); -#else - (void)orig_pkt; -#endif -} +void gnrc_icmpv6_error_dst_unr_send(uint8_t code, const gnrc_pktsnip_t *orig_pkt); /** * @brief Sends an ICMPv6 packet too big message for sending. * + * @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6 + * * @param[in] mtu The maximum transission unit of the next-hop link. * @param[in] orig_pkt The invoking packet. */ -static inline void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu, gnrc_pktsnip_t *orig_pkt) -{ - gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_pkt_too_big_build(mtu, orig_pkt); - - if (pkt != NULL) { - gnrc_netapi_send(gnrc_ipv6_pid, pkt); - } -#ifdef MODULE_GNRC_PKTBUF - gnrc_pktbuf_release_error(orig_pkt, EMSGSIZE); -#else - (void)orig_pkt; -#endif -} +void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu, + const gnrc_pktsnip_t *orig_pkt); /** * @brief Sends an ICMPv6 time exceeded message for sending. * - * @param[in] code The code for the message @see net/icmpv6.h. + * @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6 + * + * @param[in] code The [code for the message](@ref net_icmpv6_error_time_exc_codes). * @param[in] orig_pkt The invoking packet. */ -static inline void gnrc_icmpv6_error_time_exc_send(uint8_t code, gnrc_pktsnip_t *orig_pkt) -{ - gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_time_exc_build(code, orig_pkt); - - if (pkt != NULL) { - gnrc_netapi_send(gnrc_ipv6_pid, pkt); - } -#ifdef MODULE_GNRC_PKTBUF - gnrc_pktbuf_release_error(orig_pkt, ETIMEDOUT); -#else - (void)orig_pkt; -#endif -} +void gnrc_icmpv6_error_time_exc_send(uint8_t code, + const gnrc_pktsnip_t *orig_pkt); /** * @brief Sends an ICMPv6 parameter problem message for sending. * - * @param[in] code The code for the message @see net/icmpv6.h. + * @pre @p orig_pkt is in receive order. + * @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6 + * + * + * @param[in] code The [code for the message](@ref net_icmpv6_error_param_prob_codes). * @param[in] ptr Pointer to the errorneous octet in @p orig_pkt. * @param[in] orig_pkt The invoking packet. */ -static inline void gnrc_icmpv6_error_param_prob_send(uint8_t code, void *ptr, - gnrc_pktsnip_t *orig_pkt) -{ - gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_param_prob_build(code, ptr, orig_pkt); - - if (pkt != NULL) { - gnrc_netapi_send(gnrc_ipv6_pid, pkt); - } -#ifdef MODULE_GNRC_PKTBUF - gnrc_pktbuf_release_error(orig_pkt, EINVAL); -#else - (void)orig_pkt; -#endif -} +void gnrc_icmpv6_error_param_prob_send(uint8_t code, void *ptr, + const gnrc_pktsnip_t *orig_pkt); +#else /* defined(MODULE_GNRC_ICMPV6_ERROR) || defined(DOXYGEN) */ +/* NOPs to make the usage code more readable */ +#define gnrc_icmpv6_error_dst_unr_send(code, orig_pkt) \ + (void)code; (void)orig_pkt +#define gnrc_icmpv6_error_pkt_too_big_send(mtu, orig_pkt) \ + (void)mtu; (void)orig_pkt +#define gnrc_icmpv6_error_time_exc_send(code, orig_pkt) \ + (void)code; (void)orig_pkt +#define gnrc_icmpv6_error_param_prob_send(code, ptr, orig_pkt) \ + (void)code; (void)ptr, (void)orig_pkt +#endif /* defined(MODULE_GNRC_ICMPV6_ERROR) || defined(DOXYGEN) */ #ifdef __cplusplus } diff --git a/sys/include/net/icmpv6.h b/sys/include/net/icmpv6.h index 3a9e606e16952ab9335b90aaf1cabc7f3036f468..29d0bec7e078c513d71b68961f006a07b52a8b59 100644 --- a/sys/include/net/icmpv6.h +++ b/sys/include/net/icmpv6.h @@ -75,6 +75,7 @@ extern "C" { * @{ * @name Codes for destination unreachable messages * + * @anchor net_icmpv6_error_dst_unr_codes * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.1"> * RFC 4443, section 3.1 * </a> @@ -97,6 +98,7 @@ extern "C" { * @{ * @name Codes for time exceeded messages * + * @anchor net_icmpv6_error_time_exc_codes * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.3"> * RFC 4443, section 3.3 * </a> @@ -111,6 +113,7 @@ extern "C" { * @{ * @name Codes for parameter problem messages * + * @anchor net_icmpv6_error_param_prob_codes * @see <a href="https://tools.ietf.org/html/rfc4443#section-3.4"> * RFC 4443, section 3.4 * </a> 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 4313414c45e583b2d92adf22f15f9fd6513e6682..ba1e028fb4943e3db695f70579b43999fdedaefe 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 @@ -12,59 +12,145 @@ * @file */ +#include "net/ipv6.h" +#include "net/gnrc/icmpv6.h" +#include "net/gnrc/netif.h" #include "net/gnrc/pktbuf.h" -#include "net/ipv6.h" #include "net/gnrc/icmpv6/error.h" -#include "net/gnrc/icmpv6.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" /* all error messages are basically the same size and format */ #define ICMPV6_ERROR_SZ (sizeof(icmpv6_error_dst_unr_t)) #define ICMPV6_ERROR_SET_VALUE(data, value) \ ((icmpv6_error_pkt_too_big_t *)(data))->mtu = byteorder_htonl(value) -/* TODO: generalize and centralize (see https://github.com/RIOT-OS/RIOT/pull/3184) */ #define MIN(a, b) ((a) < (b)) ? (a) : (b) -static inline size_t _fit(gnrc_pktsnip_t *pkt) +/** + * @brief Get packet fit. + * + * Get's the minimum size for an ICMPv6 error message packet, based on the + * invoking packet's size and the interface the invoking packet came over. + * + * @param[in] orig_pkt The invoking packet + * + * @return The supposed size of the ICMPv6 error message. + */ +static size_t _fit(const gnrc_pktsnip_t *orig_pkt) +{ + /* discarding const qualifier is safe here */ + gnrc_pktsnip_t *netif_hdr = gnrc_pktsnip_search_type( + (gnrc_pktsnip_t *)orig_pkt, GNRC_NETTYPE_NETIF + ); + size_t pkt_len = gnrc_pkt_len(orig_pkt) + ICMPV6_ERROR_SZ + + sizeof(ipv6_hdr_t); + + if (netif_hdr) { + gnrc_netif_hdr_t *data = netif_hdr->data; + gnrc_netif_t *netif = gnrc_netif_get_by_pid(data->if_pid); + + pkt_len -= netif_hdr->size; + DEBUG("gnrc_icmpv6_error: fitting to MTU of iface %u (%u)\n", + netif->pid, netif->ipv6.mtu); + return MIN(pkt_len, netif->ipv6.mtu - sizeof(ipv6_hdr_t)); + } + else { + /* packet does not have a netif header (most likely because it did not + * came from remote) => just assume pkt_len as ideal */ + DEBUG("gnrc_icmpv6_error: copying whole packet\n"); + return pkt_len; + } +} + +static inline bool _in_orig_pkt(const gnrc_pktsnip_t *orig_pkt) { - /* TODO: replace IPV6_MIN_MTU with known path MTU? */ - return MIN((gnrc_pkt_len(pkt) + ICMPV6_ERROR_SZ), IPV6_MIN_MTU); + return (orig_pkt != NULL) && (orig_pkt->type != GNRC_NETTYPE_NETIF); +} + +static size_t _copy_rcv_snip(gnrc_pktsnip_t *pkt, + const gnrc_pktsnip_t *orig_snip) +{ + /* always skip ICMPv6 error header */ + size_t offset = ICMPV6_ERROR_SZ; + const gnrc_pktsnip_t *ptr = orig_snip; + + while (_in_orig_pkt(ptr->next)) { + offset += ptr->next->size; + ptr = ptr->next; + } + + if (offset < pkt->size) { + uint8_t *data = pkt->data; + + memcpy(data + offset, orig_snip->data, + MIN(pkt->size - offset, orig_snip->size)); + } + return offset; +} + +static inline bool _check_send_order(const gnrc_pktsnip_t *pkt) +{ + /* sent packets in IPv6 start either with netif header or + * with IPv6 header (but then the NETIF header doesn't follow) */ + return (pkt->type == GNRC_NETTYPE_NETIF) || + ((pkt->type == GNRC_NETTYPE_IPV6) && + ((pkt->next == NULL) || (pkt->next->type != GNRC_NETTYPE_NETIF))); } /* Build a generic error message */ static gnrc_pktsnip_t *_icmpv6_error_build(uint8_t type, uint8_t code, - gnrc_pktsnip_t *orig_pkt, uint32_t value) + const gnrc_pktsnip_t *orig_pkt, + uint32_t value) { gnrc_pktsnip_t *pkt = gnrc_icmpv6_build(NULL, type, code, _fit(orig_pkt)); - /* copy as much of the originating packet into error message as fits the message's size */ + /* copy as much of the originating packet into error message as fits the + * message's size */ if (pkt != NULL) { - size_t offset = ICMPV6_ERROR_SZ; - uint8_t *data = pkt->data; - ICMPV6_ERROR_SET_VALUE(data, value); - while ((orig_pkt != NULL) && (offset < pkt->size)) { - memcpy(data + offset, orig_pkt->data, - MIN(pkt->size - offset, orig_pkt->size)); - offset += MIN(pkt->size - offset, orig_pkt->size); - orig_pkt = orig_pkt->next; + ICMPV6_ERROR_SET_VALUE(pkt->data, value); + if (_check_send_order(orig_pkt)) { + const gnrc_pktsnip_t *ptr = (orig_pkt->type == GNRC_NETTYPE_NETIF) + ? orig_pkt->next + : orig_pkt; + size_t offset = ICMPV6_ERROR_SZ; + + while ((ptr != NULL) && (offset < pkt->size)) { + uint8_t *data = pkt->data; + + memcpy(data + offset, ptr->data, MIN(pkt->size - offset, + ptr->size)); + offset += ptr->size; + ptr = ptr->next; + } + } + else { + while (_in_orig_pkt(orig_pkt)) { + _copy_rcv_snip(pkt, orig_pkt); + orig_pkt = orig_pkt->next; + } } } return pkt; } -gnrc_pktsnip_t *gnrc_icmpv6_error_dst_unr_build(uint8_t code, gnrc_pktsnip_t *orig_pkt) +static inline gnrc_pktsnip_t *_dst_unr_build(uint8_t code, + const gnrc_pktsnip_t *orig_pkt) { return _icmpv6_error_build(ICMPV6_DST_UNR, code, orig_pkt, 0); } -gnrc_pktsnip_t *gnrc_icmpv6_error_pkt_too_big_build(uint32_t mtu, gnrc_pktsnip_t *orig_pkt) +static inline gnrc_pktsnip_t *_pkt_too_big_build(uint32_t mtu, + const gnrc_pktsnip_t *orig_pkt) { return _icmpv6_error_build(ICMPV6_PKT_TOO_BIG, 0, orig_pkt, mtu); } -gnrc_pktsnip_t *gnrc_icmpv6_error_time_exc_build(uint8_t code, gnrc_pktsnip_t *orig_pkt) +static inline gnrc_pktsnip_t *_time_exc_build(uint8_t code, + const gnrc_pktsnip_t *orig_pkt) { return _icmpv6_error_build(ICMPV6_TIME_EXC, code, orig_pkt, 0); } @@ -74,8 +160,8 @@ static inline bool _in_range(uint8_t *ptr, uint8_t *start, size_t sz) return (ptr >= start) && (ptr < (start + sz)); } -gnrc_pktsnip_t *gnrc_icmpv6_error_param_prob_build(uint8_t code, void *ptr, - gnrc_pktsnip_t *orig_pkt) +static gnrc_pktsnip_t *_param_prob_build(uint8_t code, void *ptr, + const gnrc_pktsnip_t *orig_pkt) { gnrc_pktsnip_t *pkt = gnrc_icmpv6_build(NULL, ICMPV6_PARAM_PROB, code, _fit(orig_pkt)); @@ -83,39 +169,107 @@ gnrc_pktsnip_t *gnrc_icmpv6_error_param_prob_build(uint8_t code, void *ptr, /* copy as much of the originating packet into error message and * determine relative *ptr* offset */ if (pkt != NULL) { - size_t offset = sizeof(icmpv6_error_param_prob_t); - uint8_t *data = pkt->data; + icmpv6_error_param_prob_t *hdr = pkt->data; uint32_t ptr_offset = 0U; - bool found_offset = false; - - while (orig_pkt != NULL) { - /* copy as long as it fits into packet */ - if (offset < pkt->size) { - memcpy(data + offset, orig_pkt->data, - MIN(pkt->size - offset, orig_pkt->size)); - offset += MIN(pkt->size - offset, orig_pkt->size); - } + + while (_in_orig_pkt(orig_pkt)) { + /* copy as long as it fits into packet; parameter problem can only + * come from received packets */ + size_t offset = _copy_rcv_snip(pkt, orig_pkt); if (_in_range(ptr, orig_pkt->data, orig_pkt->size)) { - ptr_offset += (uint32_t)(((uint8_t *)ptr) - ((uint8_t *)orig_pkt->data)); - found_offset = true; - } - else if (!found_offset) { - ptr_offset += (uint32_t)orig_pkt->size; + ptr_offset = (uint32_t)(((uint8_t *)ptr) - + ((uint8_t *)orig_pkt->data) + + (offset - ICMPV6_ERROR_SZ)); } - orig_pkt = orig_pkt->next; - - if ((offset < pkt->size) && found_offset) { - break; - } } /* set "pointer" field to relative pointer offset */ - ((icmpv6_error_param_prob_t *)data)->ptr = byteorder_htonl(ptr_offset); + hdr->ptr = byteorder_htonl(ptr_offset); } return pkt; } +static void _send(gnrc_pktsnip_t *pkt, const gnrc_pktsnip_t *orig_pkt) +{ + if (pkt != NULL) { + /* discarding const qualifier is safe here */ + gnrc_pktsnip_t *ipv6 = gnrc_pktsnip_search_type((gnrc_pktsnip_t *)orig_pkt, + GNRC_NETTYPE_IPV6); + gnrc_pktsnip_t *netif = gnrc_pktsnip_search_type((gnrc_pktsnip_t *)orig_pkt, + GNRC_NETTYPE_NETIF); + assert(ipv6 != NULL); + ipv6_hdr_t *ipv6_hdr = ipv6->data; + ipv6 = gnrc_ipv6_hdr_build(pkt, NULL, &ipv6_hdr->src); + if (ipv6 == NULL) { + DEBUG("gnrc_icmpv6_error: No space in packet buffer left\n"); + gnrc_pktbuf_release(pkt); + return; + } + pkt = ipv6; + if (netif) { + /* copy interface from original netif header to assure packet + * goes out where it came from */ + gnrc_netif_hdr_t *netif_hdr = netif->data; + kernel_pid_t netif_pid = netif_hdr->if_pid; + + netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0); + if (netif == NULL) { + DEBUG("gnrc_icmpv6_error: No space in packet buffer left\n"); + gnrc_pktbuf_release(pkt); + return; + } + netif_hdr = netif->data; + netif_hdr->if_pid = netif_pid; + LL_PREPEND(pkt, netif); + } + if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6, + GNRC_NETREG_DEMUX_CTX_ALL, + pkt)) { + DEBUG("gnrc_icmpv6_error: No send handler found.\n"); + gnrc_pktbuf_release(pkt); + } + } + else { + DEBUG("gnrc_icmpv6_error: No space in packet buffer left\n"); + } +} + +void gnrc_icmpv6_error_dst_unr_send(uint8_t code, const gnrc_pktsnip_t *orig_pkt) +{ + gnrc_pktsnip_t *pkt = _dst_unr_build(code, orig_pkt); + + DEBUG("gnrc_icmpv6_error: trying to send destination unreachable error\n"); + _send(pkt, orig_pkt); +} + +void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu, + const gnrc_pktsnip_t *orig_pkt) +{ + gnrc_pktsnip_t *pkt = _pkt_too_big_build(mtu, orig_pkt); + + DEBUG("gnrc_icmpv6_error: trying to send packet too big error\n"); + _send(pkt, orig_pkt); +} + +void gnrc_icmpv6_error_time_exc_send(uint8_t code, + const gnrc_pktsnip_t *orig_pkt) +{ + gnrc_pktsnip_t *pkt = _time_exc_build(code, orig_pkt); + + DEBUG("gnrc_icmpv6_error: trying to send time exceeded error\n"); + _send(pkt, orig_pkt); +} + +void gnrc_icmpv6_error_param_prob_send(uint8_t code, void *ptr, + const gnrc_pktsnip_t *orig_pkt) +{ + gnrc_pktsnip_t *pkt = _param_prob_build(code, ptr, orig_pkt); + + DEBUG("gnrc_icmpv6_error: trying to send parameter problem error\n"); + _send(pkt, orig_pkt); +} + /** @} */ diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index 255095f6391b52faa632881a6508685fb066ff77..b030e39959bfa4f0ef30b1adeebaafa40622f3f0 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -321,7 +321,8 @@ static void _send_to_iface(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) ((gnrc_netif_hdr_t *)pkt->data)->if_pid = netif->pid; if (gnrc_pkt_len(pkt->next) > netif->ipv6.mtu) { DEBUG("ipv6: packet too big\n"); - gnrc_pktbuf_release(pkt); + gnrc_icmpv6_error_pkt_too_big_send(netif->ipv6.mtu, pkt); + gnrc_pktbuf_release_error(pkt, EMSGSIZE); return; } #ifdef MODULE_NETSTATS_IPV6 @@ -742,6 +743,7 @@ static void _receive(gnrc_pktsnip_t *pkt) #ifdef MODULE_GNRC_IPV6_WHITELIST if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(pkt->data))->src)) { DEBUG("ipv6: Source address not whitelisted, dropping packet\n"); + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt); gnrc_pktbuf_release(pkt); return; } @@ -749,6 +751,7 @@ static void _receive(gnrc_pktsnip_t *pkt) #ifdef MODULE_GNRC_IPV6_BLACKLIST if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(pkt->data))->src)) { DEBUG("ipv6: Source address blacklisted, dropping packet\n"); + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt); gnrc_pktbuf_release(pkt); return; } @@ -779,6 +782,7 @@ static void _receive(gnrc_pktsnip_t *pkt) else if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(ipv6->data))->src)) { /* if ipv6 header already marked*/ DEBUG("ipv6: Source address not whitelisted, dropping packet\n"); + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt); gnrc_pktbuf_release(pkt); return; } @@ -787,6 +791,7 @@ static void _receive(gnrc_pktsnip_t *pkt) else if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(ipv6->data))->src)) { /* if ipv6 header already marked*/ DEBUG("ipv6: Source address blacklisted, dropping packet\n"); + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt); gnrc_pktbuf_release(pkt); return; } @@ -812,7 +817,9 @@ static void _receive(gnrc_pktsnip_t *pkt) DEBUG("ipv6: invalid payload length: %d, actual: %d, dropping packet\n", (int) byteorder_ntohs(hdr->len), (int) (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t))); - gnrc_pktbuf_release(pkt); + gnrc_icmpv6_error_param_prob_send(ICMPV6_ERROR_PARAM_PROB_HDR_FIELD, + &(hdr->len), pkt); + gnrc_pktbuf_release_error(pkt, EINVAL); return; } @@ -836,6 +843,15 @@ static void _receive(gnrc_pktsnip_t *pkt) 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" " destination address\n"); +#ifdef MODULE_GNRC_ICMPV6_ERROR + if (ipv6_addr_is_link_local(&(hdr->src)) && + !ipv6_addr_is_link_local(&(hdr->dst))) { + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_SCOPE, pkt); + } + else if (!ipv6_addr_is_multicast(&(hdr->dst))) { + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR, pkt); + } +#endif gnrc_pktbuf_release(pkt); return; } @@ -868,7 +884,8 @@ static void _receive(gnrc_pktsnip_t *pkt) } else { DEBUG("ipv6: hop limit reached 0: drop packet\n"); - gnrc_pktbuf_release(pkt); + gnrc_icmpv6_error_time_exc_send(ICMPV6_ERROR_TIME_EXC_HL, pkt); + gnrc_pktbuf_release_error(pkt, ETIMEDOUT); return; } diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c index 65d3a32c33ec59ab90055397ebc01401bfb1ab04..4c33f9d53685471f333812c434b7ac7abda5df1c 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c @@ -17,6 +17,7 @@ #include <stdbool.h> #include <string.h> +#include "net/gnrc/icmpv6/error.h" #include "net/gnrc/ipv6.h" #include "net/gnrc/ipv6/nib/conf.h" #include "net/gnrc/ipv6/nib/nc.h" @@ -265,6 +266,8 @@ void _nib_nc_remove(_nib_onl_entry_t *node) (ptr != NULL) && (tmp = (ptr->next), 1); ptr = tmp) { gnrc_pktqueue_t *entry = gnrc_pktqueue_remove(&node->pktqueue, ptr); + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR, + entry->pkt); gnrc_pktbuf_release_error(entry->pkt, EHOSTUNREACH); entry->pkt = NULL; } diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c index 81eb765d4fe558cc6a29758abe9d9f8485b47c64..17bb9b91aeefc3a37c45410e84fb3c4f015a39a1 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c @@ -18,6 +18,7 @@ #include "log.h" #include "net/ipv6/addr.h" +#include "net/gnrc/icmpv6/error.h" #include "net/gnrc/nettype.h" #include "net/gnrc/netif/internal.h" #include "net/gnrc/ipv6/nib.h" @@ -203,6 +204,8 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst, * we also shouldn't release), but if netif is not defined we * should release in any case. */ if (netif == NULL) { + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR, + pkt); gnrc_pktbuf_release_error(pkt, EHOSTUNREACH); } res = -EHOSTUNREACH; @@ -225,6 +228,8 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst, memcpy(&route.next_hop, dst, sizeof(route.next_hop)); } else { + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_NO_ROUTE, + pkt); res = -ENETUNREACH; gnrc_pktbuf_release_error(pkt, ENETUNREACH); break; @@ -1168,9 +1173,13 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif_t *netif, } } else { + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR, + pkt); gnrc_pktbuf_release_error(pkt, EHOSTUNREACH); } #else /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */ + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR, + pkt); gnrc_pktbuf_release_error(pkt, EHOSTUNREACH); #endif /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */ } diff --git a/sys/net/gnrc/transport_layer/udp/gnrc_udp.c b/sys/net/gnrc/transport_layer/udp/gnrc_udp.c index ceeb4d33a09aa515a755a1abc233d123a64756db..0478ae21fa635966d805ab0d10c5c0c7d4be1ac1 100644 --- a/sys/net/gnrc/transport_layer/udp/gnrc_udp.c +++ b/sys/net/gnrc/transport_layer/udp/gnrc_udp.c @@ -27,6 +27,7 @@ #include "net/ipv6/hdr.h" #include "net/gnrc/udp.h" #include "net/gnrc.h" +#include "net/gnrc/icmpv6/error.h" #include "net/inet_csum.h" @@ -157,6 +158,8 @@ static void _receive(gnrc_pktsnip_t *pkt) /* send payload to receivers */ if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_UDP, port, pkt)) { DEBUG("udp: unable to forward packet as no one is interested in it\n"); + /* TODO determine if IPv6 packet, when IPv4 is implemented */ + gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PORT, pkt); gnrc_pktbuf_release(pkt); } }