diff --git a/core/net/rpl/rpl-ext-header.c b/core/net/rpl/rpl-ext-header.c index 1e3250e20..a2392c124 100644 --- a/core/net/rpl/rpl-ext-header.c +++ b/core/net/rpl/rpl-ext-header.c @@ -73,6 +73,7 @@ rpl_verify_header(int uip_ext_opt_offset) uint16_t sender_rank; uint8_t sender_closer; uip_ds6_route_t *route; + rpl_parent_t *sender = NULL; if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) { PRINTF("RPL: Hop-by-hop extension header has wrong size\n"); @@ -132,10 +133,25 @@ rpl_verify_header(int uip_ext_opt_offset) instance->current_dag->rank ); + sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER)); + + if(sender != NULL && (UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR)) { + /* A rank error was signalled, attempt to repair it by updating + * the sender's rank from ext header */ + sender->rank = sender_rank; + rpl_select_dag(instance, sender); + } + if((down && !sender_closer) || (!down && sender_closer)) { PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n", sender_rank, instance->current_dag->rank, sender_closer); + /* Attempt to repair the loop by sending a unicast DIO back to the sender + * so that it gets a fresh update of our rank. */ + if(sender != NULL) { + instance->unicast_dio_target = sender; + rpl_schedule_unicast_dio_immediately(instance); + } if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) { RPL_STAT(rpl_stats.loop_errors++); PRINTF("RPL: Rank error signalled in RPL option!\n"); diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index d5ed5513f..e1d95697b 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.h @@ -309,6 +309,7 @@ rpl_of_t *rpl_find_of(rpl_ocp_t); /* Timer functions. */ void rpl_schedule_dao(rpl_instance_t *); void rpl_schedule_dao_immediately(rpl_instance_t *); +void rpl_schedule_unicast_dio_immediately(rpl_instance_t *instance); void rpl_cancel_dao(rpl_instance_t *instance); void rpl_schedule_probing(rpl_instance_t *instance); diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 8530a0f56..54cb3ddef 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -328,6 +328,24 @@ rpl_cancel_dao(rpl_instance_t *instance) ctimer_stop(&instance->dao_lifetime_timer); } /*---------------------------------------------------------------------------*/ +static void +handle_unicast_dio_timer(void *ptr) +{ + rpl_instance_t *instance = (rpl_instance_t *)ptr; + uip_ipaddr_t *target_ipaddr = rpl_get_parent_ipaddr(instance->unicast_dio_target); + + if(target_ipaddr != NULL) { + dio_output(instance, target_ipaddr); + } +} +/*---------------------------------------------------------------------------*/ +void +rpl_schedule_unicast_dio_immediately(rpl_instance_t *instance) +{ + ctimer_set(&instance->unicast_dio_timer, 0, + handle_unicast_dio_timer, instance); +} +/*---------------------------------------------------------------------------*/ #if RPL_WITH_PROBING static rpl_parent_t * get_probing_target(rpl_dag_t *dag) @@ -397,13 +415,15 @@ handle_probing_timer(void *ptr) { rpl_instance_t *instance = (rpl_instance_t *)ptr; rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(instance->current_dag); + uip_ipaddr_t *target_ipaddr = rpl_get_parent_ipaddr(probing_target); /* Perform probing */ - if(probing_target != NULL && rpl_get_parent_ipaddr(probing_target) != NULL) { - PRINTF("RPL: probing %3u\n", - nbr_table_get_lladdr(rpl_parents, probing_target)->u8[7]); - /* Send probe, e.g. unicast DIO or DIS */ - RPL_PROBING_SEND_FUNC(instance, rpl_get_parent_ipaddr(probing_target)); + if(target_ipaddr != NULL) { + PRINTF("RPL: probing %u ((last tx %u min ago))\n", + nbr_table_get_lladdr(rpl_parents, probing_target)->u8[7], + (unsigned)((clock_time() - probing_target->last_tx_time) / (60 * CLOCK_SECOND))); + /* Send probe (unicast DIO or DIS) */ + RPL_PROBING_SEND_FUNC(instance, target_ipaddr); } /* Schedule next probing */ diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index 3b3c99f9f..c3d693b26 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -231,6 +231,8 @@ struct rpl_instance { struct ctimer dio_timer; struct ctimer dao_timer; struct ctimer dao_lifetime_timer; + struct ctimer unicast_dio_timer; + rpl_parent_t *unicast_dio_target; }; /*---------------------------------------------------------------------------*/