Implement RPL non-storing mode

This commit is contained in:
Simon Duquennoy 2016-02-01 18:02:33 +01:00
parent d14b76d869
commit b3e31e1456
17 changed files with 1149 additions and 278 deletions

View file

@ -51,6 +51,7 @@
#include "net/ipv6/uip-nd6.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "net/packetbuf.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#include "random.h"
@ -119,6 +120,7 @@ find_route_entry_by_dao_ack(uint8_t seq)
}
#endif /* RPL_WITH_DAO_ACK */
#if RPL_WITH_STORING
/* prepare for forwarding of DAO */
static uint8_t
prepare_for_dao_fwd(uint8_t sequence, uip_ds6_route_t *rep)
@ -132,6 +134,7 @@ prepare_for_dao_fwd(uint8_t sequence, uip_ds6_route_t *rep)
RPL_ROUTE_SET_DAO_PENDING(rep);
return dao_sequence;
}
#endif /* RPL_WITH_STORING */
/*---------------------------------------------------------------------------*/
static int
get_global_addr(uip_ipaddr_t *addr)
@ -626,8 +629,9 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
}
/*---------------------------------------------------------------------------*/
static void
dao_input(void)
dao_input_storing(void)
{
#if RPL_WITH_STORING
uip_ipaddr_t dao_sender_addr;
rpl_dag_t *dag;
rpl_instance_t *instance;
@ -665,11 +669,6 @@ dao_input(void)
instance_id = buffer[pos++];
instance = rpl_get_instance(instance_id);
if(instance == NULL) {
PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
instance_id);
goto discard;
}
lifetime = instance->default_lifetime;
@ -685,7 +684,7 @@ dao_input(void)
if(flags & RPL_DAO_D_FLAG) {
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
goto discard;
return;
}
pos += 16;
}
@ -710,7 +709,7 @@ dao_input(void)
DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
parent->rank = INFINITE_RANK;
parent->flags |= RPL_PARENT_FLAG_UPDATED;
goto discard;
return;
}
/* If we get the DAO from our parent, we also have a loop. */
@ -718,7 +717,7 @@ dao_input(void)
PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n");
parent->rank = INFINITE_RANK;
parent->flags |= RPL_PARENT_FLAG_UPDATED;
goto discard;
return;
}
}
@ -805,7 +804,7 @@ dao_input(void)
dao_ack_output(instance, &dao_sender_addr, sequence,
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
goto discard;
return;
}
PRINTF("RPL: Adding DAO route\n");
@ -823,7 +822,7 @@ dao_input(void)
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
}
goto discard;
return;
}
rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
@ -836,7 +835,7 @@ dao_input(void)
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
}
goto discard;
return;
}
/* set lifetime and clear NOPATH bit */
@ -892,6 +891,141 @@ fwd_dao:
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
}
#endif /* RPL_WITH_STORING */
}
/*---------------------------------------------------------------------------*/
static void
dao_input_nonstoring(void)
{
#if RPL_WITH_NON_STORING
uip_ipaddr_t dao_sender_addr;
uip_ipaddr_t dao_parent_addr;
rpl_dag_t *dag;
rpl_instance_t *instance;
unsigned char *buffer;
uint16_t sequence;
uint8_t instance_id;
uint8_t lifetime;
uint8_t prefixlen;
uint8_t flags;
uint8_t subopt_type;
uip_ipaddr_t prefix;
uint8_t buffer_length;
int pos;
int len;
int i;
prefixlen = 0;
uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
memset(&dao_parent_addr, 0, 16);
buffer = UIP_ICMP_PAYLOAD;
buffer_length = uip_len - uip_l3_icmp_hdr_len;
pos = 0;
instance_id = buffer[pos++];
instance = rpl_get_instance(instance_id);
lifetime = instance->default_lifetime;
flags = buffer[pos++];
/* reserved */
pos++;
sequence = buffer[pos++];
dag = instance->current_dag;
/* Is the DAG ID present? */
if(flags & RPL_DAO_D_FLAG) {
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
return;
}
pos += 16;
}
/* Check if there are any RPL options present. */
for(i = pos; i < buffer_length; i += len) {
subopt_type = buffer[i];
if(subopt_type == RPL_OPTION_PAD1) {
len = 1;
} else {
/* The option consists of a two-byte header and a payload. */
len = 2 + buffer[i + 1];
}
switch(subopt_type) {
case RPL_OPTION_TARGET:
/* Handle the target option. */
prefixlen = buffer[i + 3];
memset(&prefix, 0, sizeof(prefix));
memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
break;
case RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
/* pathcontrol = buffer[i + 3];
pathsequence = buffer[i + 4];*/
lifetime = buffer[i + 5];
if(len >= 20) {
memcpy(&dao_parent_addr, buffer + i + 6, 16);
}
break;
}
}
PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
(unsigned)lifetime, (unsigned)prefixlen);
PRINT6ADDR(&prefix);
PRINTF(", parent: ");
PRINT6ADDR(&dao_parent_addr);
PRINTF(" \n");
if(lifetime == RPL_ZERO_LIFETIME) {
PRINTF("RPL: No-Path DAO received\n");
rpl_ns_expire_parent(dag, &prefix, &dao_parent_addr);
} else {
if(rpl_ns_update_node(dag, &prefix, &dao_parent_addr, RPL_LIFETIME(instance, lifetime)) == NULL) {
PRINTF("RPL: failed to add link\n");
return;
}
}
if(flags & RPL_DAO_K_FLAG) {
PRINTF("RPL: Sending DAO ACK\n");
uip_clear_buf();
dao_ack_output(instance, &dao_sender_addr, sequence,
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
#endif /* RPL_WITH_NON_STORING */
}
/*---------------------------------------------------------------------------*/
static void
dao_input(void)
{
rpl_instance_t *instance;
uint8_t instance_id;
/* Destination Advertisement Object */
PRINTF("RPL: Received a DAO from ");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
instance_id = UIP_ICMP_PAYLOAD[0];
instance = rpl_get_instance(instance_id);
if(instance == NULL) {
PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
instance_id);
goto discard;
}
if(instance->mop != RPL_MOP_NON_STORING) {
if(RPL_IS_STORING(instance)) {
dao_input_storing();
}
} else {
if(RPL_IS_NON_STORING(instance)) {
dao_input_nonstoring();
}
}
discard:
uip_clear_buf();
@ -1006,6 +1140,8 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
unsigned char *buffer;
uint8_t prefixlen;
int pos;
uip_ipaddr_t *parent_ipaddr = NULL;
uip_ipaddr_t *dest_ipaddr = NULL;
/* Destination Advertisement Object */
@ -1019,6 +1155,12 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
return;
}
parent_ipaddr = rpl_get_parent_ipaddr(parent);
if(parent_ipaddr == NULL) {
PRINTF("RPL dao_output_target error parent IP address NULL\n");
return;
}
dag = parent->dag;
if(dag == NULL) {
PRINTF("RPL dao_output_target error dag NULL\n");
@ -1071,21 +1213,37 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
/* Create a transit information sub-option. */
buffer[pos++] = RPL_OPTION_TRANSIT;
buffer[pos++] = 4;
buffer[pos++] = (instance->mop != RPL_MOP_NON_STORING) ? 4 : 20;
buffer[pos++] = 0; /* flags - ignored */
buffer[pos++] = 0; /* path control - ignored */
buffer[pos++] = 0; /* path seq - ignored */
buffer[pos++] = lifetime;
if(instance->mop != RPL_MOP_NON_STORING) {
/* Send DAO to parent */
dest_ipaddr = parent_ipaddr;
} else {
/* Include parent global IP address */
memcpy(buffer + pos, &parent->dag->dag_id, 8); /* Prefix */
pos += 8;
memcpy(buffer + pos, ((const unsigned char *)parent_ipaddr) + 8, 8); /* Interface identifier */
pos += 8;
/* Send DAO to root */
dest_ipaddr = &parent->dag->dag_id;
}
PRINTF("RPL: Sending a %sDAO with sequence number %u, lifetime %u, prefix ",
lifetime == RPL_ZERO_LIFETIME ? "No-Path " : "", seq_no, lifetime);
PRINT6ADDR(prefix);
PRINTF(" to ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINT6ADDR(dest_ipaddr);
PRINTF(" , parent ");
PRINT6ADDR(parent_ipaddr);
PRINTF("\n");
if(rpl_get_parent_ipaddr(parent) != NULL) {
uip_icmp6_send(rpl_get_parent_ipaddr(parent), ICMP6_RPL, RPL_CODE_DAO, pos);
if(dest_ipaddr != NULL) {
uip_icmp6_send(dest_ipaddr, ICMP6_RPL, RPL_CODE_DAO, pos);
}
}
/*---------------------------------------------------------------------------*/