diff --git a/core/net/ipv6/uip-ds6-route.h b/core/net/ipv6/uip-ds6-route.h index 342bfeffa..8df18796b 100644 --- a/core/net/ipv6/uip-ds6-route.h +++ b/core/net/ipv6/uip-ds6-route.h @@ -97,11 +97,42 @@ void uip_ds6_notification_rm(struct uip_ds6_notification *n); #ifndef UIP_DS6_ROUTE_STATE_TYPE #define UIP_DS6_ROUTE_STATE_TYPE rpl_route_entry_t /* Needed for the extended route entry state when using ContikiRPL */ +#define RPL_ROUTE_ENTRY_NOPATH_RECEIVED 0x01 +#define RPL_ROUTE_ENTRY_DAO_PENDING 0x02 +#define RPL_ROUTE_ENTRY_DAO_NACK 0x04 + +#define RPL_ROUTE_IS_NOPATH_RECEIVED(route) \ + (((route)->state.state_flags & RPL_ROUTE_ENTRY_NOPATH_RECEIVED) != 0) +#define RPL_ROUTE_SET_NOPATH_RECEIVED(route) do { \ + (route)->state.state_flags |= RPL_ROUTE_ENTRY_NOPATH_RECEIVED; \ + } while(0) + +#define RPL_ROUTE_IS_DAO_PENDING(route) \ + ((route->state.state_flags & RPL_ROUTE_ENTRY_DAO_PENDING) != 0) +#define RPL_ROUTE_SET_DAO_PENDING(route) do { \ + (route)->state.state_flags |= RPL_ROUTE_ENTRY_DAO_PENDING; \ + } while(0) +#define RPL_ROUTE_CLEAR_DAO_PENDING(route) do { \ + (route)->state.state_flags &= ~RPL_ROUTE_ENTRY_DAO_PENDING; \ + } while(0) + +#define RPL_ROUTE_IS_DAO_NACKED(route) \ + ((route->state.state_flags & RPL_ROUTE_ENTRY_DAO_NACK) != 0) +#define RPL_ROUTE_SET_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); \ + } while(0) + +struct rpl_dag; typedef struct rpl_route_entry { uint32_t lifetime; - void *dag; - uint8_t learned_from; - uint8_t nopath_received; + struct rpl_dag *dag; + uint8_t dao_seqno_out; + uint8_t dao_seqno_in; + uint8_t state_flags; } rpl_route_entry_t; #endif /* UIP_DS6_ROUTE_STATE_TYPE */ diff --git a/core/net/rpl/rpl-conf.h b/core/net/rpl/rpl-conf.h index 5511b8289..2ff9fbf91 100644 --- a/core/net/rpl/rpl-conf.h +++ b/core/net/rpl/rpl-conf.h @@ -235,6 +235,16 @@ #define RPL_INSERT_HBH_OPTION 1 #endif +/* + * RPL DAO ACK support. When enabled, DAO ACK will be sent and requested. + * This will also enable retransmission of DAO when no ack is received. + * */ +#ifdef RPL_CONF_WITH_DAO_ACK +#define RPL_WITH_DAO_ACK RPL_CONF_WITH_DAO_ACK +#else +#define RPL_WITH_DAO_ACK 1 +#endif /* RPL_CONF_WITH_DAO_ACK */ + /* * RPL probing. When enabled, probes will be sent periodically to keep * parent link estimates up to date. diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index 27a534b09..04c64a50d 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -1028,7 +1028,7 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) rpl_set_default_route(instance, from); if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { - rpl_schedule_dao(instance); + rpl_schedule_dao_immediately(instance); } else { PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n"); } diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 14de349fe..e1ac899ba 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -76,6 +76,9 @@ static void dio_input(void); static void dao_input(void); static void dao_ack_input(void); +static void dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix, + uint8_t lifetime, uint8_t seq_no); + /* some debug callbacks useful when debugging RPL networks */ #ifdef RPL_DEBUG_DIO_INPUT void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *); @@ -85,6 +88,7 @@ void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *); void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *); #endif +/* TODO: should these variables be a part of the instance? */ static uint8_t dao_sequence = RPL_LOLLIPOP_INIT; extern rpl_of_t RPL_OF; @@ -99,6 +103,37 @@ UIP_ICMP6_HANDLER(dio_handler, ICMP6_RPL, RPL_CODE_DIO, dio_input); 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); /*---------------------------------------------------------------------------*/ +#if RPL_WITH_DAO_ACK +static uip_ds6_route_t * +find_route_entry_by_dao_ack(uint8_t seq) +{ + uip_ds6_route_t *re; + re = uip_ds6_route_head(); + while(re != NULL) { + if(re->state.dao_seqno_out == seq && RPL_ROUTE_IS_DAO_PENDING(re)) { + /* found it! */ + return re; + } + re = uip_ds6_route_next(re); + } + return NULL; +} +#endif /* RPL_WITH_DAO_ACK */ + +/* prepare for forwarding of DAO */ +static uint8_t +prepare_for_dao_fwd(uint8_t sequence, uip_ds6_route_t *rep) +{ + /* not pending - or pending but not a retransmission */ + RPL_LOLLIPOP_INCREMENT(dao_sequence); + + /* set DAO pending and sequence numbers */ + rep->state.dao_seqno_in = sequence; + rep->state.dao_seqno_out = dao_sequence; + RPL_ROUTE_SET_DAO_PENDING(rep); + return dao_sequence; +} +/*---------------------------------------------------------------------------*/ static int get_global_addr(uip_ipaddr_t *addr) { @@ -723,28 +758,37 @@ dao_input(void) PRINTF("RPL: No-Path DAO received\n"); /* No-Path DAO received; invoke the route purging routine. */ if(rep != NULL && - rep->state.nopath_received == 0 && + !RPL_ROUTE_IS_NOPATH_RECEIVED(rep) && rep->length == prefixlen && uip_ds6_route_nexthop(rep) != NULL && uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) { PRINTF("RPL: Setting expiration timer for prefix "); PRINT6ADDR(&prefix); PRINTF("\n"); - rep->state.nopath_received = 1; + RPL_ROUTE_SET_NOPATH_RECEIVED(rep); rep->state.lifetime = RPL_NOPATH_REMOVAL_DELAY; /* We forward the incoming No-Path DAO to our parent, if we have one. */ if(dag->preferred_parent != NULL && rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) { - PRINTF("RPL: Forwarding No-Path DAO to parent "); + uint8_t out_seq; + out_seq = prepare_for_dao_fwd(sequence, rep); + + PRINTF("RPL: Forwarding no-path DAO to parent - out_seq:%d", + out_seq); PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent)); PRINTF("\n"); + + buffer = UIP_ICMP_PAYLOAD; + buffer[3] = out_seq; /* add an outgoing seq no before fwd */ uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent), ICMP6_RPL, RPL_CODE_DAO, buffer_length); } if(flags & RPL_DAO_K_FLAG) { - dao_ack_output(instance, &dao_sender_addr, sequence); + /* indicate that we accepted the no-path DAO */ + dao_ack_output(instance, &dao_sender_addr, sequence, + RPL_DAO_ACK_UNCONDITIONAL_ACCEPT); } } goto discard; @@ -781,28 +825,64 @@ dao_input(void) if(rep == NULL) { RPL_STAT(rpl_stats.mem_overflows++); PRINTF("RPL: Could not add a route after receiving a DAO\n"); + + if(flags & RPL_DAO_K_FLAG) { + /* signal the failure to add the node */ + dao_ack_output(instance, &dao_sender_addr, sequence, + RPL_DAO_ACK_UNABLE_TO_ACCEPT); + } goto discard; } rep->state.lifetime = RPL_LIFETIME(instance, lifetime); - rep->state.learned_from = learned_from; - rep->state.nopath_received = 0; + /* rep->state.learned_from = learned_from; */ + /* rep->state.nopath_received = 0; */ #if RPL_CONF_MULTICAST fwd_dao: #endif if(learned_from == RPL_ROUTE_FROM_UNICAST_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. */ + if((!RPL_ROUTE_IS_DAO_PENDING(rep) && + rep->state.dao_seqno_in == sequence) || + dag->rank == ROOT_RANK(instance)) { + should_ack = 1; + } + } + if(dag->preferred_parent != NULL && rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) { + uint8_t out_seq = 0; + /* if this is pending and we get the same seq no it is a retrans */ + if(RPL_ROUTE_IS_DAO_PENDING(rep) && + rep->state.dao_seqno_in == sequence) { + /* keep the same seq-no as before for parent also */ + out_seq = rep->state.dao_seqno_out; + } else { + out_seq = prepare_for_dao_fwd(sequence, rep); + } + PRINTF("RPL: Forwarding DAO to parent "); PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent)); - PRINTF("\n"); + PRINTF(" in seq: %d out seq: %d\n", sequence, out_seq); + + buffer = UIP_ICMP_PAYLOAD; + buffer[3] = out_seq; /* add an outgoing seq no before fwd */ uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent), ICMP6_RPL, RPL_CODE_DAO, buffer_length); } - if(flags & RPL_DAO_K_FLAG) { - dao_ack_output(instance, &dao_sender_addr, sequence); + + /* Ack sent immediately after forwarding (otherwise the packets is + corrupted. */ + if(should_ack) { + PRINTF("RPL: sending DAO ACK\n"); + dao_ack_output(instance, &dao_sender_addr, sequence, + RPL_DAO_ACK_UNCONDITIONAL_ACCEPT); } } @@ -810,23 +890,95 @@ fwd_dao: uip_clear_buf(); } /*---------------------------------------------------------------------------*/ +#if RPL_WITH_DAO_ACK +static void +handle_dao_retransmission(void *ptr) +{ + rpl_parent_t *parent; + uip_ipaddr_t prefix; + rpl_instance_t *instance; + parent = ptr; + + if(parent == NULL || parent->dag == NULL || parent->dag->instance == NULL) { + return; + } + instance = parent->dag->instance; + + if(instance->my_dao_transmissions >= RPL_DAO_MAX_RETRANSMISSIONS) { + /* no more retransmissions - what now ??? */ + if(instance->lifetime_unit == 0xffff && instance->default_lifetime == 0xff) { + /* RPL is using infinite lifetime for routes. This probably + means that the root is running an old version that does not + support DAO ack. Assume that everything is ok for now and + let the normal repair mechanisms detect any problems. */ + return; + } + + if(instance->of->dao_ack_callback) { + /* Inform about the timeout for taking decision on punishment */ + instance->of->dao_ack_callback(parent, RPL_DAO_ACK_TIMEOUT); + } + + rpl_local_repair(instance); + /* give up this and hope to find another parent */ + return; + } + + PRINTF("Should retransmit DAO - seq:%d trans:%d\n", instance->my_dao_seqno, + instance->my_dao_transmissions); + + if(get_global_addr(&prefix) == 0) { + return; + } + + ctimer_set(&instance->dao_retransmit_timer, RPL_DAO_RETRANSMISSION_TIMEOUT, + handle_dao_retransmission, parent); + + instance->my_dao_transmissions++; + dao_output_target_seq(parent, &prefix, + instance->default_lifetime, instance->my_dao_seqno); +} +#endif /* RPL_WITH_DAO_ACK */ +/*---------------------------------------------------------------------------*/ void dao_output(rpl_parent_t *parent, uint8_t lifetime) { /* Destination Advertisement Object */ uip_ipaddr_t prefix; + rpl_instance_t *instance; if(get_global_addr(&prefix) == 0) { PRINTF("RPL: No global address set for this node - suppressing DAO\n"); return; } + if(parent == NULL || parent->dag == NULL || parent->dag->instance == NULL) { + return; + } + instance = parent->dag->instance; + /* Sending a DAO with own prefix as target */ dao_output_target(parent, &prefix, lifetime); + /* keep track of my own sending of DAO for handling ack and loss of ack */ + instance->my_dao_seqno = dao_sequence; + +#if RPL_WITH_DAO_ACK + instance->my_dao_transmissions = 1; + ctimer_set(&instance->dao_retransmit_timer, RPL_DAO_RETRANSMISSION_TIMEOUT, + handle_dao_retransmission, parent); +#endif /* RPL_WITH_DAO_ACK */ } /*---------------------------------------------------------------------------*/ void dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime) +{ + RPL_LOLLIPOP_INCREMENT(dao_sequence); + dao_output_target_seq(parent, prefix, lifetime, dao_sequence); +} +/*---------------------------------------------------------------------------*/ +static void +dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix, + uint8_t lifetime, uint8_t seq_no) { rpl_dag_t *dag; rpl_instance_t *instance; @@ -867,8 +1019,6 @@ dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime) #endif buffer = UIP_ICMP_PAYLOAD; - - RPL_LOLLIPOP_INCREMENT(dao_sequence); pos = 0; buffer[pos++] = instance->instance_id; @@ -876,12 +1026,12 @@ dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime) #if RPL_DAO_SPECIFY_DAG buffer[pos] |= RPL_DAO_D_FLAG; #endif /* RPL_DAO_SPECIFY_DAG */ -#if RPL_CONF_DAO_ACK +#if RPL_WITH_DAO_ACK buffer[pos] |= RPL_DAO_K_FLAG; -#endif /* RPL_CONF_DAO_ACK */ +#endif /* RPL_WITH_DAO_ACK */ ++pos; buffer[pos++] = 0; /* reserved */ - buffer[pos++] = dao_sequence; + buffer[pos++] = seq_no; #if RPL_DAO_SPECIFY_DAG memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id)); pos+=sizeof(dag->dag_id); @@ -918,41 +1068,105 @@ dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime) static void dao_ack_input(void) { -#if DEBUG - unsigned char *buffer; +#if RPL_WITH_DAO_ACK + + uint8_t *buffer; + uint8_t instance_id; uint8_t sequence; uint8_t status; + rpl_instance_t *instance; + rpl_parent_t *parent; buffer = UIP_ICMP_PAYLOAD; sequence = buffer[2]; status = buffer[3]; - PRINTF("RPL: Received a DAO ACK with sequence number %d and status %d from ", - sequence, status); + instance = rpl_get_instance(instance_id); + if(instance == NULL) { + return; + } + + 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); + return; + } + + PRINTF("RPL: Received a DAO ACK with sequence number %d (%d) and status %d from ", + sequence, instance->my_dao_seqno, status); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("\n"); #endif /* DEBUG */ + + if(sequence == instance->my_dao_seqno) { + PRINTF("RPL: DAO ACK for me!\n"); + + /* always stop the retransmit timer when the ACK arrived */ + ctimer_stop(&instance->dao_retransmit_timer); + + /* Inform objective function on status of the DAO ACK */ + if(instance->of->dao_ack_callback) { + instance->of->dao_ack_callback(parent, status); + } + + 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... */ + rpl_local_repair(instance); + } + } else { + /* this DAO should be forwarded to another recently registered route */ + uip_ds6_route_t *re; + uip_ipaddr_t *nexthop; + if((re = find_route_entry_by_dao_ack(sequence)) != NULL) { + /* pick the recorded seq no from that node and forward DAO ACK - and + clear the pending flag*/ + RPL_ROUTE_CLEAR_DAO_PENDING(re); + + nexthop = uip_ds6_route_nexthop(re); + if(nexthop == NULL) { + PRINTF("No next hop to fwd DAO ACK to\n"); + } else { + PRINTF("Fwd DAO ACK\n"); + buffer[2] = re->state.dao_seqno_in; + uip_icmp6_send(nexthop, ICMP6_RPL, RPL_CODE_DAO_ACK, 4); + } + + if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) { + /* this node did not get in to the routing tables above... - remove */ + uip_ds6_route_rm(re); + } + } else { + PRINTF("No route entry to fwd DAO ACK to\n"); + } + } +#endif /* RPL_WITH_DAO_ACK */ uip_clear_buf(); } /*---------------------------------------------------------------------------*/ void -dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence) +dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence, + uint8_t status) { +#if RPL_WITH_DAO_ACK unsigned char *buffer; PRINTF("RPL: Sending a DAO ACK with sequence number %d to ", sequence); PRINT6ADDR(dest); - PRINTF("\n"); + PRINTF(" with status %d\n", status); buffer = UIP_ICMP_PAYLOAD; buffer[0] = instance->instance_id; buffer[1] = 0; buffer[2] = sequence; - buffer[3] = 0; + buffer[3] = status; uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4); +#endif /* RPL_WITH_DAO_ACK */ } /*---------------------------------------------------------------------------*/ void diff --git a/core/net/rpl/rpl-mrhof.c b/core/net/rpl/rpl-mrhof.c index 47314917f..acf2b1d54 100644 --- a/core/net/rpl/rpl-mrhof.c +++ b/core/net/rpl/rpl-mrhof.c @@ -54,6 +54,7 @@ static void reset(rpl_dag_t *); static void neighbor_link_callback(rpl_parent_t *, int, int); +static void dao_ack_callback(rpl_parent_t *, int); 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); @@ -62,6 +63,7 @@ static void update_metric_container(rpl_instance_t *); rpl_of_t rpl_mrhof = { reset, neighbor_link_callback, + dao_ack_callback, best_parent, best_dag, calculate_rank, @@ -117,6 +119,20 @@ reset(rpl_dag_t *dag) PRINTF("RPL: Reset MRHOF\n"); } +static void +dao_ack_callback(rpl_parent_t *p, int status) +{ + /* here we need to handle failed DAO's and other stuff */ + PRINTF("RPL: MRHOF - DAO ACK received with status: %d", status); + if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) { + /* punish the ETX as if this was 10 packets lost */ + neighbor_link_callback(p, MAC_TX_OK, 10); + } else if(status == RPL_DAO_ACK_TIMEOUT) { /* timeout = no ack */ + /* punish the total lack of ACK with a similar punishment */ + neighbor_link_callback(p, MAC_TX_OK, 10); + } +} + static void neighbor_link_callback(rpl_parent_t *p, int status, int numtx) { diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index ca73169fc..ed76bac4b 100644 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -55,6 +55,7 @@ static void update_metric_container(rpl_instance_t *); rpl_of_t rpl_of0 = { reset, NULL, + NULL, best_parent, best_dag, calculate_rank, diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index e1d95697b..5a7a9be94 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.h @@ -90,6 +90,13 @@ #define RPL_DAO_K_FLAG 0x80 /* DAO ACK requested */ #define RPL_DAO_D_FLAG 0x40 /* DODAG ID present */ + +#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_TIMEOUT -1 + /*---------------------------------------------------------------------------*/ /* RPL IPv6 extension header option. */ #define RPL_HDR_OPT_LEN 4 @@ -117,6 +124,9 @@ #define RPL_NOPATH_REMOVAL_DELAY 60 #endif /* RPL_CONF_NOPATH_REMOVAL_DELAY */ +#define RPL_DAO_MAX_RETRANSMISSIONS 5 +#define RPL_DAO_RETRANSMISSION_TIMEOUT (5 * CLOCK_SECOND) + /* Special value indicating immediate removal. */ #define RPL_ZERO_LIFETIME 0 @@ -268,7 +278,7 @@ void dis_output(uip_ipaddr_t *addr); void dio_output(rpl_instance_t *, uip_ipaddr_t *uc_addr); void dao_output(rpl_parent_t *, uint8_t lifetime); void dao_output_target(rpl_parent_t *, uip_ipaddr_t *, uint8_t lifetime); -void dao_ack_output(rpl_instance_t *, uip_ipaddr_t *, uint8_t); +void dao_ack_output(rpl_instance_t *, uip_ipaddr_t *, uint8_t, uint8_t); void rpl_icmp6_register_handlers(void); /* RPL logic functions. */ diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index 7e7947e34..da5822757 100644 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -238,7 +238,7 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len, rep->state.dag = dag; rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime); - rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL; + /* rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL; */ PRINTF("RPL: Added a route to "); PRINT6ADDR(prefix); diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index 54b63c875..b7d7757c2 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -185,6 +185,7 @@ typedef struct rpl_instance rpl_instance_t; struct rpl_of { void (*reset)(struct rpl_dag *); void (*neighbor_link_callback)(rpl_parent_t *, int, int); + void (*dao_ack_callback)(rpl_parent_t *, int status); 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); @@ -216,6 +217,9 @@ struct rpl_instance { uint8_t dio_intcurrent; uint8_t dio_send; /* for keeping track of which mode the timer is in */ uint8_t dio_counter; + /* my last registered DAO that I might be waiting for ACK on */ + uint8_t my_dao_seqno; + uint8_t my_dao_transmissions; rpl_rank_t max_rankinc; rpl_rank_t min_hoprankinc; uint16_t lifetime_unit; /* lifetime in seconds = l_u * d_l */ @@ -233,6 +237,9 @@ struct rpl_instance { struct ctimer dao_lifetime_timer; struct ctimer unicast_dio_timer; rpl_parent_t *unicast_dio_target; +#if RPL_WITH_DAO_ACK + struct ctimer dao_retransmit_timer; +#endif /* RPL_WITH_DAO_ACK */ }; /*---------------------------------------------------------------------------*/