diff --git a/examples/gnrc_networking/Makefile b/examples/gnrc_networking/Makefile
index 4d361f8250..7aac1aee12 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 20d0343196..7bd527e131 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 3a9e606e16..29d0bec7e0 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
* RFC 4443, section 3.1
*
@@ -97,6 +98,7 @@ extern "C" {
* @{
* @name Codes for time exceeded messages
*
+ * @anchor net_icmpv6_error_time_exc_codes
* @see
* RFC 4443, section 3.3
*
@@ -111,6 +113,7 @@ extern "C" {
* @{
* @name Codes for parameter problem messages
*
+ * @anchor net_icmpv6_error_param_prob_codes
* @see
* RFC 4443, section 3.4
*
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 4313414c45..ba1e028fb4 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)
{
- /* TODO: replace IPV6_MIN_MTU with known path MTU? */
- return MIN((gnrc_pkt_len(pkt) + ICMPV6_ERROR_SZ), IPV6_MIN_MTU);
+ /* 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)
+{
+ 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;
+ ptr_offset = (uint32_t)(((uint8_t *)ptr) -
+ ((uint8_t *)orig_pkt->data) +
+ (offset - ICMPV6_ERROR_SZ));
}
- else if (!found_offset) {
- ptr_offset += (uint32_t)orig_pkt->size;
- }
-
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 255095f639..b030e39959 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 65d3a32c33..4c33f9d536 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
#include
+#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 81eb765d4f..17bb9b91ae 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 ceeb4d33a0..0478ae21fa 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);
}
}