diff --git a/sys/include/net/gnrc/rpl/srh.h b/sys/include/net/gnrc/rpl/srh.h index ab7248d2308f78690d77e27763c303e725d9993b..21fce7fe123e4af8b9d0a94c4d4370f067fb2f8d 100644 --- a/sys/include/net/gnrc/rpl/srh.h +++ b/sys/include/net/gnrc/rpl/srh.h @@ -52,6 +52,10 @@ typedef struct __attribute__((packed)) { /** * @brief Process the RPL source routing header. * + * @pre `rh->seq_left > 0`; The 0 case means the destination is reached and + * 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] rh A RPL source routing header. * 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 753d5bf65e0b9255e0808e7a433c1f119d3b5d92..618d749a1a3ae106f863cbc869e76ace9db9c191 100644 --- a/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c +++ b/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com> + * Copyright (C) 2018 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -10,6 +11,8 @@ * @{ * * @file + * @author Cenk Gündoğan <cnkgndgn@gmail.com> + * @author Martine Lenders <m.lenders@fu-berlin.de> */ #include <string.h> @@ -26,34 +29,74 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN]; #define GNRC_RPL_SRH_COMPRE(X) (X & 0x0F) #define GNRC_RPL_SRH_COMPRI(X) ((X & 0xF0) >> 4) -int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh) +/* 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) { - if (rh->seg_left == 0) { - return GNRC_IPV6_EXT_RH_AT_DST; + ipv6_addr_t addr; + uint8_t *addr_vec = (uint8_t *) (rh + 1); + bool found = false; + uint8_t pref_elided = GNRC_RPL_SRH_COMPRI(rh->compr); + uint8_t addr_len = compri_addr_len; + uint8_t found_pos = 0; + + memcpy(&addr, dst, pref_elided); + for (unsigned i = 0; i < num_addr; i++) { + 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); + 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; + } + found_pos = i; + found = true; + } } + return false; +} - uint8_t n = (((rh->len * 8) - GNRC_RPL_SRH_PADDING(rh->pad_resv) - - (16 - GNRC_RPL_SRH_COMPRE(rh->compr))) / - (16 - GNRC_RPL_SRH_COMPRI(rh->compr))) + 1; - ipv6_addr_t addr = ipv6->dst, tmp; - uint8_t i, pref_elided, tmp_pref_elided, addr_len, compri_addr_len, tmp_addr_len, found_pos = 0; +int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh) +{ + ipv6_addr_t addr; uint8_t *addr_vec = (uint8_t *) (rh + 1); - bool found = false; + 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; - DEBUG("RPL SRH: %u addresses in the routing header\n", (unsigned) n); + assert(rh->seg_left > 0); + num_addr = (((rh->len * 8) - GNRC_RPL_SRH_PADDING(rh->pad_resv) - + (16 - GNRC_RPL_SRH_COMPRE(rh->compr))) / + (16 - GNRC_RPL_SRH_COMPRI(rh->compr))) + 1; - if (rh->seg_left > n) { - DEBUG("RPL SRH: number of segments left > number of addresses - discard\n"); + DEBUG("RPL SRH: %u addresses in the routing header\n", (unsigned) num_addr); + + if (rh->seg_left > num_addr) { + DEBUG("RPL SRH: number of segments left > number of addresses - " + "discard\n"); /* TODO ICMP Parameter Problem - Code 0 */ return GNRC_IPV6_EXT_RH_ERROR; } - rh->seg_left--; - i = n - rh->seg_left; - pref_elided = rh->seg_left ? GNRC_RPL_SRH_COMPRI(rh->compr) : GNRC_RPL_SRH_COMPRE(rh->compr); + current_pos = num_addr - new_seg_left; + pref_elided = (new_seg_left) + ? GNRC_RPL_SRH_COMPRI(rh->compr) + : GNRC_RPL_SRH_COMPRE(rh->compr); compri_addr_len = sizeof(ipv6_addr_t) - GNRC_RPL_SRH_COMPRI(rh->compr); addr_len = sizeof(ipv6_addr_t) - pref_elided; - memcpy(&addr.u8[pref_elided], &addr_vec[(i - 1) * compri_addr_len], addr_len); + memcpy(&addr, &ipv6->dst, pref_elided); + memcpy(&addr.u8[pref_elided], + &addr_vec[(current_pos - 1) * compri_addr_len], + addr_len); if (ipv6_addr_is_multicast(&ipv6->dst) || ipv6_addr_is_multicast(&addr)) { DEBUG("RPL SRH: found a multicast address - discard\n"); @@ -62,32 +105,18 @@ int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh) } /* check if multiple addresses of my interface exist */ - tmp_pref_elided = GNRC_RPL_SRH_COMPRI(rh->compr); - tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided; - tmp = ipv6->dst; - for (uint8_t k = 0; k < n; k++) { - if (k == n - 1) { - tmp_pref_elided = GNRC_RPL_SRH_COMPRE(rh->compr); - tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided; - } - memcpy(&tmp.u8[tmp_pref_elided], &addr_vec[k * compri_addr_len], tmp_addr_len); - if (gnrc_netif_get_by_ipv6_addr(&tmp) != NULL) { - if (found && ((k - 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 GNRC_IPV6_EXT_RH_ERROR; - } - found_pos = k; - found = true; - } + if (_contains_multiple_of_my_addr(&ipv6->dst, rh, num_addr, + compri_addr_len)) { + return GNRC_IPV6_EXT_RH_ERROR; } - - memcpy(&addr_vec[(i - 1) * compri_addr_len], &ipv6->dst.u8[pref_elided], addr_len); + rh->seg_left = new_seg_left; + memcpy(&addr_vec[(current_pos - 1) * compri_addr_len], + &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)), i); + ipv6_addr_to_str(addr_str, &addr, sizeof(addr_str)), current_pos); - ipv6->dst = addr; + memcpy(&ipv6->dst, &addr, sizeof(ipv6->dst)); return GNRC_IPV6_EXT_RH_FORWARDED; }