Added support for end-to-end DAO ACK for Contiki RPL.
This is a fix for Contiki RPL so that it fully supports DAO ACK in an end-to-end fashion. When DAO is sent it will be forwarded upwards as before. DAO ACK will be forwarded downwards until it reach the node that initiated the DAO ACK and unlike before it is not a single-hop DAO ACK but it is fully reaching the RPL ROOT before any DAO ACK is sent back. DAO ACK also now fully support different status messages (success / fail).
This commit is contained in:
parent
3b9fa19a66
commit
946be77248
@ -97,11 +97,42 @@ void uip_ds6_notification_rm(struct uip_ds6_notification *n);
|
|||||||
#ifndef UIP_DS6_ROUTE_STATE_TYPE
|
#ifndef UIP_DS6_ROUTE_STATE_TYPE
|
||||||
#define UIP_DS6_ROUTE_STATE_TYPE rpl_route_entry_t
|
#define UIP_DS6_ROUTE_STATE_TYPE rpl_route_entry_t
|
||||||
/* Needed for the extended route entry state when using ContikiRPL */
|
/* 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 {
|
typedef struct rpl_route_entry {
|
||||||
uint32_t lifetime;
|
uint32_t lifetime;
|
||||||
void *dag;
|
struct rpl_dag *dag;
|
||||||
uint8_t learned_from;
|
uint8_t dao_seqno_out;
|
||||||
uint8_t nopath_received;
|
uint8_t dao_seqno_in;
|
||||||
|
uint8_t state_flags;
|
||||||
} rpl_route_entry_t;
|
} rpl_route_entry_t;
|
||||||
#endif /* UIP_DS6_ROUTE_STATE_TYPE */
|
#endif /* UIP_DS6_ROUTE_STATE_TYPE */
|
||||||
|
|
||||||
|
@ -235,6 +235,16 @@
|
|||||||
#define RPL_INSERT_HBH_OPTION 1
|
#define RPL_INSERT_HBH_OPTION 1
|
||||||
#endif
|
#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
|
* RPL probing. When enabled, probes will be sent periodically to keep
|
||||||
* parent link estimates up to date.
|
* parent link estimates up to date.
|
||||||
|
@ -1028,7 +1028,7 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||||||
rpl_set_default_route(instance, from);
|
rpl_set_default_route(instance, from);
|
||||||
|
|
||||||
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
|
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
|
||||||
rpl_schedule_dao(instance);
|
rpl_schedule_dao_immediately(instance);
|
||||||
} else {
|
} else {
|
||||||
PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n");
|
PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n");
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,9 @@ static void dio_input(void);
|
|||||||
static void dao_input(void);
|
static void dao_input(void);
|
||||||
static void dao_ack_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 */
|
/* some debug callbacks useful when debugging RPL networks */
|
||||||
#ifdef RPL_DEBUG_DIO_INPUT
|
#ifdef RPL_DEBUG_DIO_INPUT
|
||||||
void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *);
|
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 *);
|
void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* TODO: should these variables be a part of the instance? */
|
||||||
static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
|
static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
|
||||||
|
|
||||||
extern rpl_of_t RPL_OF;
|
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_handler, ICMP6_RPL, RPL_CODE_DAO, dao_input);
|
||||||
UIP_ICMP6_HANDLER(dao_ack_handler, ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_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
|
static int
|
||||||
get_global_addr(uip_ipaddr_t *addr)
|
get_global_addr(uip_ipaddr_t *addr)
|
||||||
{
|
{
|
||||||
@ -723,28 +758,37 @@ dao_input(void)
|
|||||||
PRINTF("RPL: No-Path DAO received\n");
|
PRINTF("RPL: No-Path DAO received\n");
|
||||||
/* No-Path DAO received; invoke the route purging routine. */
|
/* No-Path DAO received; invoke the route purging routine. */
|
||||||
if(rep != NULL &&
|
if(rep != NULL &&
|
||||||
rep->state.nopath_received == 0 &&
|
!RPL_ROUTE_IS_NOPATH_RECEIVED(rep) &&
|
||||||
rep->length == prefixlen &&
|
rep->length == prefixlen &&
|
||||||
uip_ds6_route_nexthop(rep) != NULL &&
|
uip_ds6_route_nexthop(rep) != NULL &&
|
||||||
uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) {
|
uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) {
|
||||||
PRINTF("RPL: Setting expiration timer for prefix ");
|
PRINTF("RPL: Setting expiration timer for prefix ");
|
||||||
PRINT6ADDR(&prefix);
|
PRINT6ADDR(&prefix);
|
||||||
PRINTF("\n");
|
PRINTF("\n");
|
||||||
rep->state.nopath_received = 1;
|
RPL_ROUTE_SET_NOPATH_RECEIVED(rep);
|
||||||
rep->state.lifetime = RPL_NOPATH_REMOVAL_DELAY;
|
rep->state.lifetime = RPL_NOPATH_REMOVAL_DELAY;
|
||||||
|
|
||||||
/* We forward the incoming No-Path DAO to our parent, if we have
|
/* We forward the incoming No-Path DAO to our parent, if we have
|
||||||
one. */
|
one. */
|
||||||
if(dag->preferred_parent != NULL &&
|
if(dag->preferred_parent != NULL &&
|
||||||
rpl_get_parent_ipaddr(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));
|
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
|
||||||
PRINTF("\n");
|
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),
|
uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
|
||||||
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
|
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
|
||||||
}
|
}
|
||||||
if(flags & RPL_DAO_K_FLAG) {
|
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;
|
goto discard;
|
||||||
@ -781,28 +825,64 @@ dao_input(void)
|
|||||||
if(rep == NULL) {
|
if(rep == NULL) {
|
||||||
RPL_STAT(rpl_stats.mem_overflows++);
|
RPL_STAT(rpl_stats.mem_overflows++);
|
||||||
PRINTF("RPL: Could not add a route after receiving a DAO\n");
|
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;
|
goto discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
|
rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
|
||||||
rep->state.learned_from = learned_from;
|
/* rep->state.learned_from = learned_from; */
|
||||||
rep->state.nopath_received = 0;
|
/* rep->state.nopath_received = 0; */
|
||||||
|
|
||||||
#if RPL_CONF_MULTICAST
|
#if RPL_CONF_MULTICAST
|
||||||
fwd_dao:
|
fwd_dao:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
|
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 &&
|
if(dag->preferred_parent != NULL &&
|
||||||
rpl_get_parent_ipaddr(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 ");
|
PRINTF("RPL: Forwarding DAO to parent ");
|
||||||
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_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),
|
uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
|
||||||
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
|
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();
|
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
|
void
|
||||||
dao_output(rpl_parent_t *parent, uint8_t lifetime)
|
dao_output(rpl_parent_t *parent, uint8_t lifetime)
|
||||||
{
|
{
|
||||||
/* Destination Advertisement Object */
|
/* Destination Advertisement Object */
|
||||||
uip_ipaddr_t prefix;
|
uip_ipaddr_t prefix;
|
||||||
|
rpl_instance_t *instance;
|
||||||
|
|
||||||
if(get_global_addr(&prefix) == 0) {
|
if(get_global_addr(&prefix) == 0) {
|
||||||
PRINTF("RPL: No global address set for this node - suppressing DAO\n");
|
PRINTF("RPL: No global address set for this node - suppressing DAO\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(parent == NULL || parent->dag == NULL || parent->dag->instance == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance = parent->dag->instance;
|
||||||
|
|
||||||
/* Sending a DAO with own prefix as target */
|
/* Sending a DAO with own prefix as target */
|
||||||
dao_output_target(parent, &prefix, lifetime);
|
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
|
void
|
||||||
dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
|
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_dag_t *dag;
|
||||||
rpl_instance_t *instance;
|
rpl_instance_t *instance;
|
||||||
@ -867,8 +1019,6 @@ dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
buffer = UIP_ICMP_PAYLOAD;
|
buffer = UIP_ICMP_PAYLOAD;
|
||||||
|
|
||||||
RPL_LOLLIPOP_INCREMENT(dao_sequence);
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
|
||||||
buffer[pos++] = instance->instance_id;
|
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
|
#if RPL_DAO_SPECIFY_DAG
|
||||||
buffer[pos] |= RPL_DAO_D_FLAG;
|
buffer[pos] |= RPL_DAO_D_FLAG;
|
||||||
#endif /* RPL_DAO_SPECIFY_DAG */
|
#endif /* RPL_DAO_SPECIFY_DAG */
|
||||||
#if RPL_CONF_DAO_ACK
|
#if RPL_WITH_DAO_ACK
|
||||||
buffer[pos] |= RPL_DAO_K_FLAG;
|
buffer[pos] |= RPL_DAO_K_FLAG;
|
||||||
#endif /* RPL_CONF_DAO_ACK */
|
#endif /* RPL_WITH_DAO_ACK */
|
||||||
++pos;
|
++pos;
|
||||||
buffer[pos++] = 0; /* reserved */
|
buffer[pos++] = 0; /* reserved */
|
||||||
buffer[pos++] = dao_sequence;
|
buffer[pos++] = seq_no;
|
||||||
#if RPL_DAO_SPECIFY_DAG
|
#if RPL_DAO_SPECIFY_DAG
|
||||||
memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
|
memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
|
||||||
pos+=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
|
static void
|
||||||
dao_ack_input(void)
|
dao_ack_input(void)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if RPL_WITH_DAO_ACK
|
||||||
unsigned char *buffer;
|
|
||||||
|
uint8_t *buffer;
|
||||||
|
uint8_t instance_id;
|
||||||
uint8_t sequence;
|
uint8_t sequence;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
rpl_instance_t *instance;
|
||||||
|
rpl_parent_t *parent;
|
||||||
|
|
||||||
buffer = UIP_ICMP_PAYLOAD;
|
buffer = UIP_ICMP_PAYLOAD;
|
||||||
|
|
||||||
sequence = buffer[2];
|
sequence = buffer[2];
|
||||||
status = buffer[3];
|
status = buffer[3];
|
||||||
|
|
||||||
PRINTF("RPL: Received a DAO ACK with sequence number %d and status %d from ",
|
instance = rpl_get_instance(instance_id);
|
||||||
sequence, status);
|
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);
|
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||||
PRINTF("\n");
|
PRINTF("\n");
|
||||||
#endif /* DEBUG */
|
#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();
|
uip_clear_buf();
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
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;
|
unsigned char *buffer;
|
||||||
|
|
||||||
PRINTF("RPL: Sending a DAO ACK with sequence number %d to ", sequence);
|
PRINTF("RPL: Sending a DAO ACK with sequence number %d to ", sequence);
|
||||||
PRINT6ADDR(dest);
|
PRINT6ADDR(dest);
|
||||||
PRINTF("\n");
|
PRINTF(" with status %d\n", status);
|
||||||
|
|
||||||
buffer = UIP_ICMP_PAYLOAD;
|
buffer = UIP_ICMP_PAYLOAD;
|
||||||
|
|
||||||
buffer[0] = instance->instance_id;
|
buffer[0] = instance->instance_id;
|
||||||
buffer[1] = 0;
|
buffer[1] = 0;
|
||||||
buffer[2] = sequence;
|
buffer[2] = sequence;
|
||||||
buffer[3] = 0;
|
buffer[3] = status;
|
||||||
|
|
||||||
uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
|
uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
|
||||||
|
#endif /* RPL_WITH_DAO_ACK */
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
|
|
||||||
static void reset(rpl_dag_t *);
|
static void reset(rpl_dag_t *);
|
||||||
static void neighbor_link_callback(rpl_parent_t *, int, int);
|
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_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
|
||||||
static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_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);
|
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 = {
|
rpl_of_t rpl_mrhof = {
|
||||||
reset,
|
reset,
|
||||||
neighbor_link_callback,
|
neighbor_link_callback,
|
||||||
|
dao_ack_callback,
|
||||||
best_parent,
|
best_parent,
|
||||||
best_dag,
|
best_dag,
|
||||||
calculate_rank,
|
calculate_rank,
|
||||||
@ -117,6 +119,20 @@ reset(rpl_dag_t *dag)
|
|||||||
PRINTF("RPL: Reset MRHOF\n");
|
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
|
static void
|
||||||
neighbor_link_callback(rpl_parent_t *p, int status, int numtx)
|
neighbor_link_callback(rpl_parent_t *p, int status, int numtx)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +55,7 @@ static void update_metric_container(rpl_instance_t *);
|
|||||||
rpl_of_t rpl_of0 = {
|
rpl_of_t rpl_of0 = {
|
||||||
reset,
|
reset,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
best_parent,
|
best_parent,
|
||||||
best_dag,
|
best_dag,
|
||||||
calculate_rank,
|
calculate_rank,
|
||||||
|
@ -90,6 +90,13 @@
|
|||||||
|
|
||||||
#define RPL_DAO_K_FLAG 0x80 /* DAO ACK requested */
|
#define RPL_DAO_K_FLAG 0x80 /* DAO ACK requested */
|
||||||
#define RPL_DAO_D_FLAG 0x40 /* DODAG ID present */
|
#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. */
|
/* RPL IPv6 extension header option. */
|
||||||
#define RPL_HDR_OPT_LEN 4
|
#define RPL_HDR_OPT_LEN 4
|
||||||
@ -117,6 +124,9 @@
|
|||||||
#define RPL_NOPATH_REMOVAL_DELAY 60
|
#define RPL_NOPATH_REMOVAL_DELAY 60
|
||||||
#endif /* RPL_CONF_NOPATH_REMOVAL_DELAY */
|
#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. */
|
/* Special value indicating immediate removal. */
|
||||||
#define RPL_ZERO_LIFETIME 0
|
#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 dio_output(rpl_instance_t *, uip_ipaddr_t *uc_addr);
|
||||||
void dao_output(rpl_parent_t *, uint8_t lifetime);
|
void dao_output(rpl_parent_t *, uint8_t lifetime);
|
||||||
void dao_output_target(rpl_parent_t *, uip_ipaddr_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);
|
void rpl_icmp6_register_handlers(void);
|
||||||
|
|
||||||
/* RPL logic functions. */
|
/* RPL logic functions. */
|
||||||
|
@ -238,7 +238,7 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len,
|
|||||||
|
|
||||||
rep->state.dag = dag;
|
rep->state.dag = dag;
|
||||||
rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime);
|
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 ");
|
PRINTF("RPL: Added a route to ");
|
||||||
PRINT6ADDR(prefix);
|
PRINT6ADDR(prefix);
|
||||||
|
@ -185,6 +185,7 @@ typedef struct rpl_instance rpl_instance_t;
|
|||||||
struct rpl_of {
|
struct rpl_of {
|
||||||
void (*reset)(struct rpl_dag *);
|
void (*reset)(struct rpl_dag *);
|
||||||
void (*neighbor_link_callback)(rpl_parent_t *, int, int);
|
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_parent_t *(*best_parent)(rpl_parent_t *, rpl_parent_t *);
|
||||||
rpl_dag_t *(*best_dag)(rpl_dag_t *, rpl_dag_t *);
|
rpl_dag_t *(*best_dag)(rpl_dag_t *, rpl_dag_t *);
|
||||||
rpl_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_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_intcurrent;
|
||||||
uint8_t dio_send; /* for keeping track of which mode the timer is in */
|
uint8_t dio_send; /* for keeping track of which mode the timer is in */
|
||||||
uint8_t dio_counter;
|
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 max_rankinc;
|
||||||
rpl_rank_t min_hoprankinc;
|
rpl_rank_t min_hoprankinc;
|
||||||
uint16_t lifetime_unit; /* lifetime in seconds = l_u * d_l */
|
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 dao_lifetime_timer;
|
||||||
struct ctimer unicast_dio_timer;
|
struct ctimer unicast_dio_timer;
|
||||||
rpl_parent_t *unicast_dio_target;
|
rpl_parent_t *unicast_dio_target;
|
||||||
|
#if RPL_WITH_DAO_ACK
|
||||||
|
struct ctimer dao_retransmit_timer;
|
||||||
|
#endif /* RPL_WITH_DAO_ACK */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
Loading…
Reference in New Issue
Block a user