Changes in RPL implementation :
- Structural modification of RPL data storage. - Support multiple gateways (multiple DODAG-ID with a unique InstanceID) - Use Lollipop counters - Add leaf-only configuration option for RPL Bugfix : - Correctly send "Grounded" flag in DIO
This commit is contained in:
parent
2ac91d53b5
commit
dc9cbe647d
15 changed files with 1497 additions and 555 deletions
|
@ -72,7 +72,7 @@ static void dio_input(void);
|
|||
static void dao_input(void);
|
||||
static void dao_ack_input(void);
|
||||
|
||||
static uint8_t dao_sequence;
|
||||
static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
get_global_addr(uip_ipaddr_t *addr)
|
||||
|
@ -112,21 +112,27 @@ set32(uint8_t *buffer, int pos, uint32_t value)
|
|||
static void
|
||||
dis_input(void)
|
||||
{
|
||||
rpl_dag_t *dag;
|
||||
rpl_instance_t *instance;
|
||||
rpl_instance_t *end;
|
||||
|
||||
/* DAG Information Solicitation */
|
||||
PRINTF("RPL: Received a DIS from ");
|
||||
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||
PRINTF("\n");
|
||||
|
||||
dag = rpl_get_dag(RPL_ANY_INSTANCE);
|
||||
if(dag != NULL) {
|
||||
if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
PRINTF("RPL: Multicast DIS => reset DIO timer\n");
|
||||
rpl_reset_dio_timer(dag, 0);
|
||||
} else {
|
||||
PRINTF("RPL: Unicast DIS, reply to sender\n");
|
||||
dio_output(dag, &UIP_IP_BUF->srcipaddr);
|
||||
for( instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
|
||||
if ( instance->used == 1 ) {
|
||||
#if RPL_LEAF_ONLY
|
||||
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
#else /* !RPL_LEAF_ONLY */
|
||||
if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
PRINTF("RPL: Multicast DIS => reset DIO timer\n");
|
||||
rpl_reset_dio_timer(instance, 0);
|
||||
} else {
|
||||
#endif /* !RPL_LEAF_ONLY */
|
||||
PRINTF("RPL: Unicast DIS, reply to sender\n");
|
||||
dio_output(instance, &UIP_IP_BUF->srcipaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +205,7 @@ dio_input(void)
|
|||
buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
|
||||
|
||||
#if RPL_CONF_ADJUST_LLH_LEN
|
||||
buffer_length+=UIP_LLH_LEN; //Add jackdaw, minimal-net ethernet header
|
||||
buffer_length += UIP_LLH_LEN; /* Add jackdaw, minimal-net ethernet header */
|
||||
#endif
|
||||
|
||||
/* Process the DIO base option. */
|
||||
|
@ -211,6 +217,7 @@ dio_input(void)
|
|||
dio.rank = (buffer[i] << 8) | buffer[i + 1];
|
||||
i += 2;
|
||||
|
||||
PRINTF("RPL: Incoming DIO InstanceID-Version %u-%u\n", (unsigned)dio.instance_id,(unsigned)dio.version);
|
||||
PRINTF("RPL: Incoming DIO rank %u\n", (unsigned)dio.rank);
|
||||
|
||||
dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
|
||||
|
@ -224,6 +231,10 @@ dio_input(void)
|
|||
memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
|
||||
i += sizeof(dio.dag_id);
|
||||
|
||||
PRINTF("RPL: Incoming DIO DODAG ");
|
||||
PRINT6ADDR(&dio.dag_id);
|
||||
PRINTF(" preference : %u\n",dio.preference);
|
||||
|
||||
/* Check if there are any DIO suboptions. */
|
||||
for(; i < buffer_length; i += len) {
|
||||
subopt_type = buffer[i];
|
||||
|
@ -249,7 +260,6 @@ dio_input(void)
|
|||
RPL_STAT(rpl_stats.malformed_msgs++);
|
||||
return;
|
||||
}
|
||||
|
||||
dio.mc.type = buffer[i + 2];
|
||||
dio.mc.flags = buffer[i + 3] << 1;
|
||||
dio.mc.flags |= buffer[i + 4] >> 7;
|
||||
|
@ -347,30 +357,50 @@ dio_input(void)
|
|||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
|
||||
dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
int pos;
|
||||
#if !RPL_LEAF_ONLY
|
||||
uip_ipaddr_t addr;
|
||||
#endif /* !RPL_LEAF_ONLY */
|
||||
|
||||
#if RPL_LEAF_ONLY
|
||||
/* only respond to unicast DIS */
|
||||
if(uc_addr == NULL) {
|
||||
return;
|
||||
}
|
||||
#endif /* RPL_LEAF_ONLY */
|
||||
|
||||
rpl_dag_t *dag = instance->current_dag;
|
||||
|
||||
/* DAG Information Object */
|
||||
pos = 0;
|
||||
|
||||
buffer = UIP_ICMP_PAYLOAD;
|
||||
buffer[pos++] = dag->instance_id;
|
||||
buffer[pos++] = instance->instance_id;
|
||||
buffer[pos++] = dag->version;
|
||||
#if RPL_LEAF_ONLY
|
||||
buffer[pos++] = INFINITE_RANK >> 8;
|
||||
buffer[pos++] = INFINITE_RANK & 0xff;
|
||||
#else /* RPL_LEAF_ONLY */
|
||||
buffer[pos++] = dag->rank >> 8;
|
||||
buffer[pos++] = dag->rank & 0xff;
|
||||
#endif /* RPL_LEAF_ONLY */
|
||||
|
||||
buffer[pos] = 0;
|
||||
if(dag->grounded) {
|
||||
buffer[pos] |= RPL_DIO_GROUNDED;
|
||||
}
|
||||
|
||||
buffer[pos] = dag->mop << RPL_DIO_MOP_SHIFT;
|
||||
buffer[pos] |= instance->mop << RPL_DIO_MOP_SHIFT;
|
||||
buffer[pos] |= dag->preference & RPL_DIO_PREFERENCE_MASK;
|
||||
pos++;
|
||||
|
||||
buffer[pos++] = ++dag->dtsn_out;
|
||||
buffer[pos++] = instance->dtsn_out;
|
||||
|
||||
if (RPL_LOLLIPOP_IS_INIT(instance->dtsn_out))
|
||||
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
|
||||
|
||||
/* reserved 2 bytes */
|
||||
buffer[pos++] = 0; /* flags */
|
||||
|
@ -379,49 +409,51 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
|
|||
memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
|
||||
pos += 16;
|
||||
|
||||
if(dag->mc.type != RPL_DAG_MC_NONE) {
|
||||
dag->of->update_metric_container(dag);
|
||||
#if !RPL_LEAF_ONLY
|
||||
if(instance->mc.type != RPL_DAG_MC_NONE) {
|
||||
instance->of->update_metric_container(instance);
|
||||
|
||||
buffer[pos++] = RPL_DIO_SUBOPT_DAG_METRIC_CONTAINER;
|
||||
buffer[pos++] = 6;
|
||||
buffer[pos++] = dag->mc.type;
|
||||
buffer[pos++] = dag->mc.flags >> 1;
|
||||
buffer[pos] = (dag->mc.flags & 1) << 7;
|
||||
buffer[pos++] |= (dag->mc.aggr << 4) | dag->mc.prec;
|
||||
|
||||
if(dag->mc.type == RPL_DAG_MC_ETX) {
|
||||
buffer[pos++] = instance->mc.type;
|
||||
buffer[pos++] = instance->mc.flags >> 1;
|
||||
buffer[pos] = (instance->mc.flags & 1) << 7;
|
||||
buffer[pos++] |= (instance->mc.aggr << 4) | instance->mc.prec;
|
||||
if(instance->mc.type == RPL_DAG_MC_ETX) {
|
||||
buffer[pos++] = 2;
|
||||
buffer[pos++] = dag->mc.obj.etx >> 8;
|
||||
buffer[pos++] = dag->mc.obj.etx & 0xff;
|
||||
} else if(dag->mc.type == RPL_DAG_MC_ENERGY) {
|
||||
buffer[pos++] = instance->mc.obj.etx >> 8;
|
||||
buffer[pos++] = instance->mc.obj.etx & 0xff;
|
||||
} else if(instance->mc.type == RPL_DAG_MC_ENERGY) {
|
||||
buffer[pos++] = 2;
|
||||
buffer[pos++] = dag->mc.obj.energy.flags;
|
||||
buffer[pos++] = dag->mc.obj.energy.energy_est;
|
||||
buffer[pos++] = instance->mc.obj.energy.flags;
|
||||
buffer[pos++] = instance->mc.obj.energy.energy_est;
|
||||
} else {
|
||||
PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type %u\n",
|
||||
(unsigned)dag->mc.type);
|
||||
(unsigned)instance->mc.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always add a sub-option for DAG configuration. */
|
||||
#endif /* RPL_LEAF_ONLY */
|
||||
|
||||
/* Always add a sub-option for DAG configuration */
|
||||
buffer[pos++] = RPL_DIO_SUBOPT_DAG_CONF;
|
||||
buffer[pos++] = 14;
|
||||
buffer[pos++] = 0; /* No Auth, PCS = 0 */
|
||||
buffer[pos++] = dag->dio_intdoubl;
|
||||
buffer[pos++] = dag->dio_intmin;
|
||||
buffer[pos++] = dag->dio_redundancy;
|
||||
buffer[pos++] = dag->max_rankinc >> 8;
|
||||
buffer[pos++] = dag->max_rankinc & 0xff;
|
||||
buffer[pos++] = dag->min_hoprankinc >> 8;
|
||||
buffer[pos++] = dag->min_hoprankinc & 0xff;
|
||||
buffer[pos++] = instance->dio_intdoubl;
|
||||
buffer[pos++] = instance->dio_intmin;
|
||||
buffer[pos++] = instance->dio_redundancy;
|
||||
buffer[pos++] = instance->max_rankinc >> 8;
|
||||
buffer[pos++] = instance->max_rankinc & 0xff;
|
||||
buffer[pos++] = instance->min_hoprankinc >> 8;
|
||||
buffer[pos++] = instance->min_hoprankinc & 0xff;
|
||||
/* OCP is in the DAG_CONF option */
|
||||
buffer[pos++] = dag->of->ocp >> 8;
|
||||
buffer[pos++] = dag->of->ocp & 0xff;
|
||||
buffer[pos++] = instance->of->ocp >> 8;
|
||||
buffer[pos++] = instance->of->ocp & 0xff;
|
||||
buffer[pos++] = 0; /* reserved */
|
||||
buffer[pos++] = dag->default_lifetime;
|
||||
buffer[pos++] = dag->lifetime_unit >> 8;
|
||||
buffer[pos++] = dag->lifetime_unit & 0xff;
|
||||
buffer[pos++] = instance->default_lifetime;
|
||||
buffer[pos++] = instance->lifetime_unit >> 8;
|
||||
buffer[pos++] = instance->lifetime_unit & 0xff;
|
||||
|
||||
/* Check if we have a prefix to send also. */
|
||||
if(dag->prefix_info.length > 0) {
|
||||
|
@ -445,19 +477,27 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
|
|||
dag->prefix_info.length);
|
||||
}
|
||||
|
||||
#if RPL_LEAF_ONLY
|
||||
PRINTF("RPL: Sending unicast-DIO with rank %u to ",
|
||||
(unsigned)dag->rank);
|
||||
PRINT6ADDR(uc_addr);
|
||||
PRINTF("\n");
|
||||
uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
|
||||
#else /* RPL_LEAF_ONLY */
|
||||
/* Unicast requests get unicast replies! */
|
||||
if(uc_addr == NULL) {
|
||||
PRINTF("RPL: Sending a multicast-DIO with rank %u\n",
|
||||
(unsigned)dag->rank);
|
||||
(unsigned)instance->current_dag->rank);
|
||||
uip_create_linklocal_rplnodes_mcast(&addr);
|
||||
uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DIO, pos);
|
||||
} else {
|
||||
PRINTF("RPL: Sending unicast-DIO with rank %u to ",
|
||||
(unsigned)dag->rank);
|
||||
(unsigned)instance->current_dag->rank);
|
||||
PRINT6ADDR(uc_addr);
|
||||
PRINTF("\n");
|
||||
uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
|
||||
}
|
||||
#endif /* RPL_LEAF_ONLY */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
|
@ -465,10 +505,11 @@ dao_input(void)
|
|||
{
|
||||
uip_ipaddr_t dao_sender_addr;
|
||||
rpl_dag_t *dag;
|
||||
rpl_instance_t *instance;
|
||||
unsigned char *buffer;
|
||||
uint16_t sequence;
|
||||
uint8_t instance_id;
|
||||
rpl_lifetime_t lifetime;
|
||||
uint8_t lifetime;
|
||||
uint8_t prefixlen;
|
||||
uint8_t flags;
|
||||
uint8_t subopt_type;
|
||||
|
@ -494,32 +535,37 @@ dao_input(void)
|
|||
|
||||
buffer = UIP_ICMP_PAYLOAD;
|
||||
buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
|
||||
|
||||
#if RPL_CONF_ADJUST_LLH_LEN
|
||||
buffer_length += UIP_LLH_LEN; /* Add jackdaw, minimal-net ethernet header */
|
||||
#endif
|
||||
|
||||
pos = 0;
|
||||
instance_id = buffer[pos++];
|
||||
|
||||
dag = rpl_get_dag(instance_id);
|
||||
if(dag == NULL) {
|
||||
PRINTF("RPL: Ignoring a DAO for a different RPL instance (%u)\n",
|
||||
instance = rpl_get_instance(instance_id);
|
||||
if(instance == NULL) {
|
||||
PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
|
||||
instance_id);
|
||||
return;
|
||||
}
|
||||
|
||||
lifetime = dag->default_lifetime;
|
||||
lifetime = instance->default_lifetime;
|
||||
|
||||
flags = buffer[pos++];
|
||||
/* reserved */
|
||||
pos++;
|
||||
sequence = buffer[pos++];
|
||||
|
||||
dag = instance->current_dag;
|
||||
/* Is the DAGID present? */
|
||||
if(flags & RPL_DAO_D_FLAG) {
|
||||
/* Currently the DAG ID is ignored since we only use global
|
||||
RPL Instance IDs. */
|
||||
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
|
||||
PRINTF("RPL: Ignoring a DAO for a DODAG different from ours\n");
|
||||
return;
|
||||
}
|
||||
pos += 16;
|
||||
} else {
|
||||
/* Perhaps, there are verification to do but ... */
|
||||
}
|
||||
|
||||
/* Check if there are any DIO sub-options. */
|
||||
|
@ -529,7 +575,7 @@ dao_input(void)
|
|||
if(subopt_type == RPL_DIO_SUBOPT_PAD1) {
|
||||
len = 1;
|
||||
} else {
|
||||
/* Sub-option with a two-byte header and payload */
|
||||
/* Sub-option with a two-byte header + payload */
|
||||
len = 2 + buffer[i + 1];
|
||||
}
|
||||
|
||||
|
@ -551,7 +597,7 @@ dao_input(void)
|
|||
}
|
||||
|
||||
PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
|
||||
(unsigned)lifetime, (unsigned)prefixlen);
|
||||
(unsigned)lifetime, (unsigned)prefixlen);
|
||||
PRINT6ADDR(&prefix);
|
||||
PRINTF("\n");
|
||||
|
||||
|
@ -559,7 +605,7 @@ dao_input(void)
|
|||
|
||||
if(lifetime == ZERO_LIFETIME) {
|
||||
/* No-Path DAO received; invoke the route purging routine. */
|
||||
if(rep != NULL && rep->state.saved_lifetime == 0) {
|
||||
if(rep != NULL && rep->state.saved_lifetime == 0 && rep->length==prefixlen) {
|
||||
PRINTF("RPL: Setting expiration timer for prefix ");
|
||||
PRINT6ADDR(&prefix);
|
||||
PRINTF("\n");
|
||||
|
@ -575,9 +621,11 @@ dao_input(void)
|
|||
if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
|
||||
/* Check whether this is a DAO forwarding loop. */
|
||||
p = rpl_find_parent(dag, &dao_sender_addr);
|
||||
if(p != NULL && DAG_RANK(p->rank, dag) < DAG_RANK(dag->rank, dag)) {
|
||||
/* check if this is a new DAO registration with an "illegal" rank */
|
||||
/* if we already route to this node it is likely */
|
||||
if(p != NULL && DAG_RANK(p->rank, instance) < DAG_RANK(dag->rank, instance)) {
|
||||
PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
|
||||
DAG_RANK(p->rank, dag), DAG_RANK(dag->rank, dag));
|
||||
DAG_RANK(p->rank, instance), DAG_RANK(dag->rank, instance));
|
||||
p->rank = INFINITE_RANK;
|
||||
p->updated = 1;
|
||||
return;
|
||||
|
@ -593,7 +641,7 @@ dao_input(void)
|
|||
}
|
||||
}
|
||||
|
||||
rep->state.lifetime = RPL_LIFETIME(dag, lifetime);
|
||||
rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
|
||||
rep->state.learned_from = learned_from;
|
||||
|
||||
if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
|
||||
|
@ -603,16 +651,18 @@ dao_input(void)
|
|||
PRINTF("\n");
|
||||
uip_icmp6_send(&dag->preferred_parent->addr,
|
||||
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
|
||||
} else if(flags & RPL_DAO_K_FLAG) {
|
||||
dao_ack_output(dag, &dao_sender_addr, sequence);
|
||||
}
|
||||
if(flags & RPL_DAO_K_FLAG) {
|
||||
dao_ack_output(instance, &dao_sender_addr, sequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dao_output(rpl_parent_t *n, rpl_lifetime_t lifetime)
|
||||
dao_output(rpl_parent_t *n, uint8_t lifetime)
|
||||
{
|
||||
rpl_dag_t *dag;
|
||||
rpl_instance_t *instance;
|
||||
unsigned char *buffer;
|
||||
uint8_t prefixlen;
|
||||
uip_ipaddr_t addr;
|
||||
|
@ -626,7 +676,7 @@ dao_output(rpl_parent_t *n, rpl_lifetime_t lifetime)
|
|||
}
|
||||
|
||||
if(n == NULL) {
|
||||
dag = rpl_get_dag(RPL_ANY_INSTANCE);
|
||||
dag = rpl_get_any_dag();
|
||||
if(dag == NULL) {
|
||||
PRINTF("RPL: Did not join a DAG before sending DAO\n");
|
||||
return;
|
||||
|
@ -635,19 +685,28 @@ dao_output(rpl_parent_t *n, rpl_lifetime_t lifetime)
|
|||
dag = n->dag;
|
||||
}
|
||||
|
||||
instance = dag->instance;
|
||||
|
||||
buffer = UIP_ICMP_PAYLOAD;
|
||||
|
||||
++dao_sequence;
|
||||
RPL_LOLLIPOP_INCREMENT(dao_sequence);
|
||||
pos = 0;
|
||||
|
||||
buffer[pos++] = dag->instance_id;
|
||||
buffer[pos++] = instance->instance_id;
|
||||
buffer[pos] = 0;
|
||||
#if RPL_DAO_SPECIFY_DODAG
|
||||
buffer[pos] |= RPL_DAO_D_FLAG;
|
||||
#endif /* RPL_DAO_SPECIFY_DODAG */
|
||||
#if RPL_CONF_DAO_ACK
|
||||
buffer[pos++] = RPL_DAO_K_FLAG; /* DAO ACK request, no DODAGID */
|
||||
#else
|
||||
buffer[pos++] = 0; /* No DAO ACK request, no DODAGID */
|
||||
#endif
|
||||
buffer[pos] |= RPL_DAO_K_FLAG;
|
||||
#endif /* RPL_CONF_DAO_ACK */
|
||||
++pos;
|
||||
buffer[pos++] = 0; /* reserved */
|
||||
buffer[pos++] = dao_sequence & 0xff;
|
||||
buffer[pos++] = dao_sequence;
|
||||
#if RPL_DAO_SPECIFY_DODAG
|
||||
memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
|
||||
pos+=sizeof(dag->dag_id);
|
||||
#endif /* RPL_DAO_SPECIFY_DODAG */
|
||||
|
||||
/* create target subopt */
|
||||
prefixlen = sizeof(prefix) * CHAR_BIT;
|
||||
|
@ -696,9 +755,6 @@ dao_ack_input(void)
|
|||
|
||||
buffer = UIP_ICMP_PAYLOAD;
|
||||
buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
|
||||
#if RPL_CONF_ADJUST_LLH_LEN
|
||||
buffer_length+=UIP_LLH_LEN; //Add jackdaw, minimal-net ethernet header
|
||||
#endif
|
||||
|
||||
instance_id = buffer[0];
|
||||
sequence = buffer[2];
|
||||
|
@ -711,7 +767,7 @@ dao_ack_input(void)
|
|||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dao_ack_output(rpl_dag_t *dag, uip_ipaddr_t *dest, uint8_t sequence)
|
||||
dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
|
||||
|
@ -721,7 +777,7 @@ dao_ack_output(rpl_dag_t *dag, uip_ipaddr_t *dest, uint8_t sequence)
|
|||
|
||||
buffer = UIP_ICMP_PAYLOAD;
|
||||
|
||||
buffer[0] = dag->instance_id;
|
||||
buffer[0] = instance->instance_id;
|
||||
buffer[1] = 0;
|
||||
buffer[2] = sequence;
|
||||
buffer[3] = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue