Fix and cleanup RPL ext header handling

This commit is contained in:
Simon Duquennoy 2016-06-13 12:04:19 +02:00
parent e584a54608
commit d73b229624
3 changed files with 68 additions and 154 deletions

View File

@ -549,7 +549,12 @@ tcpip_ipv6_output(void)
} }
#if UIP_CONF_IPV6_RPL #if UIP_CONF_IPV6_RPL
rpl_insert_header(); if(!rpl_update_header()) {
/* Packet can not be forwarded */
PRINTF("tcpip_ipv6_output: RPL header update error\n");
uip_clear_buf();
return;
}
#endif /* UIP_CONF_IPV6_RPL */ #endif /* UIP_CONF_IPV6_RPL */
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
@ -655,12 +660,6 @@ tcpip_ipv6_output(void)
/* End of next hop determination */ /* End of next hop determination */
#if UIP_CONF_IPV6_RPL
if(!rpl_finalize_header(nexthop)) {
uip_clear_buf();
return;
}
#endif /* UIP_CONF_IPV6_RPL */
nbr = uip_ds6_nbr_lookup(nexthop); nbr = uip_ds6_nbr_lookup(nexthop);
if(nbr == NULL) { if(nbr == NULL) {
#if UIP_ND6_SEND_NA #if UIP_ND6_SEND_NA

View File

@ -890,7 +890,7 @@ ext_hdr_options_process(void)
*/ */
#if UIP_CONF_IPV6_RPL #if UIP_CONF_IPV6_RPL
PRINTF("Processing RPL option\n"); PRINTF("Processing RPL option\n");
if(rpl_verify_hbh_header(uip_ext_opt_offset)) { if(!rpl_verify_hbh_header(uip_ext_opt_offset)) {
PRINTF("RPL Option Error: Dropping Packet\n"); PRINTF("RPL Option Error: Dropping Packet\n");
return 1; return 1;
} }
@ -1228,14 +1228,6 @@ uip_process(uint8_t flag)
goto send; goto send;
} }
#if UIP_CONF_IPV6_RPL
if(!rpl_update_header()) {
/* Packet can not be forwarded */
PRINTF("RPL header update error\n");
goto drop;
}
#endif /* UIP_CONF_IPV6_RPL */
UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1; UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1;
PRINTF("Forwarding packet to "); PRINTF("Forwarding packet to ");
PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINT6ADDR(&UIP_IP_BUF->destipaddr);

View File

