diff --git a/core/net/ipv6/uip-ds6-nbr.c b/core/net/ipv6/uip-ds6-nbr.c index b8666a14a..e5c6167e5 100644 --- a/core/net/ipv6/uip-ds6-nbr.c +++ b/core/net/ipv6/uip-ds6-nbr.c @@ -83,7 +83,7 @@ uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr, void *data) { uip_ds6_nbr_t *nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr - ,reason, data); + , reason, data); if(nbr) { uip_ipaddr_copy(&nbr->ipaddr, ipaddr); #if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER diff --git a/core/net/ipv6/uip-ds6-route.c b/core/net/ipv6/uip-ds6-route.c index 21ce38f64..043ca78d4 100644 --- a/core/net/ipv6/uip-ds6-route.c +++ b/core/net/ipv6/uip-ds6-route.c @@ -207,8 +207,15 @@ uip_ds6_route_next(uip_ds6_route_t *r) } /*---------------------------------------------------------------------------*/ int -uip_ds6_route_is_nexthop(const uip_lladdr_t *lladdr) +uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr) { + const uip_lladdr_t *lladdr; + lladdr = uip_ds6_nbr_lladdr_from_ipaddr(ipaddr); + + if(lladdr == NULL) { + return 0; + } + return nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)lladdr) != NULL; } /*---------------------------------------------------------------------------*/ diff --git a/core/net/ipv6/uip-ds6-route.h b/core/net/ipv6/uip-ds6-route.h index 7a5d805f0..6ca533c9b 100644 --- a/core/net/ipv6/uip-ds6-route.h +++ b/core/net/ipv6/uip-ds6-route.h @@ -124,6 +124,9 @@ void uip_ds6_notification_rm(struct uip_ds6_notification *n); #define RPL_ROUTE_SET_DAO_NACKED(route) do { \ (route)->state.state_flags |= RPL_ROUTE_ENTRY_DAO_NACK; \ } while(0) +#define RPL_ROUTE_CLEAR_DAO_NACKED(route) do { \ + (route)->state.state_flags &= ~RPL_ROUTE_ENTRY_DAO_NACK; \ + } while(0) #define RPL_ROUTE_CLEAR_DAO(route) do { \ (route)->state.state_flags &= ~(RPL_ROUTE_ENTRY_DAO_NACK|RPL_ROUTE_ENTRY_DAO_PENDING); \ @@ -200,7 +203,7 @@ uip_ipaddr_t *uip_ds6_route_nexthop(uip_ds6_route_t *); int uip_ds6_route_num_routes(void); uip_ds6_route_t *uip_ds6_route_head(void); uip_ds6_route_t *uip_ds6_route_next(uip_ds6_route_t *); -int uip_ds6_route_is_nexthop(const uip_lladdr_t *lladdr); +int uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr); /** @} */ #endif /* UIP_DS6_ROUTE_H */ diff --git a/core/net/nbr-table.h b/core/net/nbr-table.h index cc58c2f80..88a90a46c 100644 --- a/core/net/nbr-table.h +++ b/core/net/nbr-table.h @@ -83,7 +83,7 @@ typedef enum { NBR_TABLE_REASON_ROUTE, NBR_TABLE_REASON_IPV6_ND, NBR_TABLE_REASON_MAC, - NBR_TABLE_REASON_LLSEC + NBR_TABLE_REASON_LLSEC } nbr_table_reason_t; /** \name Neighbor tables: register and loop through table elements */ diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index 034678ff5..27f781bdf 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -899,6 +899,18 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent) parent->dag = dag_dst; } /*---------------------------------------------------------------------------*/ +int +rpl_has_downward_route(void) +{ + int i; + for(i = 0; i < RPL_MAX_INSTANCES; ++i) { + if(instance_table[i].used && instance_table[i].has_downward_route) { + return 1; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ rpl_dag_t * rpl_get_any_dag(void) { @@ -1157,8 +1169,6 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio) RPL_STAT(rpl_stats.global_repairs++); } -void rpl_set_downward_link(uint8_t link); - /*---------------------------------------------------------------------------*/ void rpl_local_repair(rpl_instance_t *instance) @@ -1177,8 +1187,8 @@ rpl_local_repair(rpl_instance_t *instance) } } - /* no downward link anymore */ - rpl_set_downward_link(0); + /* no downward route anymore */ + instance->has_downward_route = 0; rpl_reset_dio_timer(instance); /* Request refresh of DAO registrations next DIO */ diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 2296f0d97..0f20ddb67 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -90,7 +90,6 @@ void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *); #endif static uint8_t dao_sequence = RPL_LOLLIPOP_INIT; -static uint8_t downward = 0; extern rpl_of_t RPL_OF; @@ -105,18 +104,6 @@ UIP_ICMP6_HANDLER(dao_handler, ICMP6_RPL, RPL_CODE_DAO, dao_input); UIP_ICMP6_HANDLER(dao_ack_handler, ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_input); /*---------------------------------------------------------------------------*/ -void -rpl_set_downward_link(uint8_t link) -{ - downward = link; -} - -int -rpl_has_downward_link() -{ - return downward; -} - #if RPL_WITH_DAO_ACK static uip_ds6_route_t * find_route_entry_by_dao_ack(uint8_t seq) @@ -215,8 +202,10 @@ rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void * if(nbr != NULL) { #if UIP_ND6_SEND_NA - /* set reachable timer if we added or found the nbr entry */ + /* set reachable timer if we added or found the nbr entry - and update + neighbor entry to reachable to avoid sending NS/NA, etc. */ stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000); + nbr->state = NBR_REACHABLE; #endif /* UIP_ND6_SEND_NA */ } return nbr; @@ -833,7 +822,7 @@ dao_input(void) if(flags & RPL_DAO_K_FLAG) { /* signal the failure to add the node */ dao_ack_output(instance, &dao_sender_addr, sequence, - is_root ? RPL_DAO_ACK_UNABLE_TO_ACCEPT_ROOT : + is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT : RPL_DAO_ACK_UNABLE_TO_ACCEPT); } goto discard; @@ -846,7 +835,7 @@ dao_input(void) if(flags & RPL_DAO_K_FLAG) { /* signal the failure to add the node */ dao_ack_output(instance, &dao_sender_addr, sequence, - is_root ? RPL_DAO_ACK_UNABLE_TO_ACCEPT_ROOT : + is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT : RPL_DAO_ACK_UNABLE_TO_ACCEPT); } goto discard; @@ -864,8 +853,12 @@ fwd_dao: int should_ack = 0; if(flags & RPL_DAO_K_FLAG) { - /* check if this route is already installed and we can ack now! */ - /* not pending - and same seq-no means that we can ack. */ + /* + * check if this route is already installed and we can ack now! + * not pending - and same seq-no means that we can ack. + * (e.g. the route is installed already so it will not take any + * more room that it already takes - so should be ok!) + */ if((!RPL_ROUTE_IS_DAO_PENDING(rep) && rep->state.dao_seqno_in == sequence) || dag->rank == ROOT_RANK(instance)) { @@ -992,7 +985,7 @@ dao_output(rpl_parent_t *parent, uint8_t lifetime) #else /* We know that we have tried to register so now we are assuming that we have a down-link - unless this is a zero lifetime one */ - rpl_set_downward_link(lifetime != RPL_ZERO_LIFETIME); + parent->dag->instance->has_downward_route = lifetime != RPL_ZERO_LIFETIME; #endif /* RPL_WITH_DAO_ACK */ /* Sending a DAO with own prefix as target */ @@ -1122,9 +1115,7 @@ dao_ack_input(void) parent = rpl_find_parent(instance->current_dag, &UIP_IP_BUF->srcipaddr); if(parent == NULL) { - /* not a known instance - did we switch?? */ - // PRINTF("RPL: Received a DAO ACK from a not joined instance: %d", - // instance_id); + /* not a known instance - drop the packet and ignore */ uip_clear_buf(); return; } @@ -1136,7 +1127,7 @@ dao_ack_input(void) PRINTF("\n"); if(sequence == instance->my_dao_seqno) { - rpl_set_downward_link(status < 128); + instance->has_downward_route = status < 128; /* always stop the retransmit timer when the ACK arrived */ ctimer_stop(&instance->dao_retransmit_timer); @@ -1148,8 +1139,10 @@ dao_ack_input(void) #if RPL_REPAIR_ON_DAO_NACK if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) { - /* failed the DAO transmission - need to remove the default route. */ - /* Trigger a local repair since we can not get our DAO in... */ + /* + * Failed the DAO transmission - need to remove the default route. + * Trigger a local repair since we can not get our DAO in. + */ rpl_local_repair(instance); } #endif diff --git a/core/net/rpl/rpl-mrhof.c b/core/net/rpl/rpl-mrhof.c index 6da2ec304..f9ea76080 100644 --- a/core/net/rpl/rpl-mrhof.c +++ b/core/net/rpl/rpl-mrhof.c @@ -54,7 +54,9 @@ static void reset(rpl_dag_t *); static void neighbor_link_callback(rpl_parent_t *, int, int); +#if RPL_WITH_DAO_ACK static void dao_ack_callback(rpl_parent_t *, int); +#endif static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); @@ -63,7 +65,9 @@ static void update_metric_container(rpl_instance_t *); rpl_of_t rpl_mrhof = { reset, neighbor_link_callback, +#if RPL_WITH_DAO_ACK dao_ack_callback, +#endif best_parent, best_dag, calculate_rank, @@ -119,10 +123,11 @@ reset(rpl_dag_t *dag) PRINTF("RPL: Reset MRHOF\n"); } +#if RPL_WITH_DAO_ACK static void dao_ack_callback(rpl_parent_t *p, int status) { - if(status == RPL_DAO_ACK_UNABLE_TO_ACCEPT_ROOT) { + if(status == RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT) { return; } /* here we need to handle failed DAO's and other stuff */ @@ -135,6 +140,7 @@ dao_ack_callback(rpl_parent_t *p, int status) neighbor_link_callback(p, MAC_TX_OK, 10); } } +#endif /* RPL_WITH_DAO_ACK */ static void neighbor_link_callback(rpl_parent_t *p, int status, int numtx) diff --git a/core/net/rpl/rpl-nbr-policy.c b/core/net/rpl/rpl-nbr-policy.c index 6f0dd9ca3..87849af40 100644 --- a/core/net/rpl/rpl-nbr-policy.c +++ b/core/net/rpl/rpl-nbr-policy.c @@ -72,6 +72,10 @@ static linkaddr_t *worst_rank_nbr; /* the parent that has the worst rank */ static rpl_rank_t worst_rank; /*---------------------------------------------------------------------------*/ #if DEBUG == DEBUG_FULL +/* + * This create a periodic call of the update_nbr function that will print + * useful debugging information when in DEBUG_FULL mode + */ static void update_nbr(void); static struct ctimer periodic_timer; static int timer_init = 0; @@ -111,9 +115,12 @@ update_nbr(void) linkaddr_t *lladdr = nbr_table_get_lladdr(ds6_neighbors, nbr); is_used = 0; - /* Check if this neighbor is used as nexthop and therefor being a - RPL child. */ - if(uip_ds6_route_is_nexthop((uip_lladdr_t *)lladdr) != 0) { + /* + * Check if this neighbor is used as nexthop and therefor being a + * RPL child. + */ + + if(uip_ds6_route_is_nexthop(&nbr->ipaddr) != 0) { is_used++; num_children++; } @@ -123,10 +130,10 @@ update_nbr(void) num_parents++; if(parent->dag != NULL && parent->dag->preferred_parent == parent) { - /* This is the preferred parent for the DAG and must not be removed */ - - /* Note: this assumes that only RPL adds default routes. */ - + /* + * This is the preferred parent for the DAG and must not be removed + * Note: this assumes that only RPL adds default routes. + */ } else if(is_used == 0 && worst_rank < INFINITE_RANK && parent->rank > 0 && parent->dag != NULL && @@ -168,9 +175,10 @@ find_removable_dis(uip_ipaddr_t *from) update_nbr(); if(num_free > 0) { - printf("num-free > 0 = %d", num_free); - printf("**** Should remove unused elements but can not... \n"); - /* return 1; */ + /* there are free entries (e.g. unsused by RPL and ND6) but since it is + used by other modules we can not pick these entries for removal. */ + PRINTF("Num-free > 0 = %d - Other for RPL/ND6 unused NBR entry exists .", + num_free); } if(num_children < MAX_CHILDREN) { return worst_rank_nbr; @@ -192,7 +200,7 @@ find_removable_dio(uip_ipaddr_t *from, rpl_dio_t *dio) return NULL; } - /* Add the new neighbor only if it is better than the preferred parent. */ + /* Add the new neighbor only if it is better than the worst parent. */ rank = instance->of->calculate_rank(NULL, dio->rank); if(rank < worst_rank - instance->min_hoprankinc / 2) { /* Found *great* neighbor - add! */ @@ -231,7 +239,8 @@ find_removable_dao(uip_ipaddr_t *from, rpl_instance_t *instance) } /*---------------------------------------------------------------------------*/ const linkaddr_t * -rpl_nbr_policy_find_removable(nbr_table_reason_t reason,void * data) { +rpl_nbr_policy_find_removable(nbr_table_reason_t reason,void * data) +{ /* When we get the DIO/DAO/DIS we know that UIP contains the incoming packet */ switch(reason) { diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index ed76bac4b..b0a909a4d 100644 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -55,7 +55,9 @@ static void update_metric_container(rpl_instance_t *); rpl_of_t rpl_of0 = { reset, NULL, +#if RPL_WITH_DAO_ACK NULL, +#endif best_parent, best_dag, calculate_rank, diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index 161cdc532..ec885eaea 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.h @@ -94,7 +94,7 @@ #define RPL_DAO_ACK_UNCONDITIONAL_ACCEPT 0 #define RPL_DAO_ACK_ACCEPT 1 /* 1 - 127 is OK but not good */ #define RPL_DAO_ACK_UNABLE_TO_ACCEPT 128 /* >127 is fail */ -#define RPL_DAO_ACK_UNABLE_TO_ACCEPT_ROOT 255 /* root can not accept */ +#define RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT 255 /* root can not accept */ #define RPL_DAO_ACK_TIMEOUT -1 diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index dfc081d4b..532df4b3a 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -181,11 +181,19 @@ typedef struct rpl_instance rpl_instance_t; * Updates the metric container for outgoing DIOs in a certain DAG. * If the objective function of the DAG does not use metric containers, * the function should set the object type to RPL_DAG_MC_NONE. + * + * dao_ack_callback(parent, status) + * + * A callback on the result of the DAO ACK. Similar to the neighbor link + * callback. A failed DAO_ACK (NACK) can be used for switching to another + * parent via changed link metric or other mechanisms. */ struct rpl_of { void (*reset)(struct rpl_dag *); void (*neighbor_link_callback)(rpl_parent_t *, int, int); +#if RPL_WITH_DAO_ACK void (*dao_ack_callback)(rpl_parent_t *, int status); +#endif rpl_parent_t *(*best_parent)(rpl_parent_t *, rpl_parent_t *); rpl_dag_t *(*best_dag)(rpl_dag_t *, rpl_dag_t *); rpl_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_t); @@ -220,6 +228,8 @@ struct rpl_instance { /* my last registered DAO that I might be waiting for ACK on */ uint8_t my_dao_seqno; uint8_t my_dao_transmissions; + /* this is intended to keep track if this instance have a route downward */ + uint8_t has_downward_route; rpl_rank_t max_rankinc; rpl_rank_t min_hoprankinc; uint16_t lifetime_unit; /* lifetime in seconds = l_u * d_l */ @@ -302,11 +312,11 @@ enum rpl_mode rpl_get_mode(void); /** - * Get the RPL's best guess on if we have downward link or not. + * Get the RPL's best guess on if we have downward route or not. * - * \retval 1 if we have a downward link, 0 if not. + * \retval 1 if we have a downward route from RPL Root, 0 if not. */ -int rpl_has_downward_link(void); +int rpl_has_downward_route(void); /*---------------------------------------------------------------------------*/ #endif /* RPL_H */ diff --git a/regression-tests/21-large-rpl/code/node/client.c b/regression-tests/21-large-rpl/code/node/client.c index 36dc40923..1e82e2df0 100644 --- a/regression-tests/21-large-rpl/code/node/client.c +++ b/regression-tests/21-large-rpl/code/node/client.c @@ -100,7 +100,7 @@ PROCESS_THREAD(http_example_process, ev, data) while(1) { PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); etimer_reset(&et); - if(connect && rpl_has_downward_link()) { + if(connect && rpl_has_downward_route()) { printf("#A color=green\n"); http_socket_get(&s, "http://www.contiki-os.org/", 0, 0, callback, NULL);