diff --git a/sys/include/net/gnrc/rpl/srh.h b/sys/include/net/gnrc/rpl/srh.h index 21fce7fe123e4af8b9d0a94c4d4370f067fb2f8d..42ff83b5e691bb412d80112106df061a629b1bc2 100644 --- a/sys/include/net/gnrc/rpl/srh.h +++ b/sys/include/net/gnrc/rpl/srh.h @@ -56,14 +56,18 @@ typedef struct __attribute__((packed)) { * common among all routing headers, so it should be handled by an * external routing header handler. * - * @param[in,out] ipv6 The IPv6 header of the incoming packet. + * @param[in, out] ipv6 The IPv6 header of the incoming packet. * @param[in] rh A RPL source routing header. + * @param[out] err_ptr A pointer to an erroneous octet within @p rh when + * return value is @ref GNRC_IPV6_EXT_RH_ERROR. For any + * other return value than @ref GNRC_IPV6_EXT_RH_ERROR the + * value of `err_ptr` is not defined. * * @return @ref GNRC_IPV6_EXT_RH_AT_DST, on success * @return @ref GNRC_IPV6_EXT_RH_FORWARDED, when @p pkt *should be* forwarded * @return @ref GNRC_IPV6_EXT_RH_ERROR, on error */ -int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh); +int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh, void **err_ptr); #ifdef __cplusplus } diff --git a/sys/net/gnrc/network_layer/ipv6/ext/rh/gnrc_ipv6_ext_rh.c b/sys/net/gnrc/network_layer/ipv6/ext/rh/gnrc_ipv6_ext_rh.c index 68d0c2b7e583bcf780bb19f37f93d6cdf37dadb3..8a56bad75656e064036014210577f5c7de351bb0 100644 --- a/sys/net/gnrc/network_layer/ipv6/ext/rh/gnrc_ipv6_ext_rh.c +++ b/sys/net/gnrc/network_layer/ipv6/ext/rh/gnrc_ipv6_ext_rh.c @@ -18,6 +18,8 @@ #include "net/ipv6/ext/rh.h" #include "net/gnrc.h" +#include "net/gnrc/icmpv6/error.h" + #ifdef MODULE_GNRC_RPL_SRH #include "net/gnrc/rpl/srh.h" #endif @@ -35,7 +37,8 @@ static void _forward_pkt(gnrc_pktsnip_t *pkt, ipv6_hdr_t *hdr) if (--(hdr->hl) == 0) { DEBUG("ipv6_ext_rh: 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; } /* remove L2 headers around IPV6 */ @@ -66,6 +69,7 @@ int gnrc_ipv6_ext_rh_process(gnrc_pktsnip_t *pkt) ipv6_ext_rh_t *ext = pkt->data; ipv6_hdr_t *hdr; int res = GNRC_IPV6_EXT_RH_AT_DST; + void *err_ptr = NULL; /* check seg_left early to avoid duplicating the packet */ if (ext->seg_left == 0) { @@ -77,11 +81,12 @@ int gnrc_ipv6_ext_rh_process(gnrc_pktsnip_t *pkt) switch (ext->type) { #ifdef MODULE_GNRC_RPL_SRH case IPV6_EXT_RH_TYPE_RPL_SRH: - res = gnrc_rpl_srh_process(hdr, (gnrc_rpl_srh_t *)ext); + res = gnrc_rpl_srh_process(hdr, (gnrc_rpl_srh_t *)ext, &err_ptr); break; #endif default: res = GNRC_IPV6_EXT_RH_ERROR; + err_ptr = &ext->type; break; } switch (res) { @@ -91,7 +96,17 @@ int gnrc_ipv6_ext_rh_process(gnrc_pktsnip_t *pkt) case GNRC_IPV6_EXT_RH_AT_DST: break; default: - gnrc_pktbuf_release(pkt); +#ifdef MODULE_GNRC_ICMPV6_ERROR + if (err_ptr) { + gnrc_icmpv6_error_param_prob_send( + ICMPV6_ERROR_PARAM_PROB_HDR_FIELD, + err_ptr, pkt + ); + } +#else + (void)err_ptr; +#endif + gnrc_pktbuf_release_error(pkt, EINVAL); break; } return res; diff --git a/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c b/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c index 618d749a1a3ae106f863cbc869e76ace9db9c191..fdf72ccbe7e1b11c962d0d0a30d26d03c75686ed 100644 --- a/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c +++ b/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c @@ -31,10 +31,10 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN]; /* checks if multiple addresses within the source routing header exist on my * interfaces */ -static bool _contains_multiple_of_my_addr(const ipv6_addr_t *dst, - const gnrc_rpl_srh_t *rh, - unsigned num_addr, - unsigned compri_addr_len) +static void *_contains_multiple_of_my_addr(const ipv6_addr_t *dst, + const gnrc_rpl_srh_t *rh, + unsigned num_addr, + unsigned compri_addr_len) { ipv6_addr_t addr; uint8_t *addr_vec = (uint8_t *) (rh + 1); @@ -45,30 +45,30 @@ static bool _contains_multiple_of_my_addr(const ipv6_addr_t *dst, memcpy(&addr, dst, pref_elided); for (unsigned i = 0; i < num_addr; i++) { + uint8_t *addr_vec_ptr = &addr_vec[i * compri_addr_len]; + if (i == num_addr - 1) { pref_elided = GNRC_RPL_SRH_COMPRE(rh->compr); addr_len = sizeof(ipv6_addr_t) - pref_elided; } - memcpy(&addr.u8[pref_elided], &addr_vec[i * compri_addr_len], addr_len); + memcpy(&addr.u8[pref_elided], addr_vec_ptr, addr_len); if (gnrc_netif_get_by_ipv6_addr(&addr) != NULL) { if (found && ((i - found_pos) > 1)) { DEBUG("RPL SRH: found multiple addresses that belong to me - " "discard\n"); - /* TODO send an ICMP Parameter Problem (Code 0) and - * discard the packet */ - return true; + return addr_vec_ptr; } found_pos = i; found = true; } } - return false; + return NULL; } -int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh) +int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh, void **err_ptr) { ipv6_addr_t addr; - uint8_t *addr_vec = (uint8_t *) (rh + 1); + uint8_t *addr_vec = (uint8_t *) (rh + 1), *current_address; uint8_t num_addr; uint8_t current_pos, pref_elided, addr_len, compri_addr_len; const uint8_t new_seg_left = rh->seg_left - 1; @@ -83,7 +83,7 @@ int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh) if (rh->seg_left > num_addr) { DEBUG("RPL SRH: number of segments left > number of addresses - " "discard\n"); - /* TODO ICMP Parameter Problem - Code 0 */ + *err_ptr = &rh->seg_left; return GNRC_IPV6_EXT_RH_ERROR; } @@ -94,24 +94,27 @@ int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh) compri_addr_len = sizeof(ipv6_addr_t) - GNRC_RPL_SRH_COMPRI(rh->compr); addr_len = sizeof(ipv6_addr_t) - pref_elided; memcpy(&addr, &ipv6->dst, pref_elided); - memcpy(&addr.u8[pref_elided], - &addr_vec[(current_pos - 1) * compri_addr_len], - addr_len); + current_address = &addr_vec[(current_pos - 1) * compri_addr_len]; + memcpy(&addr.u8[pref_elided], current_address, addr_len); - if (ipv6_addr_is_multicast(&ipv6->dst) || ipv6_addr_is_multicast(&addr)) { - DEBUG("RPL SRH: found a multicast address - discard\n"); - /* TODO discard the packet */ + if (ipv6_addr_is_multicast(&ipv6->dst)) { + DEBUG("RPL SRH: found a multicast destination address - discard\n"); + *err_ptr = &ipv6->dst; + return GNRC_IPV6_EXT_RH_ERROR; + } + if (ipv6_addr_is_multicast(&addr)) { + DEBUG("RPL SRH: found a multicast addres in next address - discard\n"); + *err_ptr = current_address; return GNRC_IPV6_EXT_RH_ERROR; } /* check if multiple addresses of my interface exist */ - if (_contains_multiple_of_my_addr(&ipv6->dst, rh, num_addr, - compri_addr_len)) { + if ((*err_ptr = _contains_multiple_of_my_addr(&ipv6->dst, rh, num_addr, + compri_addr_len))) { return GNRC_IPV6_EXT_RH_ERROR; } rh->seg_left = new_seg_left; - memcpy(&addr_vec[(current_pos - 1) * compri_addr_len], - &ipv6->dst.u8[pref_elided], addr_len); + memcpy(current_address, &ipv6->dst.u8[pref_elided], addr_len); DEBUG("RPL SRH: Next hop: %s at position %d\n", ipv6_addr_to_str(addr_str, &addr, sizeof(addr_str)), current_pos);