diff --git a/sys/include/net/gnrc/rpl/structs.h b/sys/include/net/gnrc/rpl/structs.h index b192163c2a..230371d601 100644 --- a/sys/include/net/gnrc/rpl/structs.h +++ b/sys/include/net/gnrc/rpl/structs.h @@ -27,6 +27,7 @@ extern "C" { #endif +#include "byteorder.h" #include "net/ipv6/addr.h" #include "xtimer.h" #include "trickle.h" @@ -189,14 +190,16 @@ typedef struct __attribute__((packed)) { * */ typedef struct __attribute__((packed)) { - uint8_t type; /**< option type */ - uint8_t length; /**< option length without the first two bytes */ - uint8_t prefix_len; /**< prefix length */ - uint8_t LAR_flags; /**< flags and resereved */ - uint32_t valid_lifetime; /**< valid lifetime */ - uint32_t pref_lifetime; /**< preferred lifetime */ - uint32_t reserved; /**< reserved */ - ipv6_addr_t prefix; /**< prefix used for Stateless Address Autoconfiguration */ + uint8_t type; /**< option type */ + uint8_t length; /**< option length without the first + * two bytes */ + uint8_t prefix_len; /**< prefix length */ + uint8_t LAR_flags; /**< flags and resereved */ + network_uint32_t valid_lifetime; /**< valid lifetime */ + network_uint32_t pref_lifetime; /**< preferred lifetime */ + uint32_t reserved; /**< reserved */ + ipv6_addr_t prefix; /**< prefix used for Stateless Address + * Autoconfiguration */ } gnrc_rpl_opt_prefix_info_t; /** diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c index 3230a58df0..4deea6a340 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c @@ -78,7 +78,7 @@ void gnrc_rpl_send(gnrc_pktsnip_t *pkt, kernel_pid_t iface, ipv6_addr_t *src, ip if (iface == KERNEL_PID_UNDEF) { netif = _find_interface_with_rpl_mcast(); - if (netif == KERNEL_PID_UNDEF) { + if (netif == NULL) { DEBUG("RPL: no suitable interface found for this destination address\n"); gnrc_pktbuf_release(pkt); return; @@ -150,10 +150,25 @@ gnrc_pktsnip_t *_dio_dodag_conf_build(gnrc_pktsnip_t *pkt, gnrc_rpl_dodag_t *dod } #ifndef GNRC_RPL_WITHOUT_PIO +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; +} + gnrc_pktsnip_t *_dio_prefix_info_build(gnrc_pktsnip_t *pkt, gnrc_rpl_dodag_t *dodag) { + gnrc_ipv6_nib_pl_t ple; gnrc_rpl_opt_prefix_info_t *prefix_info; gnrc_pktsnip_t *opt_snip; + 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"); @@ -165,10 +180,18 @@ gnrc_pktsnip_t *_dio_prefix_info_build(gnrc_pktsnip_t *pkt, gnrc_rpl_dodag_t *do prefix_info->length = GNRC_RPL_OPT_PREFIX_INFO_LEN; /* auto-address configuration */ prefix_info->LAR_flags = GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT; - /* TODO: Get real values from NIB_PL */ - prefix_info->valid_lifetime = UINT32_MAX; - prefix_info->pref_lifetime = UINT32_MAX; prefix_info->prefix_len = 64; + if (_get_pl_entry(dodag->iface, &dodag->dodag_id, prefix_info->prefix_len, + &ple)) { + uint32_t now = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX; + prefix_info->valid_lifetime = byteorder_htonl((ple.valid_until - now) / MS_PER_SEC); + prefix_info->pref_lifetime = byteorder_htonl((ple.pref_until - now) / MS_PER_SEC); + } + else { + DEBUG("RPL: Prefix of DODAG-ID not in prefix list\n"); + gnrc_pktbuf_release(pkt); + return NULL; + } prefix_info->reserved = 0; memset(&prefix_info->prefix, 0, sizeof(prefix_info->prefix)); @@ -403,9 +426,13 @@ bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt_t *opt break; } ipv6_addr_set_aiid(&pi->prefix, iid.uint8); + /* TODO: find a way to do this with DAD (i.e. state != VALID) */ gnrc_netif_ipv6_addr_add(netif, &pi->prefix, pi->prefix_len, GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID); - /* TODO: add to prefix list */ + /* set lifetimes */ + gnrc_ipv6_nib_pl_set(netif->pid, &pi->prefix, pi->prefix_len, + byteorder_ntohl(pi->valid_lifetime) * MS_PER_SEC, + byteorder_ntohl(pi->pref_lifetime) * MS_PER_SEC); break; @@ -488,6 +515,7 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, kernel_pid_t iface, ipv6_addr_t *src if (gnrc_rpl_instance_add(dio->instance_id, &inst)) { /* new instance and DODAG */ + gnrc_netif_t *netif; 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"); @@ -499,13 +527,14 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, kernel_pid_t iface, ipv6_addr_t *src inst->of = gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP); if (iface == KERNEL_PID_UNDEF) { - gnrc_netif_t *netif = _find_interface_with_rpl_mcast(); - - iface = netif->pid; - assert(iface != KERNEL_PID_UNDEF); + netif = _find_interface_with_rpl_mcast(); } + else { + netif = gnrc_netif_get_by_pid(iface); + } + assert(netif != NULL); - gnrc_rpl_dodag_init(inst, &dio->dodag_id, iface); + gnrc_rpl_dodag_init(inst, &dio->dodag_id, netif->pid); dodag = &inst->dodag; @@ -546,7 +575,15 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, kernel_pid_t iface, ipv6_addr_t *src #endif } - /* TODO: create prefix list entry */ + /* 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; + } gnrc_rpl_delay_dao(dodag); trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_MSG, diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c index 81dbfb8a8e..81197b16cb 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c @@ -131,8 +131,6 @@ gnrc_rpl_instance_t *gnrc_rpl_instance_get(uint8_t instance_id) bool gnrc_rpl_dodag_init(gnrc_rpl_instance_t *instance, ipv6_addr_t *dodag_id, kernel_pid_t iface) { - /* TODO: check if netif_addr belongs to iface */ - assert(instance && (instance->state > 0)); gnrc_rpl_dodag_t *dodag = &instance->dodag; @@ -342,7 +340,6 @@ gnrc_rpl_instance_t *gnrc_rpl_root_instance_init(uint8_t instance_id, ipv6_addr_ gnrc_netif_t *netif; gnrc_rpl_instance_t *inst = NULL; gnrc_rpl_dodag_t *dodag = NULL; - kernel_pid_t iface; if (!(ipv6_addr_is_global(dodag_id) || ipv6_addr_is_unique_local_unicast(dodag_id))) { DEBUG("RPL: dodag id (%s) must be a global or unique local IPv6 address\n", @@ -355,7 +352,6 @@ gnrc_rpl_instance_t *gnrc_rpl_root_instance_init(uint8_t instance_id, ipv6_addr_ ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str))); return NULL; } - iface = netif->pid; if (gnrc_rpl_instance_add(instance_id, &inst)) { inst->of = (gnrc_rpl_of_t *) gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP); @@ -372,7 +368,7 @@ gnrc_rpl_instance_t *gnrc_rpl_root_instance_init(uint8_t instance_id, ipv6_addr_ return NULL; } - if (!gnrc_rpl_dodag_init(inst, dodag_id, iface)) { + if (!gnrc_rpl_dodag_init(inst, dodag_id, netif->pid)) { DEBUG("RPL: could not initialize DODAG\n"); gnrc_rpl_instance_remove(inst); return NULL;