2015-05-22 21:47:37 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013 - 2014 INRIA.
|
|
|
|
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com>
|
|
|
|
*
|
|
|
|
* 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>
|
|
|
|
*/
|
|
|
|
|
2015-08-18 22:50:51 +02:00
|
|
|
#include "net/af.h"
|
2015-08-10 13:22:24 +02:00
|
|
|
#include "net/icmpv6.h"
|
2015-08-17 15:41:29 +02:00
|
|
|
#include "net/ipv6/hdr.h"
|
|
|
|
#include "net/gnrc/icmpv6.h"
|
|
|
|
#include "net/gnrc/ipv6.h"
|
2017-11-16 18:06:46 +01:00
|
|
|
#include "net/gnrc/netif/internal.h"
|
2015-08-17 15:41:29 +02:00
|
|
|
#include "net/gnrc.h"
|
2015-07-23 13:23:42 +02:00
|
|
|
#include "net/eui64.h"
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
#include "gnrc_rpl_internal/netstats.h"
|
|
|
|
#endif
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
#include "net/gnrc/rpl.h"
|
2016-04-12 11:33:52 +02:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_VALIDATION
|
|
|
|
#include "gnrc_rpl_internal/validation.h"
|
|
|
|
#endif
|
2015-08-17 15:41:29 +02:00
|
|
|
|
2015-08-23 14:25:39 +02:00
|
|
|
#ifdef MODULE_GNRC_RPL_P2P
|
|
|
|
#include "net/gnrc/rpl/p2p_structs.h"
|
|
|
|
#include "net/gnrc/rpl/p2p_dodag.h"
|
|
|
|
#include "net/gnrc/rpl/p2p.h"
|
|
|
|
#endif
|
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
#include "debug.h"
|
|
|
|
|
2015-08-19 22:08:07 +02:00
|
|
|
#if ENABLE_DEBUG
|
2015-05-22 21:47:37 +02:00
|
|
|
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
|
|
|
#endif
|
|
|
|
|
2015-08-18 21:13:53 +02:00
|
|
|
#define GNRC_RPL_GROUNDED_SHIFT (7)
|
|
|
|
#define GNRC_RPL_MOP_SHIFT (3)
|
2015-11-17 10:53:53 +01:00
|
|
|
#define GNRC_RPL_OPT_TRANSIT_E_FLAG_SHIFT (7)
|
|
|
|
#define GNRC_RPL_OPT_TRANSIT_E_FLAG (1 << GNRC_RPL_OPT_TRANSIT_E_FLAG_SHIFT)
|
2015-08-18 21:13:53 +02:00
|
|
|
#define GNRC_RPL_SHIFTED_MOP_MASK (0x7)
|
|
|
|
#define GNRC_RPL_PRF_MASK (0x7)
|
|
|
|
#define GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT (1 << 6)
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
static gnrc_netif_t *_find_interface_with_rpl_mcast(void)
|
2017-07-27 15:26:49 +02:00
|
|
|
{
|
2017-11-16 18:06:46 +01:00
|
|
|
gnrc_netif_t *netif = NULL;
|
2017-07-27 15:26:49 +02:00
|
|
|
|
2017-11-16 18:06:46 +01:00
|
|
|
while ((netif = gnrc_netif_iter(netif))) {
|
|
|
|
for (unsigned i = 0; i < GNRC_NETIF_IPV6_GROUPS_NUMOF; i++) {
|
2017-07-27 15:26:49 +02:00
|
|
|
if (ipv6_addr_equal(&netif->ipv6.groups[i], &ipv6_addr_all_rpl_nodes)) {
|
|
|
|
return netif;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
void gnrc_rpl_send(gnrc_pktsnip_t *pkt, kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst,
|
|
|
|
ipv6_addr_t *dodag_id)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2017-11-16 18:06:46 +01:00
|
|
|
gnrc_netif_t *netif;
|
2017-07-27 15:26:49 +02:00
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
(void)dodag_id;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *hdr;
|
2015-05-22 21:47:37 +02:00
|
|
|
if (iface == KERNEL_PID_UNDEF) {
|
2017-07-27 15:26:49 +02:00
|
|
|
netif = _find_interface_with_rpl_mcast();
|
|
|
|
|
2017-11-23 17:12:00 +01:00
|
|
|
if (netif == NULL) {
|
2016-03-22 14:58:23 +01:00
|
|
|
DEBUG("RPL: no suitable interface found for this destination address\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-27 15:26:49 +02:00
|
|
|
iface = netif->pid;
|
|
|
|
}
|
|
|
|
else {
|
2017-11-16 18:06:46 +01:00
|
|
|
netif = gnrc_netif_get_by_pid(iface);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2017-11-11 21:28:52 +01:00
|
|
|
if (dst == NULL) {
|
|
|
|
dst = (ipv6_addr_t *) &ipv6_addr_all_rpl_nodes;
|
|
|
|
}
|
2017-07-27 15:26:49 +02:00
|
|
|
|
2017-11-11 21:28:52 +01:00
|
|
|
if (src == NULL) {
|
|
|
|
src = gnrc_netif_ipv6_addr_best_src(netif, dst, true);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-09-22 16:26:19 +02:00
|
|
|
if (src == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: no suitable src address found\n");
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-21 16:24:40 +01:00
|
|
|
hdr = gnrc_ipv6_hdr_build(pkt, src, dst);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
|
|
|
if (hdr == NULL) {
|
|
|
|
DEBUG("RPL: Send - no space left in packet buffer\n");
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
pkt = hdr;
|
|
|
|
|
|
|
|
hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
|
|
|
((gnrc_netif_hdr_t *)hdr->data)->if_pid = iface;
|
|
|
|
LL_PREPEND(pkt, hdr);
|
|
|
|
|
|
|
|
if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: cannot send packet: no subscribers found.\n");
|
2016-03-22 14:58:23 +01:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-01 20:50:00 +01:00
|
|
|
gnrc_pktsnip_t *_dio_dodag_conf_build(gnrc_pktsnip_t *pkt, gnrc_rpl_dodag_t *dodag)
|
|
|
|
{
|
|
|
|
gnrc_rpl_opt_dodag_conf_t *dodag_conf;
|
|
|
|
gnrc_pktsnip_t *opt_snip;
|
|
|
|
if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_opt_dodag_conf_t),
|
|
|
|
GNRC_NETTYPE_UNDEF)) == NULL) {
|
|
|
|
DEBUG("RPL: BUILD DODAG CONF - no space left in packet buffer\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
dodag_conf = opt_snip->data;
|
|
|
|
dodag_conf->type = GNRC_RPL_OPT_DODAG_CONF;
|
|
|
|
dodag_conf->length = GNRC_RPL_OPT_DODAG_CONF_LEN;
|
|
|
|
dodag_conf->flags_a_pcs = 0;
|
|
|
|
dodag_conf->dio_int_doubl = dodag->dio_interval_doubl;
|
|
|
|
dodag_conf->dio_int_min = dodag->dio_min;
|
|
|
|
dodag_conf->dio_redun = dodag->dio_redun;
|
|
|
|
dodag_conf->max_rank_inc = byteorder_htons(dodag->instance->max_rank_inc);
|
|
|
|
dodag_conf->min_hop_rank_inc = byteorder_htons(dodag->instance->min_hop_rank_inc);
|
|
|
|
dodag_conf->ocp = byteorder_htons(dodag->instance->of->ocp);
|
|
|
|
dodag_conf->reserved = 0;
|
|
|
|
dodag_conf->default_lifetime = dodag->default_lifetime;
|
|
|
|
dodag_conf->lifetime_unit = byteorder_htons(dodag->lifetime_unit);
|
|
|
|
return opt_snip;
|
|
|
|
}
|
|
|
|
|
2016-02-03 08:37:59 +01:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_PIO
|
2017-11-23 17:12:00 +01:00
|
|
|
static bool _get_pl_entry(unsigned iface, ipv6_addr_t *pfx,
|
|
|
|
unsigned pfx_len, gnrc_ipv6_nib_pl_t *ple)
|
|
|
|
{
|
|
|
|
void *state = NULL;
|
|
|
|
|
|
|
|
while (gnrc_ipv6_nib_pl_iter(iface, &state, ple)) {
|
|
|
|
if (ipv6_addr_match_prefix(&ple->pfx, pfx) >= pfx_len) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-01 20:50:00 +01:00
|
|
|
gnrc_pktsnip_t *_dio_prefix_info_build(gnrc_pktsnip_t *pkt, gnrc_rpl_dodag_t *dodag)
|
|
|
|
{
|
2017-11-23 17:12:00 +01:00
|
|
|
gnrc_ipv6_nib_pl_t ple;
|
2015-11-01 20:50:00 +01:00
|
|
|
gnrc_rpl_opt_prefix_info_t *prefix_info;
|
|
|
|
gnrc_pktsnip_t *opt_snip;
|
2017-11-23 17:12:00 +01:00
|
|
|
|
2015-11-01 20:50:00 +01:00
|
|
|
if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_opt_prefix_info_t),
|
|
|
|
GNRC_NETTYPE_UNDEF)) == NULL) {
|
|
|
|
DEBUG("RPL: BUILD PREFIX INFO - no space left in packet buffer\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
prefix_info = opt_snip->data;
|
|
|
|
prefix_info->type = GNRC_RPL_OPT_PREFIX_INFO;
|
|
|
|
prefix_info->length = GNRC_RPL_OPT_PREFIX_INFO_LEN;
|
|
|
|
/* auto-address configuration */
|
|
|
|
prefix_info->LAR_flags = GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT;
|
2017-07-27 15:26:49 +02:00
|
|
|
prefix_info->prefix_len = 64;
|
2017-11-23 17:12:00 +01:00
|
|
|
if (_get_pl_entry(dodag->iface, &dodag->dodag_id, prefix_info->prefix_len,
|
|
|
|
&ple)) {
|
2017-11-23 17:12:43 +01:00
|
|
|
uint32_t now = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX;
|
2017-11-24 11:38:40 +01:00
|
|
|
uint32_t valid_ltime = (ple.valid_until < UINT32_MAX) ?
|
|
|
|
(ple.valid_until - now) / MS_PER_SEC : UINT32_MAX;
|
|
|
|
uint32_t pref_ltime = (ple.pref_until < UINT32_MAX) ?
|
|
|
|
(ple.pref_until - now) / MS_PER_SEC : UINT32_MAX;
|
|
|
|
|
|
|
|
prefix_info->valid_lifetime = byteorder_htonl(valid_ltime);
|
|
|
|
prefix_info->pref_lifetime = byteorder_htonl(pref_ltime);
|
2017-11-23 17:12:00 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
DEBUG("RPL: Prefix of DODAG-ID not in prefix list\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-11-01 20:50:00 +01:00
|
|
|
prefix_info->reserved = 0;
|
|
|
|
|
|
|
|
memset(&prefix_info->prefix, 0, sizeof(prefix_info->prefix));
|
2017-07-27 15:26:49 +02:00
|
|
|
ipv6_addr_init_prefix(&prefix_info->prefix, &dodag->dodag_id,
|
|
|
|
prefix_info->prefix_len);
|
2015-11-01 20:50:00 +01:00
|
|
|
return opt_snip;
|
|
|
|
}
|
2016-02-03 08:37:59 +01:00
|
|
|
#endif
|
2015-11-01 20:50:00 +01:00
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
void gnrc_rpl_send_DIO(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2015-08-27 22:29:08 +02:00
|
|
|
if (inst == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Error - trying to send DIO without being part of a dodag.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_dodag_t *dodag = &inst->dodag;
|
2016-03-22 10:17:32 +01:00
|
|
|
gnrc_pktsnip_t *pkt = NULL, *tmp;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_dio_t *dio;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-23 14:25:39 +02:00
|
|
|
#ifdef MODULE_GNRC_RPL_P2P
|
|
|
|
gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag);
|
|
|
|
if (dodag->instance->mop == GNRC_RPL_P2P_MOP) {
|
|
|
|
if (!p2p_ext->for_me) {
|
|
|
|
if ((pkt = gnrc_rpl_p2p_rdo_build(pkt, p2p_ext)) == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dodag->dio_opts &= ~GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-02-03 08:37:59 +01:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_PIO
|
2016-03-15 15:17:46 +01:00
|
|
|
if (dodag->dio_opts & GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO) {
|
2015-11-01 20:50:00 +01:00
|
|
|
if ((pkt = _dio_prefix_info_build(pkt, dodag)) == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2015-08-25 11:03:28 +02:00
|
|
|
}
|
2016-02-03 08:37:59 +01:00
|
|
|
#endif
|
2015-08-25 11:03:28 +02:00
|
|
|
|
2016-03-15 15:17:46 +01:00
|
|
|
if (dodag->dio_opts & GNRC_RPL_REQ_DIO_OPT_DODAG_CONF) {
|
2015-11-01 20:50:00 +01:00
|
|
|
if ((pkt = _dio_dodag_conf_build(pkt, dodag)) == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-15 15:17:46 +01:00
|
|
|
dodag->dio_opts &= ~GNRC_RPL_REQ_DIO_OPT_DODAG_CONF;
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2015-11-01 20:50:00 +01:00
|
|
|
if ((tmp = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_dio_t), GNRC_NETTYPE_UNDEF)) == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Send DIO - no space left in packet buffer\n");
|
2015-11-01 20:50:00 +01:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-11-01 20:50:00 +01:00
|
|
|
pkt = tmp;
|
|
|
|
dio = pkt->data;
|
2015-08-27 22:29:08 +02:00
|
|
|
dio->instance_id = inst->id;
|
2015-05-22 21:47:37 +02:00
|
|
|
dio->version_number = dodag->version;
|
2015-08-22 09:19:27 +02:00
|
|
|
/* a leaf node announces an INFINITE_RANK */
|
|
|
|
dio->rank = ((dodag->node_status == GNRC_RPL_LEAF_NODE) ?
|
|
|
|
byteorder_htons(GNRC_RPL_INFINITE_RANK) : byteorder_htons(dodag->my_rank));
|
2015-08-17 15:41:29 +02:00
|
|
|
dio->g_mop_prf = (dodag->grounded << GNRC_RPL_GROUNDED_SHIFT) |
|
2015-08-27 22:29:08 +02:00
|
|
|
(inst->mop << GNRC_RPL_MOP_SHIFT) | dodag->prf;
|
2015-05-22 21:47:37 +02:00
|
|
|
dio->dtsn = dodag->dtsn;
|
|
|
|
dio->flags = 0;
|
|
|
|
dio->reserved = 0;
|
|
|
|
dio->dodag_id = dodag->dodag_id;
|
|
|
|
|
2015-11-01 20:50:00 +01:00
|
|
|
if ((tmp = gnrc_icmpv6_build(pkt, ICMPV6_RPL_CTRL, GNRC_RPL_ICMPV6_CODE_DIO,
|
|
|
|
sizeof(icmpv6_hdr_t))) == NULL) {
|
|
|
|
DEBUG("RPL: Send DIO - no space left in packet buffer\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return;
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
2015-11-01 20:50:00 +01:00
|
|
|
pkt = tmp;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_tx_DIO(&gnrc_rpl_netstats, gnrc_pkt_len(pkt),
|
|
|
|
(destination && !ipv6_addr_is_multicast(destination)));
|
|
|
|
#endif
|
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
gnrc_rpl_send(pkt, dodag->iface, NULL, destination, &dodag->dodag_id);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
void gnrc_rpl_send_DIS(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *pkt;
|
2015-08-10 13:22:24 +02:00
|
|
|
icmpv6_hdr_t *icmp;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_dis_t *dis;
|
2015-09-08 09:26:48 +02:00
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
/* TODO: Currently the DIS is too small so that wireshark complains about an incorrect
|
|
|
|
* ethernet frame check sequence. In order to prevent this, 4 PAD1 options are added.
|
|
|
|
* This will be addressed in follow-up PRs */
|
2015-09-08 09:26:48 +02:00
|
|
|
uint8_t padding[] = {
|
|
|
|
0x01, 0x02, 0x00, 0x00
|
|
|
|
};
|
|
|
|
|
|
|
|
int size = sizeof(icmpv6_hdr_t) + sizeof(gnrc_rpl_dis_t) + sizeof(padding);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if ((pkt = gnrc_icmpv6_build(NULL, ICMPV6_RPL_CTRL, GNRC_RPL_ICMPV6_CODE_DIS, size)) == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Send DIS - no space left in packet buffer\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-10 13:22:24 +02:00
|
|
|
icmp = (icmpv6_hdr_t *)pkt->data;
|
2015-08-17 15:41:29 +02:00
|
|
|
dis = (gnrc_rpl_dis_t *)(icmp + 1);
|
2015-05-22 21:47:37 +02:00
|
|
|
dis->flags = 0;
|
|
|
|
dis->reserved = 0;
|
2015-09-08 09:26:48 +02:00
|
|
|
|
|
|
|
/* TODO add padding may be removed if packet size grows */
|
|
|
|
memcpy((dis + 1), padding, sizeof(padding));
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_tx_DIS(&gnrc_rpl_netstats, gnrc_pkt_len(pkt),
|
|
|
|
(destination && !ipv6_addr_is_multicast(destination)));
|
|
|
|
#endif
|
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
gnrc_rpl_send(pkt, KERNEL_PID_UNDEF, NULL, destination, (inst? &(inst->dodag.dodag_id) : NULL));
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
void gnrc_rpl_recv_DIS(gnrc_rpl_dis_t *dis, kernel_pid_t iface, ipv6_addr_t *src,
|
|
|
|
ipv6_addr_t *dst, uint16_t len)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
|
|
|
/* TODO handle Solicited Information Option */
|
2016-03-22 14:58:23 +01:00
|
|
|
(void)iface;
|
2016-06-01 14:04:28 +02:00
|
|
|
(void)dis;
|
|
|
|
(void)len;
|
|
|
|
|
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_rx_DIS(&gnrc_rpl_netstats, len, (dst && !ipv6_addr_is_multicast(dst)));
|
|
|
|
#endif
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2016-04-12 11:33:52 +02:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_VALIDATION
|
|
|
|
if (!gnrc_rpl_validation_DIS(dis, len)) {
|
2015-08-19 19:43:06 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-04-12 11:33:52 +02:00
|
|
|
#endif
|
2015-08-19 19:43:06 +02:00
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
if (ipv6_addr_is_multicast(dst)) {
|
2015-08-27 22:29:08 +02:00
|
|
|
for (uint8_t i = 0; i < GNRC_RPL_INSTANCES_NUMOF; ++i) {
|
|
|
|
if ((gnrc_rpl_instances[i].state != 0)
|
2015-08-22 09:19:27 +02:00
|
|
|
/* a leaf node should only react to unicast DIS */
|
2015-08-27 22:29:08 +02:00
|
|
|
&& (gnrc_rpl_instances[i].dodag.node_status != GNRC_RPL_LEAF_NODE)) {
|
2015-08-23 14:25:39 +02:00
|
|
|
#ifdef MODULE_GNRC_RPL_P2P
|
|
|
|
if (gnrc_rpl_instances[i].mop == GNRC_RPL_P2P_MOP) {
|
|
|
|
DEBUG("RPL: Not responding to DIS for P2P-RPL DODAG\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
2015-08-27 22:29:08 +02:00
|
|
|
trickle_reset_timer(&(gnrc_rpl_instances[i].dodag.trickle));
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-08-27 22:29:08 +02:00
|
|
|
for (uint8_t i = 0; i < GNRC_RPL_INSTANCES_NUMOF; ++i) {
|
|
|
|
if (gnrc_rpl_instances[i].state != 0) {
|
2016-03-15 15:17:46 +01:00
|
|
|
gnrc_rpl_instances[i].dodag.dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF;
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_send_DIO(&gnrc_rpl_instances[i], src);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-24 11:38:40 +01:00
|
|
|
static inline uint32_t _sec_to_ms(uint32_t sec)
|
|
|
|
{
|
|
|
|
if (sec == UINT32_MAX) {
|
|
|
|
/* infinite stays infinite */
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
else if (sec > ((UINT32_MAX - 1) / MS_PER_SEC)) {
|
|
|
|
/* truncate long intervals to largest possible value */
|
|
|
|
return UINT32_MAX - 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return sec * MS_PER_SEC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
/** @todo allow target prefixes in target options to be of variable length */
|
2015-08-27 22:29:08 +02:00
|
|
|
bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt_t *opt, uint16_t len,
|
2015-08-25 11:03:28 +02:00
|
|
|
ipv6_addr_t *src, uint32_t *included_opts)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
|
|
|
uint16_t l = 0;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_opt_target_t *first_target = NULL;
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_dodag_t *dodag = &inst->dodag;
|
2015-07-23 13:23:42 +02:00
|
|
|
eui64_t iid;
|
2015-08-25 11:03:28 +02:00
|
|
|
*included_opts = 0;
|
2015-08-19 20:57:28 +02:00
|
|
|
|
2016-04-12 11:33:52 +02:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_VALIDATION
|
|
|
|
if (!gnrc_rpl_validation_options(msg_type, inst, opt, len)) {
|
2015-08-19 20:57:28 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-04-12 11:33:52 +02:00
|
|
|
#else
|
|
|
|
(void) msg_type;
|
|
|
|
#endif
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-19 20:57:28 +02:00
|
|
|
while(l < len) {
|
2015-05-22 21:47:37 +02:00
|
|
|
switch(opt->type) {
|
2015-08-19 20:57:28 +02:00
|
|
|
case (GNRC_RPL_OPT_PAD1):
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: PAD1 option parsed\n");
|
2015-08-25 11:03:28 +02:00
|
|
|
*included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PAD1;
|
2015-05-22 21:47:37 +02:00
|
|
|
l += 1;
|
2015-08-17 15:41:29 +02:00
|
|
|
opt = (gnrc_rpl_opt_t *) (((uint8_t *) opt) + 1);
|
2015-05-22 21:47:37 +02:00
|
|
|
continue;
|
2015-08-19 20:57:28 +02:00
|
|
|
|
|
|
|
case (GNRC_RPL_OPT_PADN):
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: PADN option parsed\n");
|
2015-08-25 11:03:28 +02:00
|
|
|
*included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PADN;
|
2015-05-22 21:47:37 +02:00
|
|
|
break;
|
2015-08-19 20:57:28 +02:00
|
|
|
|
|
|
|
case (GNRC_RPL_OPT_DODAG_CONF):
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: DODAG CONF DIO option parsed\n");
|
2015-08-25 11:03:28 +02:00
|
|
|
*included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_DODAG_CONF;
|
2016-03-15 15:17:46 +01:00
|
|
|
dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_opt_dodag_conf_t *dc = (gnrc_rpl_opt_dodag_conf_t *) opt;
|
|
|
|
gnrc_rpl_of_t *of = gnrc_rpl_get_of_for_ocp(byteorder_ntohs(dc->ocp));
|
2015-05-22 21:47:37 +02:00
|
|
|
if (of != NULL) {
|
2015-08-27 22:29:08 +02:00
|
|
|
inst->of = of;
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
DEBUG("RPL: Unsupported OCP 0x%02x\n", byteorder_ntohs(dc->ocp));
|
2015-08-27 22:29:08 +02:00
|
|
|
inst->of = gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
dodag->dio_interval_doubl = dc->dio_int_doubl;
|
|
|
|
dodag->dio_min = dc->dio_int_min;
|
|
|
|
dodag->dio_redun = dc->dio_redun;
|
2015-08-27 22:29:08 +02:00
|
|
|
inst->max_rank_inc = byteorder_ntohs(dc->max_rank_inc);
|
|
|
|
inst->min_hop_rank_inc = byteorder_ntohs(dc->min_hop_rank_inc);
|
2015-05-22 21:47:37 +02:00
|
|
|
dodag->default_lifetime = dc->default_lifetime;
|
|
|
|
dodag->lifetime_unit = byteorder_ntohs(dc->lifetime_unit);
|
|
|
|
dodag->trickle.Imin = (1 << dodag->dio_min);
|
|
|
|
dodag->trickle.Imax = dodag->dio_interval_doubl;
|
|
|
|
dodag->trickle.k = dodag->dio_redun;
|
|
|
|
break;
|
2015-08-19 20:57:28 +02:00
|
|
|
|
|
|
|
case (GNRC_RPL_OPT_PREFIX_INFO):
|
2015-07-23 13:23:42 +02:00
|
|
|
DEBUG("RPL: Prefix Information DIO option parsed\n");
|
2015-08-25 11:03:28 +02:00
|
|
|
*included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PREFIX_INFO;
|
2016-02-03 08:37:59 +01:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_PIO
|
2016-03-15 15:17:46 +01:00
|
|
|
dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO;
|
2016-02-03 08:37:59 +01:00
|
|
|
#endif
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_opt_prefix_info_t *pi = (gnrc_rpl_opt_prefix_info_t *) opt;
|
2015-07-23 13:23:42 +02:00
|
|
|
/* check for the auto address-configuration flag */
|
2017-11-16 18:06:46 +01:00
|
|
|
gnrc_netif_t *netif = gnrc_netif_get_by_pid(dodag->iface);
|
2017-07-27 15:26:49 +02:00
|
|
|
|
|
|
|
assert(netif != NULL);
|
2017-11-16 18:06:46 +01:00
|
|
|
if ((gnrc_netif_ipv6_get_iid(netif, &iid) < 0)
|
|
|
|
&& !(pi->LAR_flags & GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT)) {
|
2015-07-23 13:23:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ipv6_addr_set_aiid(&pi->prefix, iid.uint8);
|
2017-11-23 17:12:43 +01:00
|
|
|
/* TODO: find a way to do this with DAD (i.e. state != VALID) */
|
2017-12-13 13:40:40 +01:00
|
|
|
gnrc_netif_ipv6_addr_add_internal(netif, &pi->prefix, pi->prefix_len,
|
|
|
|
GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID);
|
2017-11-23 17:12:43 +01:00
|
|
|
/* set lifetimes */
|
2017-11-23 17:12:00 +01:00
|
|
|
gnrc_ipv6_nib_pl_set(netif->pid, &pi->prefix, pi->prefix_len,
|
2017-11-24 11:38:40 +01:00
|
|
|
_sec_to_ms(byteorder_ntohl(pi->valid_lifetime)),
|
|
|
|
_sec_to_ms(byteorder_ntohl(pi->pref_lifetime)));
|
2015-07-23 13:23:42 +02:00
|
|
|
|
|
|
|
break;
|
2015-08-19 20:57:28 +02:00
|
|
|
|
|
|
|
case (GNRC_RPL_OPT_TARGET):
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: RPL TARGET DAO option parsed\n");
|
2015-08-25 11:03:28 +02:00
|
|
|
*included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_TARGET;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_opt_target_t *target = (gnrc_rpl_opt_target_t *) opt;
|
2015-05-22 21:47:37 +02:00
|
|
|
if (first_target == NULL) {
|
|
|
|
first_target = target;
|
|
|
|
}
|
|
|
|
|
2017-11-11 21:28:52 +01:00
|
|
|
DEBUG("RPL: adding FT entry %s/%d 0x%" PRIx32 "\n",
|
2016-01-21 03:11:38 +01:00
|
|
|
ipv6_addr_to_str(addr_str, &(target->target), sizeof(addr_str)),
|
2017-11-11 21:28:52 +01:00
|
|
|
target->prefix_length);
|
|
|
|
|
|
|
|
gnrc_ipv6_nib_ft_add(&(target->target), target->prefix_length, src,
|
|
|
|
dodag->iface,
|
|
|
|
dodag->default_lifetime * dodag->lifetime_unit);
|
2015-05-22 21:47:37 +02:00
|
|
|
break;
|
2015-08-19 20:57:28 +02:00
|
|
|
|
|
|
|
case (GNRC_RPL_OPT_TRANSIT):
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n");
|
2015-08-25 11:03:28 +02:00
|
|
|
*included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_TRANSIT;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_opt_transit_t *transit = (gnrc_rpl_opt_transit_t *) opt;
|
2015-05-22 21:47:37 +02:00
|
|
|
if (first_target == NULL) {
|
2016-03-22 10:17:32 +01:00
|
|
|
DEBUG("RPL: Encountered a RPL TRANSIT DAO option without "
|
|
|
|
"a preceding RPL TARGET DAO option\n");
|
2015-05-22 21:47:37 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2017-11-11 21:28:52 +01:00
|
|
|
DEBUG("RPL: updating FT entry %s/%d\n",
|
2016-01-21 03:11:38 +01:00
|
|
|
ipv6_addr_to_str(addr_str, &(first_target->target), sizeof(addr_str)),
|
|
|
|
first_target->prefix_length);
|
|
|
|
|
2017-11-11 21:28:52 +01:00
|
|
|
gnrc_ipv6_nib_ft_add(&(first_target->target),
|
|
|
|
first_target->prefix_length, src,
|
|
|
|
dodag->iface,
|
|
|
|
transit->path_lifetime * dodag->lifetime_unit);
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
first_target = (gnrc_rpl_opt_target_t *) (((uint8_t *) (first_target)) +
|
2015-08-27 22:29:08 +02:00
|
|
|
sizeof(gnrc_rpl_opt_t) + first_target->length);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
2015-08-17 15:41:29 +02:00
|
|
|
while (first_target->type == GNRC_RPL_OPT_TARGET);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
|
|
|
first_target = NULL;
|
|
|
|
break;
|
2015-08-19 20:57:28 +02:00
|
|
|
|
2015-08-23 14:25:39 +02:00
|
|
|
#ifdef MODULE_GNRC_RPL_P2P
|
|
|
|
case (GNRC_RPL_P2P_OPT_RDO):
|
|
|
|
gnrc_rpl_p2p_rdo_parse((gnrc_rpl_p2p_opt_rdo_t *) opt, gnrc_rpl_p2p_ext_get(dodag));
|
|
|
|
break;
|
|
|
|
#endif
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
2015-08-17 15:41:29 +02:00
|
|
|
l += opt->length + sizeof(gnrc_rpl_opt_t);
|
|
|
|
opt = (gnrc_rpl_opt_t *) (((uint8_t *) (opt + 1)) + opt->length);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst,
|
|
|
|
uint16_t len)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2016-06-01 14:04:28 +02:00
|
|
|
(void) dst;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_instance_t *inst = NULL;
|
|
|
|
gnrc_rpl_dodag_t *dodag = NULL;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_rx_DIO(&gnrc_rpl_netstats, len, (dst && !ipv6_addr_is_multicast(dst)));
|
|
|
|
#endif
|
|
|
|
|
2016-04-12 11:33:52 +02:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_VALIDATION
|
|
|
|
if (!gnrc_rpl_validation_DIO(dio, len)) {
|
2015-08-19 19:53:09 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-04-12 11:33:52 +02:00
|
|
|
#endif
|
2015-08-19 19:53:09 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
len -= (sizeof(gnrc_rpl_dio_t) + sizeof(icmpv6_hdr_t));
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if (gnrc_rpl_instance_add(dio->instance_id, &inst)) {
|
2015-08-27 22:29:08 +02:00
|
|
|
/* new instance and DODAG */
|
2017-11-23 17:12:43 +01:00
|
|
|
gnrc_netif_t *netif;
|
2015-08-27 22:29:08 +02:00
|
|
|
|
|
|
|
if (byteorder_ntohs(dio->rank) == GNRC_RPL_INFINITE_RANK) {
|
|
|
|
DEBUG("RPL: ignore INFINITE_RANK DIO when we are not yet part of this DODAG\n");
|
|
|
|
gnrc_rpl_instance_remove(inst);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
inst->mop = (dio->g_mop_prf >> GNRC_RPL_MOP_SHIFT) & GNRC_RPL_SHIFTED_MOP_MASK;
|
|
|
|
inst->of = gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP);
|
2016-03-22 14:58:23 +01:00
|
|
|
|
|
|
|
if (iface == KERNEL_PID_UNDEF) {
|
2017-11-23 17:12:43 +01:00
|
|
|
netif = _find_interface_with_rpl_mcast();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
netif = gnrc_netif_get_by_pid(iface);
|
2016-03-22 14:58:23 +01:00
|
|
|
}
|
2017-11-23 17:12:43 +01:00
|
|
|
assert(netif != NULL);
|
2016-03-22 14:58:23 +01:00
|
|
|
|
2017-11-23 17:12:43 +01:00
|
|
|
gnrc_rpl_dodag_init(inst, &dio->dodag_id, netif->pid);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
dodag = &inst->dodag;
|
|
|
|
|
|
|
|
DEBUG("RPL: Joined DODAG (%s).\n",
|
2016-03-22 17:35:14 +01:00
|
|
|
ipv6_addr_to_str(addr_str, &dio->dodag_id, sizeof(addr_str)));
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_parent_t *parent = NULL;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if (!gnrc_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Could not allocate new parent.\n");
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_instance_remove(inst);
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dodag->version = dio->version_number;
|
2015-08-27 22:29:08 +02:00
|
|
|
dodag->grounded = dio->g_mop_prf >> GNRC_RPL_GROUNDED_SHIFT;
|
|
|
|
dodag->prf = dio->g_mop_prf & GNRC_RPL_PRF_MASK;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
|
|
|
parent->rank = byteorder_ntohs(dio->rank);
|
|
|
|
|
2015-08-25 11:03:28 +02:00
|
|
|
uint32_t included_opts = 0;
|
2015-08-27 22:29:08 +02:00
|
|
|
if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, inst, (gnrc_rpl_opt_t *)(dio + 1), len,
|
2016-03-22 10:17:32 +01:00
|
|
|
src, &included_opts)) {
|
2015-08-18 21:13:53 +02:00
|
|
|
DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n");
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_instance_remove(inst);
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-25 11:03:28 +02:00
|
|
|
if (!(included_opts & (((uint32_t) 1) << GNRC_RPL_OPT_DODAG_CONF))) {
|
2016-03-15 16:34:06 +01:00
|
|
|
#ifndef GNRC_RPL_DODAG_CONF_OPTIONAL_ON_JOIN
|
2015-08-25 11:03:28 +02:00
|
|
|
DEBUG("RPL: DIO without DODAG_CONF option - remove DODAG and request new DIO\n");
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_instance_remove(inst);
|
2015-08-25 11:03:28 +02:00
|
|
|
gnrc_rpl_send_DIS(NULL, src);
|
|
|
|
return;
|
2016-03-15 16:34:06 +01:00
|
|
|
#else
|
|
|
|
DEBUG("RPL: DIO without DODAG_CONF option - use default trickle parameters\n");
|
|
|
|
gnrc_rpl_send_DIS(NULL, src);
|
|
|
|
#endif
|
2015-08-25 11:03:28 +02:00
|
|
|
}
|
|
|
|
|
2017-11-23 17:12:43 +01:00
|
|
|
/* if there was no address created manually or by a PIO on the interface,
|
|
|
|
* leave this DODAG */
|
|
|
|
if (gnrc_netif_ipv6_addr_match(netif, &dodag->dodag_id) < 0) {
|
|
|
|
DEBUG("RPL: no IPv6 address configured on interface %i to match the "
|
|
|
|
"given dodag id: %s\n", netif->pid,
|
|
|
|
ipv6_addr_to_str(addr_str, &(dodag->dodag_id), sizeof(addr_str)));
|
|
|
|
gnrc_rpl_instance_remove(inst);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-22 17:35:14 +01:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_delay_dao(dodag);
|
2017-06-08 21:39:33 +02:00
|
|
|
trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_MSG,
|
|
|
|
(1 << dodag->dio_min), dodag->dio_interval_doubl,
|
|
|
|
dodag->dio_redun);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_parent_update(dodag, parent);
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-08-27 22:29:08 +02:00
|
|
|
else if (inst == NULL) {
|
|
|
|
DEBUG("RPL: Could not allocate a new instance.\n");
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-08-27 22:29:08 +02:00
|
|
|
else {
|
|
|
|
/* instance exists already */
|
|
|
|
/* ignore dodags with other dodag_id's for now */
|
|
|
|
/* TODO: choose DODAG with better rank */
|
|
|
|
|
|
|
|
dodag = &inst->dodag;
|
|
|
|
|
|
|
|
if (memcmp(&dodag->dodag_id, &dio->dodag_id, sizeof(ipv6_addr_t)) != 0) {
|
|
|
|
DEBUG("RPL: DIO received from another DODAG, but same instance - ignore\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
if (inst->mop != ((dio->g_mop_prf >> GNRC_RPL_MOP_SHIFT) & GNRC_RPL_SHIFTED_MOP_MASK)) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: invalid MOP for this instance.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-23 14:25:39 +02:00
|
|
|
#ifdef MODULE_GNRC_RPL_P2P
|
|
|
|
gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag);
|
|
|
|
if ((dodag->instance->mop == GNRC_RPL_P2P_MOP) && (p2p_ext->lifetime_sec <= 0)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if (GNRC_RPL_COUNTER_GREATER_THAN(dio->version_number, dodag->version)) {
|
|
|
|
if (dodag->node_status == GNRC_RPL_ROOT_NODE) {
|
|
|
|
dodag->version = GNRC_RPL_COUNTER_INCREMENT(dio->version_number);
|
2015-05-22 21:47:37 +02:00
|
|
|
trickle_reset_timer(&dodag->trickle);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dodag->version = dio->version_number;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_local_repair(dodag);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
}
|
2015-08-17 15:41:29 +02:00
|
|
|
else if (GNRC_RPL_COUNTER_GREATER_THAN(dodag->version, dio->version_number)) {
|
2015-05-22 21:47:37 +02:00
|
|
|
trickle_reset_timer(&dodag->trickle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if (dodag->node_status == GNRC_RPL_ROOT_NODE) {
|
|
|
|
if (byteorder_ntohs(dio->rank) != GNRC_RPL_INFINITE_RANK) {
|
2015-05-22 21:47:37 +02:00
|
|
|
trickle_increment_counter(&dodag->trickle);
|
|
|
|
}
|
2015-08-21 13:36:37 +02:00
|
|
|
else {
|
|
|
|
trickle_reset_timer(&dodag->trickle);
|
|
|
|
}
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_parent_t *parent = NULL;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if (!gnrc_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Could not allocate new parent.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (parent != NULL) {
|
|
|
|
trickle_increment_counter(&dodag->trickle);
|
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
/* gnrc_rpl_parent_add_by_addr should have set this already */
|
2015-08-18 17:53:11 +02:00
|
|
|
assert(parent != NULL);
|
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
parent->rank = byteorder_ntohs(dio->rank);
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_parent_update(dodag, parent);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-21 13:36:37 +02:00
|
|
|
/* sender of incoming DIO is not a parent of mine (anymore) and has an INFINITE rank
|
|
|
|
and I have a rank != INFINITE_RANK */
|
|
|
|
if (parent->state == 0) {
|
|
|
|
if ((byteorder_ntohs(dio->rank) == GNRC_RPL_INFINITE_RANK)
|
|
|
|
&& (dodag->my_rank != GNRC_RPL_INFINITE_RANK)) {
|
|
|
|
trickle_reset_timer(&dodag->trickle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-08-21 12:43:41 +02:00
|
|
|
/* incoming DIO is from pref. parent */
|
2015-08-21 13:36:37 +02:00
|
|
|
else if (parent == dodag->parents) {
|
2015-08-21 12:43:41 +02:00
|
|
|
if (parent->dtsn != dio->dtsn) {
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_delay_dao(dodag);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
parent->dtsn = dio->dtsn;
|
2015-08-21 12:43:41 +02:00
|
|
|
dodag->grounded = dio->g_mop_prf >> GNRC_RPL_GROUNDED_SHIFT;
|
|
|
|
dodag->prf = dio->g_mop_prf & GNRC_RPL_PRF_MASK;
|
2015-08-25 11:03:28 +02:00
|
|
|
uint32_t included_opts = 0;
|
2015-08-27 22:29:08 +02:00
|
|
|
if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, inst, (gnrc_rpl_opt_t *)(dio + 1), len,
|
2016-03-22 10:17:32 +01:00
|
|
|
src, &included_opts)) {
|
2015-08-21 12:43:41 +02:00
|
|
|
DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n");
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_instance_remove(inst);
|
2015-08-21 12:43:41 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-21 03:11:38 +01:00
|
|
|
gnrc_pktsnip_t *_dao_target_build(gnrc_pktsnip_t *pkt, ipv6_addr_t *addr, uint8_t prefix_length)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2015-10-01 16:30:06 +02:00
|
|
|
gnrc_rpl_opt_target_t *target;
|
|
|
|
gnrc_pktsnip_t *opt_snip;
|
|
|
|
if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_opt_target_t),
|
|
|
|
GNRC_NETTYPE_UNDEF)) == NULL) {
|
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
target = opt_snip->data;
|
2015-08-17 15:41:29 +02:00
|
|
|
target->type = GNRC_RPL_OPT_TARGET;
|
2015-05-22 21:47:37 +02:00
|
|
|
target->length = sizeof(target->flags) + sizeof(target->prefix_length) + sizeof(target->target);
|
|
|
|
target->flags = 0;
|
2016-01-21 03:11:38 +01:00
|
|
|
target->prefix_length = prefix_length;
|
2015-05-22 21:47:37 +02:00
|
|
|
target->target = *addr;
|
2015-10-01 16:30:06 +02:00
|
|
|
return opt_snip;
|
|
|
|
}
|
|
|
|
|
2015-11-17 10:53:53 +01:00
|
|
|
gnrc_pktsnip_t *_dao_transit_build(gnrc_pktsnip_t *pkt, uint8_t lifetime, bool external)
|
2015-10-01 16:30:06 +02:00
|
|
|
{
|
|
|
|
gnrc_rpl_opt_transit_t *transit;
|
|
|
|
gnrc_pktsnip_t *opt_snip;
|
|
|
|
if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_opt_transit_t),
|
|
|
|
GNRC_NETTYPE_UNDEF)) == NULL) {
|
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
transit = opt_snip->data;
|
|
|
|
transit->type = GNRC_RPL_OPT_TRANSIT;
|
|
|
|
transit->length = sizeof(transit->e_flags) + sizeof(transit->path_control) +
|
|
|
|
sizeof(transit->path_sequence) + sizeof(transit->path_lifetime);
|
2015-11-17 10:53:53 +01:00
|
|
|
transit->e_flags = (external) << GNRC_RPL_OPT_TRANSIT_E_FLAG_SHIFT;
|
2015-10-01 16:30:06 +02:00
|
|
|
transit->path_control = 0;
|
|
|
|
transit->path_sequence = 0;
|
|
|
|
transit->path_lifetime = lifetime;
|
|
|
|
return opt_snip;
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
void gnrc_rpl_send_DAO(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination, uint8_t lifetime)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_dodag_t *dodag;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
if (inst == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Error - trying to send DAO without being part of a dodag.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
dodag = &inst->dodag;
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if (dodag->node_status == GNRC_RPL_ROOT_NODE) {
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-23 14:25:39 +02:00
|
|
|
#ifdef MODULE_GNRC_RPL_P2P
|
|
|
|
if (dodag->instance->mop == GNRC_RPL_P2P_MOP) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
if (destination == NULL) {
|
|
|
|
if (dodag->parents == NULL) {
|
|
|
|
DEBUG("RPL: dodag has no preferred parent\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
destination = &(dodag->parents->addr);
|
|
|
|
}
|
|
|
|
|
2017-11-11 21:28:52 +01:00
|
|
|
gnrc_pktsnip_t *pkt = NULL, *tmp = NULL;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_dao_t *dao;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
|
|
|
/* find my address */
|
|
|
|
ipv6_addr_t *me = NULL;
|
2017-11-11 21:28:52 +01:00
|
|
|
gnrc_netif_t *netif = gnrc_netif_get_by_prefix(&dodag->dodag_id);
|
2017-07-27 15:26:49 +02:00
|
|
|
int idx;
|
|
|
|
|
|
|
|
if (netif == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: no address configured\n");
|
|
|
|
return;
|
|
|
|
}
|
2017-11-11 21:28:52 +01:00
|
|
|
idx = gnrc_netif_ipv6_addr_match(netif, &dodag->dodag_id);
|
2017-07-27 15:26:49 +02:00
|
|
|
me = &netif->ipv6.addrs[idx];
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2017-11-11 21:28:52 +01:00
|
|
|
/* add external and RPL FT entries */
|
|
|
|
/* TODO: nib: dropped support for external transit options for now */
|
|
|
|
void *ft_state = NULL;
|
|
|
|
gnrc_ipv6_nib_ft_t fte;
|
|
|
|
while(gnrc_ipv6_nib_ft_iter(NULL, dodag->iface, &ft_state, &fte)) {
|
|
|
|
DEBUG("RPL: Send DAO - building transit option\n");
|
|
|
|
|
2017-11-23 17:03:02 +01:00
|
|
|
if ((pkt = _dao_transit_build(pkt, lifetime, false)) == NULL) {
|
2017-11-11 21:28:52 +01:00
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
|
|
|
return;
|
2015-11-17 10:53:53 +01:00
|
|
|
}
|
2017-11-23 19:29:00 +01:00
|
|
|
if (ipv6_addr_is_global(&fte.dst) &&
|
|
|
|
!ipv6_addr_is_unspecified(&fte.next_hop)) {
|
2017-11-11 21:28:52 +01:00
|
|
|
DEBUG("RPL: Send DAO - building target %s/%d\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &fte.dst, sizeof(addr_str)), fte.dst_len);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2017-11-11 21:28:52 +01:00
|
|
|
if ((pkt = _dao_target_build(pkt, &fte.dst, fte.dst_len)) == NULL) {
|
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-10-01 16:30:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add own address */
|
2016-01-21 03:11:38 +01:00
|
|
|
DEBUG("RPL: Send DAO - building target %s/128\n",
|
|
|
|
ipv6_addr_to_str(addr_str, me, sizeof(addr_str)));
|
|
|
|
if ((pkt = _dao_target_build(pkt, me, IPV6_ADDR_BIT_LEN)) == NULL) {
|
2015-10-01 16:30:06 +02:00
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
bool local_instance = (inst->id & GNRC_RPL_INSTANCE_ID_MSB) ? true : false;
|
2015-08-18 21:13:53 +02:00
|
|
|
|
|
|
|
if (local_instance) {
|
2015-10-01 16:30:06 +02:00
|
|
|
if ((tmp = gnrc_pktbuf_add(pkt, &dodag->dodag_id, sizeof(ipv6_addr_t),
|
|
|
|
GNRC_NETTYPE_UNDEF)) == NULL) {
|
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pkt = tmp;
|
2015-08-18 21:13:53 +02:00
|
|
|
}
|
|
|
|
|
2015-10-01 16:30:06 +02:00
|
|
|
if ((tmp = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_dao_t), GNRC_NETTYPE_UNDEF)) == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
2015-10-01 16:30:06 +02:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-10-01 16:30:06 +02:00
|
|
|
pkt = tmp;
|
|
|
|
dao = pkt->data;
|
2015-08-27 22:29:08 +02:00
|
|
|
dao->instance_id = inst->id;
|
2015-08-18 21:13:53 +02:00
|
|
|
if (local_instance) {
|
|
|
|
/* set the D flag to indicate that a DODAG id is present */
|
|
|
|
dao->k_d_flags = GNRC_RPL_DAO_D_BIT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dao->k_d_flags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the K flag to indicate that ACKs are required */
|
|
|
|
dao->k_d_flags |= GNRC_RPL_DAO_K_BIT;
|
2015-05-22 21:47:37 +02:00
|
|
|
dao->dao_sequence = dodag->dao_seq;
|
|
|
|
dao->reserved = 0;
|
|
|
|
|
2015-10-01 16:30:06 +02:00
|
|
|
if ((tmp = gnrc_icmpv6_build(pkt, ICMPV6_RPL_CTRL, GNRC_RPL_ICMPV6_CODE_DAO,
|
|
|
|
sizeof(icmpv6_hdr_t))) == NULL) {
|
|
|
|
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
|
2015-11-01 20:51:09 +01:00
|
|
|
gnrc_pktbuf_release(pkt);
|
2015-10-01 16:30:06 +02:00
|
|
|
return;
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
2015-10-01 16:30:06 +02:00
|
|
|
pkt = tmp;
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_tx_DAO(&gnrc_rpl_netstats, gnrc_pkt_len(pkt),
|
|
|
|
(destination && !ipv6_addr_is_multicast(destination)));
|
|
|
|
#endif
|
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
gnrc_rpl_send(pkt, dodag->iface, NULL, destination, &dodag->dodag_id);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
GNRC_RPL_COUNTER_INCREMENT(dodag->dao_seq);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
void gnrc_rpl_send_DAO_ACK(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination, uint8_t seq)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_dodag_t *dodag = NULL;
|
|
|
|
|
|
|
|
if (inst == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Error - trying to send DAO-ACK without being part of a dodag.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
dodag = &inst->dodag;
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_pktsnip_t *pkt;
|
2015-08-10 13:22:24 +02:00
|
|
|
icmpv6_hdr_t *icmp;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_dao_ack_t *dao_ack;
|
|
|
|
int size = sizeof(icmpv6_hdr_t) + sizeof(gnrc_rpl_dao_ack_t);
|
2015-08-27 22:29:08 +02:00
|
|
|
bool local_instance = (inst->id & GNRC_RPL_INSTANCE_ID_MSB) ? true : false;
|
2015-08-18 21:13:53 +02:00
|
|
|
|
|
|
|
if (local_instance) {
|
|
|
|
size += sizeof(ipv6_addr_t);
|
|
|
|
}
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if ((pkt = gnrc_icmpv6_build(NULL, ICMPV6_RPL_CTRL, GNRC_RPL_ICMPV6_CODE_DAO_ACK, size)) == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: Send DAOACK - no space left in packet buffer\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-10 13:22:24 +02:00
|
|
|
icmp = (icmpv6_hdr_t *)pkt->data;
|
2015-08-17 15:41:29 +02:00
|
|
|
dao_ack = (gnrc_rpl_dao_ack_t *)(icmp + 1);
|
2015-05-22 21:47:37 +02:00
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
dao_ack->instance_id = inst->id;
|
2015-08-18 21:13:53 +02:00
|
|
|
if (local_instance) {
|
|
|
|
/* set the D flag to indicate that a DODAG id is present */
|
|
|
|
dao_ack->d_reserved = GNRC_RPL_DAO_ACK_D_BIT;
|
|
|
|
memcpy((dao_ack + 1), &dodag->dodag_id, sizeof(ipv6_addr_t));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dao_ack->d_reserved = 0;
|
|
|
|
}
|
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
dao_ack->dao_sequence = seq;
|
|
|
|
dao_ack->status = 0;
|
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_tx_DAO_ACK(&gnrc_rpl_netstats, gnrc_pkt_len(pkt),
|
|
|
|
(destination && !ipv6_addr_is_multicast(destination)));
|
|
|
|
#endif
|
|
|
|
|
2016-03-22 14:58:23 +01:00
|
|
|
gnrc_rpl_send(pkt, dodag->iface, NULL, destination, &dodag->dodag_id);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
void gnrc_rpl_recv_DAO(gnrc_rpl_dao_t *dao, kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst,
|
|
|
|
uint16_t len)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2016-03-22 14:58:23 +01:00
|
|
|
(void)iface;
|
2016-06-01 14:04:28 +02:00
|
|
|
(void)dst;
|
|
|
|
|
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_rx_DAO(&gnrc_rpl_netstats, len, (dst && !ipv6_addr_is_multicast(dst)));
|
|
|
|
#endif
|
2016-03-22 14:58:23 +01:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_instance_t *inst = NULL;
|
|
|
|
gnrc_rpl_dodag_t *dodag = NULL;
|
2015-08-19 19:18:15 +02:00
|
|
|
|
2016-04-12 11:33:52 +02:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_VALIDATION
|
|
|
|
if (!gnrc_rpl_validation_DAO(dao, len)) {
|
2015-08-19 19:18:15 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-04-12 11:33:52 +02:00
|
|
|
#endif
|
2015-08-19 19:18:15 +02:00
|
|
|
|
2015-08-18 21:13:53 +02:00
|
|
|
gnrc_rpl_opt_t *opts = (gnrc_rpl_opt_t *) (dao + 1);
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if ((inst = gnrc_rpl_instance_get(dao->instance_id)) == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: DAO with unknown instance id (%d) received\n", dao->instance_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
dodag = &inst->dodag;
|
|
|
|
|
2015-08-18 21:13:53 +02:00
|
|
|
len -= (sizeof(gnrc_rpl_dao_t) + sizeof(icmpv6_hdr_t));
|
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
/* check if the D flag is set before accessing the DODAG id */
|
2015-08-18 21:13:53 +02:00
|
|
|
if ((dao->k_d_flags & GNRC_RPL_DAO_D_BIT)) {
|
2015-08-27 22:29:08 +02:00
|
|
|
if (memcmp(&dodag->dodag_id, (ipv6_addr_t *)(dao + 1), sizeof(ipv6_addr_t)) != 0) {
|
2015-08-18 21:13:53 +02:00
|
|
|
DEBUG("RPL: DAO with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
|
|
|
|
(ipv6_addr_t *)(dao + 1), sizeof(addr_str)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
opts = (gnrc_rpl_opt_t *)(((uint8_t *) opts) + sizeof(ipv6_addr_t));
|
|
|
|
len -= sizeof(ipv6_addr_t);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2015-08-22 09:19:27 +02:00
|
|
|
/* a leaf node should not parse DAOs */
|
|
|
|
if (dodag->node_status == GNRC_RPL_LEAF_NODE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-23 14:25:39 +02:00
|
|
|
#ifdef MODULE_GNRC_RPL_P2P
|
|
|
|
if (dodag->instance->mop == GNRC_RPL_P2P_MOP) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-25 11:03:28 +02:00
|
|
|
uint32_t included_opts = 0;
|
2015-08-27 22:29:08 +02:00
|
|
|
if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DAO, inst, opts, len, src, &included_opts)) {
|
2015-08-19 20:57:28 +02:00
|
|
|
DEBUG("RPL: Error encountered during DAO option parsing - ignore DAO\n");
|
2015-05-22 21:47:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* send a DAO-ACK if K flag is set */
|
2015-08-18 21:13:53 +02:00
|
|
|
if (dao->k_d_flags & GNRC_RPL_DAO_K_BIT) {
|
2015-08-27 22:29:08 +02:00
|
|
|
gnrc_rpl_send_DAO_ACK(inst, src, dao->dao_sequence);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_delay_dao(dodag);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
void gnrc_rpl_recv_DAO_ACK(gnrc_rpl_dao_ack_t *dao_ack, kernel_pid_t iface, ipv6_addr_t *src,
|
|
|
|
ipv6_addr_t *dst, uint16_t len)
|
2015-05-22 21:47:37 +02:00
|
|
|
{
|
2016-03-22 14:58:23 +01:00
|
|
|
(void)iface;
|
2016-06-01 14:04:28 +02:00
|
|
|
(void)src;
|
|
|
|
(void)dst;
|
2017-04-13 16:06:37 +02:00
|
|
|
(void)len;
|
2016-03-22 14:58:23 +01:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_instance_t *inst = NULL;
|
|
|
|
gnrc_rpl_dodag_t *dodag = NULL;
|
2015-08-19 19:29:17 +02:00
|
|
|
|
2016-06-01 14:04:28 +02:00
|
|
|
#ifdef MODULE_NETSTATS_RPL
|
|
|
|
gnrc_rpl_netstats_rx_DAO_ACK(&gnrc_rpl_netstats, len, (dst && !ipv6_addr_is_multicast(dst)));
|
|
|
|
#endif
|
|
|
|
|
2016-04-12 11:33:52 +02:00
|
|
|
#ifndef GNRC_RPL_WITHOUT_VALIDATION
|
2017-04-13 16:06:37 +02:00
|
|
|
if (!gnrc_rpl_validation_DAO_ACK(dao_ack, len, dst)) {
|
2015-08-19 19:29:17 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-04-12 11:33:52 +02:00
|
|
|
#endif
|
2015-08-19 19:29:17 +02:00
|
|
|
|
2015-08-17 15:41:29 +02:00
|
|
|
if ((inst = gnrc_rpl_instance_get(dao_ack->instance_id)) == NULL) {
|
2015-05-22 21:47:37 +02:00
|
|
|
DEBUG("RPL: DAO-ACK with unknown instance id (%d) received\n", dao_ack->instance_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-27 22:29:08 +02:00
|
|
|
dodag = &inst->dodag;
|
|
|
|
|
2015-05-22 21:47:37 +02:00
|
|
|
/* check if the D flag is set before accessing the DODAG id */
|
2015-08-18 21:13:53 +02:00
|
|
|
if ((dao_ack->d_reserved & GNRC_RPL_DAO_ACK_D_BIT)) {
|
2015-08-27 22:29:08 +02:00
|
|
|
if (memcmp(&dodag->dodag_id, (ipv6_addr_t *)(dao_ack + 1), sizeof(ipv6_addr_t)) != 0) {
|
2015-08-18 21:13:53 +02:00
|
|
|
DEBUG("RPL: DAO-ACK with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
|
2015-08-27 22:29:08 +02:00
|
|
|
(ipv6_addr_t *)(dao_ack + 1), sizeof(addr_str)));
|
2015-08-18 21:13:53 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((dao_ack->status != 0) && (dao_ack->dao_sequence != dodag->dao_seq)) {
|
|
|
|
DEBUG("RPL: DAO-ACK sequence (%d) does not match expected sequence (%d)\n",
|
|
|
|
dao_ack->dao_sequence, dodag->dao_seq);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dodag->dao_ack_received = true;
|
2015-08-17 15:41:29 +02:00
|
|
|
gnrc_rpl_long_delay_dao(dodag);
|
2015-05-22 21:47:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
*/
|