1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-16 08:52:44 +01:00
RIOT/sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c
Martine Lenders a279228663 gnrc_rpl_srh: don't send error message on multicast error
A node is not supposed to send an ICMPv6 error message when the
destination or one of the addresses in the source route is multicast
but is supposed to be silently discarded (see [RFC4443] and [RFC6554]).
If we leave the `err_ptr` unset, the [node will not send an error
message][err_ptr set].

[RFC 4443]: https://tools.ietf.org/html/rfc4443#section-2.4
[RFC 6554]: https://tools.ietf.org/html/rfc6554#section-4.2
[err_ptr set]: https://github.com/RIOT-OS/RIOT/blob/9bc600a/sys/net/gnrc/network_layer/ipv6/ext/rh/gnrc_ipv6_ext_rh.c#L100-L105
2019-10-14 11:25:53 +02:00

126 lines
4.2 KiB
C

/*
* 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
* directory for more details.
*/
/**
* @{
*
* @file
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#include <string.h>
#include "net/gnrc/netif/internal.h"
#include "net/gnrc/ipv6/ext/rh.h"
#include "net/gnrc/rpl/srh.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#define GNRC_RPL_SRH_PADDING(X) ((X & 0xF0) >> 4)
#define GNRC_RPL_SRH_COMPRE(X) (X & 0x0F)
#define GNRC_RPL_SRH_COMPRI(X) ((X & 0xF0) >> 4)
/* checks if multiple addresses within the source routing header exist on my
* interfaces */
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);
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++) {
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_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");
return addr_vec_ptr;
}
found_pos = i;
found = true;
}
}
return NULL;
}
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), *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;
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;
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");
*err_ptr = &rh->seg_left;
return GNRC_IPV6_EXT_RH_ERROR;
}
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, &ipv6->dst, pref_elided);
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)) {
DEBUG("RPL SRH: found a multicast destination address - discard\n");
return GNRC_IPV6_EXT_RH_ERROR;
}
if (ipv6_addr_is_multicast(&addr)) {
DEBUG("RPL SRH: found a multicast addres in next address - discard\n");
return GNRC_IPV6_EXT_RH_ERROR;
}
/* check if multiple addresses of my interface exist */
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(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);
memcpy(&ipv6->dst, &addr, sizeof(ipv6->dst));
return GNRC_IPV6_EXT_RH_FORWARDED;
}
/** @} */