diff --git a/pkg/nimble/contrib/nimble_riot.c b/pkg/nimble/contrib/nimble_riot.c index 3d7a457c9356..2f55100f4dee 100644 --- a/pkg/nimble/contrib/nimble_riot.c +++ b/pkg/nimble/contrib/nimble_riot.c @@ -23,6 +23,7 @@ #include "thread.h" #include "nimble_riot.h" +#include "net/ipv6/addr.h" #include "nimble/nimble_port.h" #include "host/ble_hs.h" #include "host/util/util.h" diff --git a/pkg/nimble/rpble/include/nimble_rpble.h b/pkg/nimble/rpble/include/nimble_rpble.h index d09c292ad503..f0a55637ccb8 100644 --- a/pkg/nimble/rpble/include/nimble_rpble.h +++ b/pkg/nimble/rpble/include/nimble_rpble.h @@ -129,6 +129,7 @@ typedef struct { uint8_t version; /**< DODAG version */ uint8_t role; /**< RPL role of the node */ uint16_t rank; /**< the node's rank in the DODAG */ + ipv6_addr_t parent_addr; /**< address of the node's preferred parent */ } nimble_rpble_ctx_t; /** diff --git a/pkg/nimble/rpble/nimble_rpble.c b/pkg/nimble/rpble/nimble_rpble.c index da56a56e6ef8..b4bccb6581ff 100644 --- a/pkg/nimble/rpble/nimble_rpble.c +++ b/pkg/nimble/rpble/nimble_rpble.c @@ -173,6 +173,7 @@ static void _on_scan_evt(uint8_t type, const ble_addr_t *addr, static void _parent_find(void) { _psel.score = SCORE_NONE; + _current_parent = PARENT_NONE; nimble_scanner_start(); ble_npl_callout_reset(&_evt_eval, _eval_itvl); } @@ -213,6 +214,18 @@ static void _parent_connect(struct ble_npl_event *ev) _current_parent = res; } +static void _parent_lost(void) +{ + nimble_netif_accept_stop(); + + if (_local_rpl_ctx.rank != 0) { + gnrc_rpl_addr_unreachable(&_local_rpl_ctx.parent_addr); + } + + /* back to 0, now we need to find a new parent... */ + _parent_find(); +} + static void _on_netif_evt(int handle, nimble_netif_event_t event, const uint8_t *addr) { @@ -232,20 +245,14 @@ static void _on_netif_evt(int handle, nimble_netif_event_t event, break; case NIMBLE_NETIF_CLOSED_MASTER: /* parent lost */ - nimble_netif_accept_stop(); - _current_parent = PARENT_NONE; - /* back to 0, now we need to find a new parent... */ - _parent_find(); - break; + _parent_lost(); case NIMBLE_NETIF_CLOSED_SLAVE: /* child lost */ _children_accept(); break; case NIMBLE_NETIF_ABORT_MASTER: /* parent selection aborted */ - nimble_netif_accept_stop(); - _current_parent = PARENT_NONE; - _parent_find(); + _parent_lost(); break; case NIMBLE_NETIF_ABORT_SLAVE: /* child selection aborted */ diff --git a/sys/include/net/gnrc/rpl.h b/sys/include/net/gnrc/rpl.h index bfba745e07fa..b6c891e37354 100644 --- a/sys/include/net/gnrc/rpl.h +++ b/sys/include/net/gnrc/rpl.h @@ -706,6 +706,16 @@ void gnrc_rpl_long_delay_dao(gnrc_rpl_dodag_t *dodag); gnrc_rpl_instance_t *gnrc_rpl_root_instance_init(uint8_t instance_id, const ipv6_addr_t *dodag_id, uint8_t mop); +/** + * @brief Mark an address as unreachable. + * + * @note Connection-oriented link-layers can use this to hint RPL + * that a parent with this address is unreachable. + * + * @param[in] addr Address that became unreachable. + */ +void gnrc_rpl_addr_unreachable(ipv6_addr_t *addr); + /** * @brief Send a control message * diff --git a/sys/include/net/gnrc/rpl/dodag.h b/sys/include/net/gnrc/rpl/dodag.h index 69a209fbd767..4e5934d8cd3a 100644 --- a/sys/include/net/gnrc/rpl/dodag.h +++ b/sys/include/net/gnrc/rpl/dodag.h @@ -129,6 +129,18 @@ void gnrc_rpl_dodag_remove_all_parents(gnrc_rpl_dodag_t *dodag); bool gnrc_rpl_parent_add_by_addr(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *addr, gnrc_rpl_parent_t **parent); +/** + * @brief Iterate over all parents in all DODAGs with IPv6 address @p addr. + * + * @param[in] idx Index to start searching from. + * @param[in] addr IPV6 address of the parent. + * @param[out] parent Pointer to the parent if one was found. Otherwise NULL. + * + * @return Index > 0 to continue next search from, if parent was found. + * @return -ENONENT if not found. + */ +int gnrc_rpl_parent_iter_by_addr(ipv6_addr_t *addr, gnrc_rpl_parent_t **parent, int idx); + /** * @brief Remove the @p parent from its DODAG. * diff --git a/sys/include/net/gnrc/rpl/rpble.h b/sys/include/net/gnrc/rpl/rpble.h index 1dcd7c07431a..10d0665e29cd 100644 --- a/sys/include/net/gnrc/rpl/rpble.h +++ b/sys/include/net/gnrc/rpl/rpble.h @@ -31,11 +31,18 @@ extern "C" { static inline void gnrc_rpl_rpble_update(const gnrc_rpl_dodag_t *dodag) { nimble_rpble_ctx_t ctx; + ctx.inst_id = dodag->instance->id; memcpy(ctx.dodag_id, &dodag->dodag_id, 16); ctx.version = dodag->version; ctx.rank = dodag->my_rank; ctx.role = dodag->node_status; + if (dodag->parents) { + ctx.parent_addr = dodag->parents->addr; + } + else { + memset(&ctx.parent_addr, 0, sizeof(ipv6_addr_t)); + } nimble_rpble_update(&ctx); } #else diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl.c b/sys/net/gnrc/routing/rpl/gnrc_rpl.c index 19e6b761c7d7..f9a38ec82c57 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl.c @@ -176,6 +176,14 @@ gnrc_rpl_instance_t *gnrc_rpl_root_init(uint8_t instance_id, const ipv6_addr_t * return inst; } +void gnrc_rpl_addr_unreachable(ipv6_addr_t *addr) +{ + msg_t msg; + msg.type = GNRC_RPL_MSG_TYPE_ADDR_UNREACHABLE; + msg.content.ptr = addr; + msg_send(&msg, gnrc_rpl_pid); +} + static void _receive(gnrc_pktsnip_t *icmpv6) { gnrc_pktsnip_t *ipv6, *netif; @@ -273,6 +281,16 @@ static void _parent_timeout(gnrc_rpl_parent_t *parent) evtimer_add_msg(&gnrc_rpl_evtimer, &parent->timeout_event, gnrc_rpl_pid); } +static void _addr_unreachable(ipv6_addr_t *addr) +{ + gnrc_rpl_parent_t *parent; + int idx = 0; + + while ((idx = gnrc_rpl_parent_iter_by_addr(addr, &parent, idx)) >= 0) { + _parent_timeout(parent); + } +} + static void *_event_loop(void *args) { msg_t msg, reply; @@ -293,6 +311,7 @@ static void *_event_loop(void *args) trickle_t *trickle; gnrc_rpl_parent_t *parent; gnrc_rpl_instance_t *instance; + ipv6_addr_t *addr; /* start event loop */ while (1) { @@ -311,6 +330,11 @@ static void *_event_loop(void *args) parent = msg.content.ptr; _parent_timeout(parent); break; + case GNRC_RPL_MSG_TYPE_ADDR_UNREACHABLE: + DEBUG("RPL: GNRC_RPL_MSG_TYPE_ADDR_UNREACHABLE received\n"); + addr = msg.content.ptr; + _addr_unreachable(addr); + break; case GNRC_RPL_MSG_TYPE_DODAG_DAO_TX: DEBUG("RPL: GNRC_RPL_MSG_TYPE_DODAG_DAO_TX received\n"); instance = msg.content.ptr; diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c index 8a0ead7fcbf3..1a06bcd25b85 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c @@ -196,6 +196,18 @@ void gnrc_rpl_dodag_remove_all_parents(gnrc_rpl_dodag_t *dodag) dodag->my_rank = GNRC_RPL_INFINITE_RANK; } +int gnrc_rpl_parent_iter_by_addr(ipv6_addr_t *addr, gnrc_rpl_parent_t **parent, int idx) +{ + *parent = NULL; + for (uint8_t i = idx; i < GNRC_RPL_PARENTS_NUMOF; ++i) { + if ((gnrc_rpl_parents[i].state != 0) && ipv6_addr_equal(&gnrc_rpl_parents[i].addr, addr)) { + *parent = &gnrc_rpl_parents[i]; + return i + 1; + } + } + return -ENOENT; +} + bool gnrc_rpl_parent_add_by_addr(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *addr, gnrc_rpl_parent_t **parent) { diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h b/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h index a9c6c8188926..b3f25a6eaffc 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h @@ -45,6 +45,10 @@ extern evtimer_msg_t gnrc_rpl_evtimer; * @brief Message type for DAO transmissions. */ #define GNRC_RPL_MSG_TYPE_DODAG_DAO_TX (0x0906) +/** + * @brief Message type for signaling an unreachable address. + */ +#define GNRC_RPL_MSG_TYPE_ADDR_UNREACHABLE (0x0907) /** @} */ /**