@ -78,26 +78,22 @@ rpl_verify_hbh_header(int uip_ext_opt_offset)
uip_ds6_route_t *route; uip_ds6_route_t *route;
rpl_parent_t *sender = NULL; rpl_parent_t *sender = NULL;
if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)) { if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
PRINTF("RPL: Hop-by-hop extension header has wrong size\n"); || UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL
return 1; || UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
}
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) { PRINTF("RPL: Hop-by-hop extension header has wrong size or type (%u %u %u)\n",
PRINTF("RPL: Non RPL Hop-by-hop option\n"); UIP_HBHO_BUF->len,
return 1; UIP_EXT_HDR_OPT_RPL_BUF->opt_type,
} UIP_EXT_HDR_OPT_RPL_BUF->opt_len);
return 0; /* Drop */
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
PRINTF("RPL: Bad header option! (wrong length)\n");
return 1;
} }
instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
if(instance == NULL) { if(instance == NULL) {
PRINTF("RPL: Unknown instance: %u\n", PRINTF("RPL: Unknown instance: %u\n",
UIP_EXT_HDR_OPT_RPL_BUF->instance); UIP_EXT_HDR_OPT_RPL_BUF->instance);
return 1; return 0;
} }
if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
@ -116,14 +112,13 @@ rpl_verify_hbh_header(int uip_ext_opt_offset)
/* Trigger DAO retransmission */ /* Trigger DAO retransmission */
rpl_reset_dio_timer(instance); rpl_reset_dio_timer(instance);
/* drop the packet as it is not routable */ /* drop the packet as it is not routable */
return 1; return 0;
} }
if(!instance->current_dag->joined) { if(!instance->current_dag->joined) {
PRINTF("RPL: No DAG in the instance\n"); PRINTF("RPL: No DAG in the instance\n");
return 1; return 0;
} }
down = 0; down = 0;
if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) { if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) {
down = 1; down = 1;
@ -167,16 +162,16 @@ rpl_verify_hbh_header(int uip_ext_opt_offset)
PRINTF("RPL: Rank error signalled in RPL option!\n"); PRINTF("RPL: Rank error signalled in RPL option!\n");
/* Packet must be dropped and dio trickle timer reset, see RFC6550 - 11.2.2.2 */ /* Packet must be dropped and dio trickle timer reset, see RFC6550 - 11.2.2.2 */
rpl_reset_dio_timer(instance); rpl_reset_dio_timer(instance);
return 1; return 0;
} }
PRINTF("RPL: Single error tolerated\n"); PRINTF("RPL: Single error tolerated\n");
RPL_STAT(rpl_stats.loop_warnings++); RPL_STAT(rpl_stats.loop_warnings++);
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR; UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR;
return 0; return 1;
} }
PRINTF("RPL: Rank OK\n"); PRINTF("RPL: Rank OK\n");
return 0; return 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if RPL_WITH_NON_STORING #if RPL_WITH_NON_STORING
@ -482,52 +477,39 @@ update_hbh_header(void)
uip_ext_len = 0; uip_ext_len = 0;
uip_ext_opt_offset = 2; uip_ext_opt_offset = 2;
PRINTF("RPL: Verifying the presence of the RPL header option\n"); if(UIP_IP_BUF->proto == UIP_PROTO_HBHO && UIP_EXT_HDR_OPT_RPL_BUF->opt_type == UIP_EXT_HDR_OPT_RPL) {
if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
|| UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
switch(UIP_IP_BUF->proto) { PRINTF("RPL: Hop-by-hop extension header has wrong size (%u %u)\n",
case UIP_PROTO_HBHO: UIP_EXT_HDR_OPT_RPL_BUF->opt_len,
if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)) { uip_ext_len);
PRINTF("RPL: Hop-by-hop extension header has wrong size\n"); return 0; /* Drop */
uip_ext_len = last_uip_ext_len;
return 1;
}
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) {
PRINTF("RPL: Non RPL Hop-by-hop option support not implemented\n");
uip_ext_len = last_uip_ext_len;
return 1;
}
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
PRINTF("RPL: RPL Hop-by-hop option has wrong length\n");
uip_ext_len = last_uip_ext_len;
return 1;
} }
instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
if(instance == NULL || !instance->used || !instance->current_dag->joined) { if(instance == NULL || !instance->used || !instance->current_dag->joined) {
PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n"); PRINTF("RPL: Unable to add/update hop-by-hop extension header: incorrect instance\n");
return 1; uip_ext_len = last_uip_ext_len;
return 0; /* Drop */
} }
break;
default:
PRINTF("RPL: No hop-by-hop option found\n");
return 1;
}
switch(UIP_EXT_HDR_OPT_BUF->type) {
case UIP_EXT_HDR_OPT_RPL:
PRINTF("RPL: Updating RPL option\n"); PRINTF("RPL: Updating RPL option\n");
/* Update sender rank and instance, will update flags next */
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank); UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);
UIP_EXT_HDR_OPT_RPL_BUF->instance = instance->instance_id;
if(RPL_IS_STORING(instance)) { /* In non-storing mode, downwards traffic does not have the HBH option */ if(RPL_IS_STORING(instance)) { /* In non-storing mode, downwards traffic does not have the HBH option */
/* Check the direction of the down flag, as per Section 11.2.2.3, /* Check the direction of the down flag, as per Section 11.2.2.3,
which states that if a packet is going down it should in which states that if a packet is going down it should in
general not go back up again. If this happens, a general not go back up again. If this happens, a
RPL_HDR_OPT_FWD_ERR should be flagged. */ RPL_HDR_OPT_FWD_ERR should be flagged. */
if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) { if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) { if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR; UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
PRINTF("RPL forwarding error\n"); PRINTF("RPL forwarding error\n");
/* We should send back the packet to the originating parent, /* We should send back the packet to the originating parent,
but it is not feasible yet, so we send a No-Path DAO instead */ but it is not feasible yet, so we send a No-Path DAO instead */
PRINTF("RPL generate No-Path DAO\n"); PRINTF("RPL generate No-Path DAO\n");
parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
if(parent != NULL) { if(parent != NULL) {
@ -538,11 +520,11 @@ update_hbh_header(void)
} }
} else { } else {
/* Set the down extension flag correctly as described in Section /* Set the down extension flag correctly as described in Section
11.2 of RFC6550. If the packet progresses along a DAO route, 11.2 of RFC6550. If the packet progresses along a DAO route,
the down flag should be set. */ the down flag should be set. */
if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) { if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
/* No route was found, so this packet will go towards the RPL /* No route was found, so this packet will go towards the RPL
root. If so, we should not set the down flag. */ root. If so, we should not set the down flag. */
UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN; UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
PRINTF("RPL option going up\n"); PRINTF("RPL option going up\n");
} else { } else {
@ -552,18 +534,14 @@ update_hbh_header(void)
} }
} }
} }
uip_ext_len = last_uip_ext_len;
return 1;
default:
PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
uip_ext_len = last_uip_ext_len;
return 1;
} }
uip_ext_len = last_uip_ext_len;
return 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
insert_hbh_header(void) insert_hbh_header(const rpl_instance_t *instance)
{ {
int uip_ext_opt_offset; int uip_ext_opt_offset;
int last_uip_ext_len; int last_uip_ext_len;
@ -594,8 +572,8 @@ insert_hbh_header(void)
UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL; UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN; UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
UIP_EXT_HDR_OPT_RPL_BUF->flags = 0; UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
UIP_EXT_HDR_OPT_RPL_BUF->instance = 0; UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0; UIP_EXT_HDR_OPT_RPL_BUF->instance = instance->instance_id;
uip_len += RPL_HOP_BY_HOP_LEN; uip_len += RPL_HOP_BY_HOP_LEN;
temp_len = UIP_IP_BUF->len[1]; temp_len = UIP_IP_BUF->len[1];
UIP_IP_BUF->len[1] += RPL_HOP_BY_HOP_LEN; UIP_IP_BUF->len[1] += RPL_HOP_BY_HOP_LEN;
@ -604,44 +582,9 @@ insert_hbh_header(void)
} }
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN; uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
return 1;
}
/*---------------------------------------------------------------------------*/
int
rpl_finalize_header(uip_ipaddr_t *addr)
{
rpl_parent_t *parent;
int uip_ext_opt_offset;
int last_uip_ext_len;
last_uip_ext_len = uip_ext_len; /* Update header before returning */
uip_ext_len = 0; return update_hbh_header();
uip_ext_opt_offset = 2;
if(UIP_IP_BUF->proto == UIP_PROTO_HBHO) {
if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)) {
PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n");
uip_ext_len = last_uip_ext_len;
return 1;
}
if(UIP_EXT_HDR_OPT_BUF->type == UIP_EXT_HDR_OPT_RPL) {
if(UIP_EXT_HDR_OPT_RPL_BUF->senderrank == 0) {
PRINTF("RPL: Updating RPL option\n");
if(default_instance == NULL || !default_instance->used || !default_instance->current_dag->joined) {
PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect default instance\n");
return 0;
}
parent = rpl_find_parent(default_instance->current_dag, addr);
if(parent == NULL || parent != parent->dag->preferred_parent) {
UIP_EXT_HDR_OPT_RPL_BUF->flags = RPL_HDR_OPT_DOWN;
}
UIP_EXT_HDR_OPT_RPL_BUF->instance = default_instance->instance_id;
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(default_instance->current_dag->rank);
}
}
}
return 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
@ -654,8 +597,6 @@ rpl_remove_header(void)
uip_ext_len = 0; uip_ext_len = 0;
uip_next_hdr = &UIP_IP_BUF->proto; uip_next_hdr = &UIP_IP_BUF->proto;
PRINTF("RPL: Verifying the presence of RPL extension headers\n");
/* Look for hop-by-hop and routing headers */ /* Look for hop-by-hop and routing headers */
while(uip_next_hdr != NULL) { while(uip_next_hdr != NULL) {
switch(*uip_next_hdr) { switch(*uip_next_hdr) {
@ -691,51 +632,33 @@ rpl_remove_header(void)
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void
rpl_insert_header(void)
{
if(default_instance == NULL || default_instance->current_dag == NULL
|| uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) || uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
return;
}
if(RPL_IS_STORING(default_instance)) {
insert_hbh_header();
}
if(RPL_IS_NON_STORING(default_instance)) {
if(default_instance->current_dag != NULL) {
if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
insert_srh_header();
} else {
insert_hbh_header();
}
}
}
}
/*---------------------------------------------------------------------------*/
int int
rpl_update_header(void) rpl_update_header(void)
{ {
if(default_instance == NULL) { if(default_instance == NULL || default_instance->current_dag == NULL
return 0; || uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) || uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
return 1;
} }
if(default_instance->current_dag != NULL) { if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) { /* At the root, remove headers if any, and insert SRH or HBH
/* At the root, remove headers if any, and insert SRH or HBH * (SRH is inserted only if the destination is in the DODAG) */
* (SRH is inserted only if the destination is in the DODAG) */ rpl_remove_header();
rpl_remove_header(); if(RPL_IS_NON_STORING(default_instance)) {
if(RPL_IS_NON_STORING(default_instance)) { return insert_srh_header();
return insert_srh_header();
} else {
return insert_hbh_header();
}
} else { } else {
return update_hbh_header(); return insert_hbh_header(default_instance);
} }
} else { } else {
return 0; if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)
&& UIP_IP_BUF->ttl == uip_ds6_if.cur_hop_limit) {
/* Insert HBH option at source. Checking the address is not sufficient because
* in non-storing mode, a packet may go up and then down the same path again */
return insert_hbh_header(default_instance);
} else {
/* Update HBH option at forwarders */
return update_hbh_header();
}
} }
} }