diff --git a/core/net/rpl/rpl-ext-header.c b/core/net/rpl/rpl-ext-header.c index 96c709f71..2bd0cb77c 100644 --- a/core/net/rpl/rpl-ext-header.c +++ b/core/net/rpl/rpl-ext-header.c @@ -75,12 +75,6 @@ rpl_verify_header(int uip_ext_opt_offset) return 1; } - if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { - PRINTF("RPL: Forward error!\n"); - /* We should try to repair it, not implemented for the moment */ - return 2; - } - instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); if(instance == NULL) { PRINTF("RPL: Unknown instance: %u\n", @@ -88,6 +82,31 @@ rpl_verify_header(int uip_ext_opt_offset) return 1; } + if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { + PRINTF("RPL: Forward error!\n"); + /* We should try to repair it by removing the neighbor that caused + the packet to be forwareded in the first place. We drop any + routes that go through the neighbor that sent the packet to + us. */ + uip_ds6_route_t *route; + route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); + if(route != NULL) { + uip_ds6_route_rm(route); + + /* If we are the root and just needed to remove a DAO route, + chances are that the network needs to be repaired. The + rpl_repair_root() function will cause a global repair if we + happen to be the root node of the dag. */ + PRINTF("RPL: initiate global repair\n"); + rpl_repair_root(instance->instance_id); + } + + /* Remove the forwarding error flag and return 0 to let the packet + be forwarded again. */ + UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_FWD_ERR; + return 0; + } + if(!instance->current_dag->joined) { PRINTF("RPL: No DAG in the instance\n"); return 1; @@ -191,18 +210,29 @@ rpl_update_header_empty(void) PRINTF("RPL: Updating RPL option\n"); UIP_EXT_HDR_OPT_RPL_BUF->senderrank = instance->current_dag->rank; - - /* Set the down extension flag correctly as described in Section - 11.2 of RFC6550. If the packet progresses along a DAO route, - the down flag should be set. */ - - if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) { - /* No route was found, so this packet will go towards the RPL - root. If so, we should not set the down flag. */ - UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN; + /* Check the direction of the down flag, as per Section 11.2.2.3, + which states that if a packet is going down it should in + general not go back up again. If this happens, a + RPL_HDR_OPT_FWD_ERR should be flagged. */ + if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) { + if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) { + UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR; + PRINTF("RPL forwarding error\n"); + } } else { - /* A DAO route was found so we set the down flag. */ - UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN; + /* Set the down extension flag correctly as described in Section + 11.2 of RFC6550. If the packet progresses along a DAO route, + the down flag should be set. */ + if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) { + /* No route was found, so this packet will go towards the RPL + root. If so, we should not set the down flag. */ + UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN; + PRINTF("RPL option going up\n"); + } else { + /* A DAO route was found so we set the down flag. */ + UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN; + PRINTF("RPL option going down\n"); + } } uip_ext_len = last_uip_ext_len;