diff --git a/core/net/mac/framer-802154.c b/core/net/mac/framer-802154.c index ba566de78..a95685a8f 100644 --- a/core/net/mac/framer-802154.c +++ b/core/net/mac/framer-802154.c @@ -54,9 +54,24 @@ #define PRINTADDR(addr) #endif +/** \brief The sequence number (0x00 - 0xff) added to the transmitted + * data or MAC command frame. The default is a random value within + * the range. + */ static uint8_t mac_dsn; + static uint8_t initialized = 0; + +/** \brief The 16-bit identifier of the PAN on which the device is + * sending to. If this value is 0xffff, the device is not + * associated. + */ static const uint16_t mac_dst_pan_id = IEEE802154_PANID; + +/** \brief The 16-bit identifier of the PAN on which the device is + * operating. If this value is 0xffff, the device is not + * associated. + */ static const uint16_t mac_src_pan_id = IEEE802154_PANID; /*---------------------------------------------------------------------------*/ @@ -145,7 +160,7 @@ create(void) /* Set the source PAN ID to the global variable. */ params.src_pid = mac_src_pan_id; - + /* * Set up the source address using only the long address mode for * phase 1. diff --git a/core/net/neighbor-info.c b/core/net/neighbor-info.c index 35c072247..c9e8c4080 100644 --- a/core/net/neighbor-info.c +++ b/core/net/neighbor-info.c @@ -39,6 +39,8 @@ #include "net/neighbor-info.h" #include "net/neighbor-attr.h" +#include "net/uip-ds6.h" +#include "net/uip-nd6.h" #define DEBUG DEBUG_NONE #include "net/uip-debug.h" @@ -104,6 +106,9 @@ neighbor_info_packet_sent(int status, int numtx) { const rimeaddr_t *dest; link_metric_t packet_metric; +#if UIP_DS6_LL_NUD + uip_ds6_nbr_t *nbr; +#endif /* UIP_DS6_LL_NUD */ dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(rimeaddr_cmp(dest, &rimeaddr_null)) { @@ -119,6 +124,17 @@ neighbor_info_packet_sent(int status, int numtx) switch(status) { case MAC_TX_OK: add_neighbor(dest); +#if UIP_DS6_LL_NUD + nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest); + if(nbr != NULL && + (nbr->state == STALE || nbr->state == DELAY || nbr->state == PROBE)) { + nbr->state = REACHABLE; + stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000); + PRINTF("neighbor-info : received a link layer ACK : "); + PRINTLLADDR((uip_lladdr_t *)dest); + PRINTF(" is reachable.\n"); + } +#endif /* UIP_DS6_LL_NUD */ break; case MAC_TX_NOACK: packet_metric = ETX_NOACK_PENALTY; diff --git a/core/net/rpl/Makefile.rpl b/core/net/rpl/Makefile.rpl index 68f67f2bc..88d5c4775 100644 --- a/core/net/rpl/Makefile.rpl +++ b/core/net/rpl/Makefile.rpl @@ -1,2 +1,2 @@ CONTIKI_SOURCEFILES += rpl.c rpl-dag.c rpl-icmp6.c rpl-timers.c \ - rpl-of-etx.c + rpl-of-etx.c rpl-ext-header.c diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c old mode 100644 new mode 100755 index 00c3400d6..0ce3e0f87 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -60,19 +60,14 @@ /************************************************************************/ extern rpl_of_t RPL_OF; static rpl_of_t * const objective_functions[] = {&RPL_OF}; + /************************************************************************/ - -#ifndef RPL_CONF_MAX_DAG_ENTRIES -#define RPL_MAX_DAG_ENTRIES 2 +#ifndef RPL_CONF_MAX_PARENTS_PER_DODAG +#define RPL_MAX_PARENTS_PER_DODAG 8 #else -#define RPL_MAX_DAG_ENTRIES RPL_CONF_MAX_DAG_ENTRIES -#endif /* !RPL_CONF_MAX_DAG_ENTRIES */ - -#ifndef RPL_CONF_MAX_PARENTS -#define RPL_MAX_PARENTS 8 -#else -#define RPL_MAX_PARENTS RPL_CONF_MAX_PARENTS +#define RPL_MAX_PARENTS_PER_DODAG RPL_CONF_MAX_PARENTS_PER_DODAG #endif /* !RPL_CONF_MAX_PARENTS */ + /************************************************************************/ /* RPL definitions. */ @@ -96,9 +91,12 @@ static rpl_of_t * const objective_functions[] = {&RPL_OF}; /************************************************************************/ /* Allocate parents from the same static MEMB chunk to reduce memory waste. */ -MEMB(parent_memb, struct rpl_parent, RPL_MAX_PARENTS); +MEMB(parent_memb, struct rpl_parent, RPL_MAX_PARENTS_PER_DODAG*RPL_MAX_INSTANCES*RPL_MAX_DODAG_PER_INSTANCE); + +/************************************************************************/ +/* Allocate instance table. */ +rpl_instance_t instance_table[RPL_MAX_INSTANCES]; -static rpl_dag_t dag_table[RPL_MAX_DAG_ENTRIES]; /************************************************************************/ /* Remove DAG parents with a rank that is at least the same as minimum_rank. */ static void @@ -118,6 +116,22 @@ remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank) } /************************************************************************/ static void +nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank) +{ + rpl_parent_t *p, *p2; + + PRINTF("RPL: Removing parents (minimum rank %u)\n", + minimum_rank); + + for(p = list_head(dag->parents); p != NULL; p = p2) { + p2 = p->next; + if(p->rank >= minimum_rank) { + rpl_nullify_parent(dag, p); + } + } +} +/************************************************************************/ +static void remove_worst_parent(rpl_dag_t *dag, rpl_rank_t min_worst_rank) { rpl_parent_t *p, *worst; @@ -140,157 +154,312 @@ remove_worst_parent(rpl_dag_t *dag, rpl_rank_t min_worst_rank) } /************************************************************************/ static int -should_send_dao(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p) +should_send_dao(rpl_instance_t *instance, rpl_dio_t *dio, rpl_parent_t *p) { /* if MOP is set to no downward routes no DAO should be sent */ - if(dag->mop == RPL_MOP_NO_DOWNWARD_ROUTES) return 0; - return dio->dtsn != p->dtsn && p == dag->preferred_parent; + if(instance->mop == RPL_MOP_NO_DOWNWARD_ROUTES) { + return 0; + } + return p == instance->current_dag->preferred_parent && + (RPL_LOLLIPOP_GREATER_THAN(dio->dtsn, p->dtsn) || + ((RPL_LOLLIPOP_GREATER_THAN(p->dtsn, dio->dtsn)) && + RPL_LOLLIPOP_IS_INIT(dio->dtsn))); } /************************************************************************/ static int acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank) { return rank != INFINITE_RANK && - (dag->max_rankinc == 0 || - DAG_RANK(rank, dag) <= DAG_RANK(dag->min_rank + dag->max_rankinc, dag)); + ((dag->instance->max_rankinc == 0) || + DAG_RANK(rank, dag->instance) <= DAG_RANK(dag->min_rank + dag->instance->max_rankinc, dag->instance)); } /************************************************************************/ rpl_dag_t * -rpl_set_root(uip_ipaddr_t *dag_id) +rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) { rpl_dag_t *dag; - int version; + rpl_instance_t *instance; + uint8_t version; - version = -1; - dag = rpl_get_dag(RPL_DEFAULT_INSTANCE); + version = RPL_LOLLIPOP_INIT; + dag = rpl_get_dodag(instance_id, dag_id); if(dag != NULL) { - PRINTF("RPL: Dropping a joined DAG when setting this node as root"); version = dag->version; - rpl_free_dag(dag); + RPL_LOLLIPOP_INCREMENT(version); + PRINTF("RPL: Dropping a joined DAG when setting this node as root"); + if(dag == dag->instance->current_dag) { + dag->instance->current_dag = NULL; + } + rpl_free_dodag(dag); } - dag = rpl_alloc_dag(RPL_DEFAULT_INSTANCE); + dag = rpl_alloc_dodag(instance_id, dag_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG\n"); return NULL; } + instance = dag->instance; + + dag->version = version; dag->joined = 1; - dag->version = version + 1; dag->grounded = RPL_GROUNDED; - dag->mop = RPL_MOP_DEFAULT; - dag->of = &RPL_OF; + instance->mop = RPL_MOP_DEFAULT; + instance->of = &RPL_OF; dag->preferred_parent = NULL; - dag->dtsn_out = 1; /* Trigger DAOs from the beginning. */ memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); - dag->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS; - dag->dio_intmin = DEFAULT_DIO_INTERVAL_MIN; - dag->dio_redundancy = DEFAULT_DIO_REDUNDANCY; - dag->max_rankinc = DEFAULT_MAX_RANKINC; - dag->min_hoprankinc = DEFAULT_MIN_HOPRANKINC; + instance->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS; + instance->dio_intmin = DEFAULT_DIO_INTERVAL_MIN; + instance->dio_redundancy = DEFAULT_DIO_REDUNDANCY; + instance->max_rankinc = DEFAULT_MAX_RANKINC; + instance->min_hoprankinc = DEFAULT_MIN_HOPRANKINC; + instance->default_lifetime = RPL_DEFAULT_LIFETIME; + instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; - dag->default_lifetime = RPL_DEFAULT_LIFETIME; - dag->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; + dag->rank = ROOT_RANK(instance); - dag->rank = ROOT_RANK(dag); + if(instance->current_dag != dag && instance->current_dag != NULL) { + /* Remove routes installed by DAOs. */ + rpl_remove_routes(instance->current_dag); - dag->of->update_metric_container(dag); + instance->current_dag->joined = 0; + } + + instance->current_dag = dag; + instance->dtsn_out = RPL_LOLLIPOP_INIT; + instance->of->update_metric_container(instance); + default_instance = instance; PRINTF("RPL: Node set to be a DAG root with DAG ID "); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); - ANNOTATE("#A root=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]); + ANNOTATE("#A root=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); - - rpl_reset_dio_timer(dag, 1); + rpl_reset_dio_timer(instance, 1); return dag; } /************************************************************************/ int -rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, int len) +rpl_repair_root(uint8_t instance_id) { - if(len <= 128) { - memset(&dag->prefix_info.prefix, 0, 16); - memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8); - dag->prefix_info.length = len; - dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS; - PRINTF("RPL: Prefix set - will announce this in DIOs\n"); + rpl_instance_t * instance; + + instance = rpl_get_instance(instance_id); + if(instance == NULL) { + return 0; + } + + if(instance->current_dag->rank == ROOT_RANK(instance)) { + RPL_LOLLIPOP_INCREMENT(instance->current_dag->version); + RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); + rpl_reset_dio_timer(instance, 1); return 1; } return 0; } /************************************************************************/ -int -rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from) +static void +set_ip_from_prefix(uip_ipaddr_t *ipaddr, rpl_prefix_t *prefix) { - if(dag->def_route != NULL) { - PRINTF("RPL: Removing default route through "); - PRINT6ADDR(&dag->def_route->ipaddr); - PRINTF("\n"); - uip_ds6_defrt_rm(dag->def_route); + memset(ipaddr, 0, sizeof(uip_ipaddr_t)); + memcpy(ipaddr, &prefix->prefix, (prefix->length + 7) / 8); + uip_ds6_set_addr_iid(ipaddr, &uip_lladdr); +} +/************************************************************************/ +static void +check_prefix(rpl_prefix_t *last_prefix, rpl_prefix_t *new_prefix) +{ + uip_ipaddr_t ipaddr; + uip_ds6_addr_t *rep; + + if(last_prefix != NULL && new_prefix != NULL && + last_prefix->length == new_prefix->length && + uip_ipaddr_prefixcmp(&last_prefix->prefix, &new_prefix->prefix, new_prefix->length) && + last_prefix->flags == new_prefix->flags) { + /* Nothing has changed. */ + return; + } + + if(last_prefix != NULL) { + set_ip_from_prefix(&ipaddr, last_prefix); + rep = uip_ds6_addr_lookup(&ipaddr); + if(rep != NULL) { + PRINTF("RPL: removing global IP address "); + PRINT6ADDR(&ipaddr); + PRINTF("\n"); + uip_ds6_addr_rm(rep); + } + } + + if(new_prefix != NULL) { + set_ip_from_prefix(&ipaddr, new_prefix); + if(uip_ds6_addr_lookup(&ipaddr) == NULL) { + PRINTF("RPL: adding global IP address "); + PRINT6ADDR(&ipaddr); + PRINTF("\n"); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); + } + } +} +/************************************************************************/ +int +rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len) +{ + if(len > 128) { + return 0; + } + + memset(&dag->prefix_info.prefix, 0, sizeof(dag->prefix_info.prefix)); + memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8); + dag->prefix_info.length = len; + dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS; + PRINTF("RPL: Prefix set - will announce this in DIOs\n"); + /* Autoconfigure an address if this node does not already have an address + with this prefix. */ + check_prefix(NULL, &dag->prefix_info); + return 1; +} +/************************************************************************/ +int +rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from) +{ + if(instance->def_route != NULL) { + if(instance->def_route->isused) { + PRINTF("RPL: Removing default route through "); + PRINT6ADDR(&instance->def_route->ipaddr); + PRINTF("\n"); + uip_ds6_defrt_rm(instance->def_route); + } + instance->def_route = NULL; } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); - dag->def_route = uip_ds6_defrt_add(from, - RPL_LIFETIME(dag, - dag->default_lifetime)); - if(dag->def_route == NULL) { + instance->def_route = uip_ds6_defrt_add(from, + RPL_LIFETIME(instance, + instance->default_lifetime)); + if(instance->def_route == NULL) { return 0; } } - return 1; } /************************************************************************/ -rpl_dag_t * -rpl_alloc_dag(uint8_t instance_id) +rpl_instance_t * +rpl_alloc_instance(uint8_t instance_id) { - rpl_dag_t *dag; - rpl_dag_t *end; + rpl_instance_t *instance, *end; - for(dag = &dag_table[0], end = dag + RPL_MAX_DAG_ENTRIES; dag < end; dag++) { - if(dag->used == 0) { + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { + if(instance->used == 0) { + memset(instance, 0, sizeof(*instance)); + instance->instance_id = instance_id; + instance->def_route = NULL; + instance->used = 1; + return instance; + } + } + return NULL; +} +/************************************************************************/ +rpl_dag_t * +rpl_alloc_dodag(uint8_t instance_id, uip_ipaddr_t *dag_id) +{ + rpl_dag_t *dag, *end; + rpl_instance_t *instance; + + instance = rpl_get_instance(instance_id); + if(instance == NULL ) { + instance = rpl_alloc_instance(instance_id); + if(instance == NULL ) { + RPL_STAT(rpl_stats.mem_overflows++); + return NULL; + } + dag = &instance->dag_table[0]; + dag->parents = &dag->parent_list; + list_init(dag->parents); + dag->used = 1; + dag->rank = INFINITE_RANK; + dag->min_rank = INFINITE_RANK; + dag->instance = instance; + instance->current_dag = dag; + return dag; + } + + for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { + if(!dag->used) { memset(dag, 0, sizeof(*dag)); dag->parents = &dag->parent_list; list_init(dag->parents); - dag->instance_id = instance_id; - dag->def_route = NULL; + dag->used = 1; dag->rank = INFINITE_RANK; dag->min_rank = INFINITE_RANK; + dag->instance = instance; return dag; } } - - RPL_STAT(rpl_stats.mem_overflows++); return NULL; } /************************************************************************/ void -rpl_free_dag(rpl_dag_t *dag) +rpl_set_default_instance(rpl_instance_t *instance) { - PRINTF("RPL: Leaving the DAG "); - PRINT6ADDR(&dag->dag_id); - PRINTF("\n"); + default_instance = instance; +} +/************************************************************************/ +void +rpl_free_instance(rpl_instance_t *instance) +{ + rpl_dag_t *dag; + rpl_dag_t *end; - /* Remove routes installed by DAOs. */ - rpl_remove_routes(dag); + PRINTF("RPL: Leaving the instance %u\n", instance->instance_id); - /* Remove parents and the default route. */ - remove_parents(dag, 0); - rpl_set_default_route(dag, NULL); + /* Remove any DODAG inside this instance */ + for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { + if(dag->used) { + rpl_free_dodag(dag); + } + } - ctimer_stop(&dag->dio_timer); - ctimer_stop(&dag->dao_timer); + rpl_set_default_route(instance, NULL); + ctimer_stop(&instance->dio_timer); + ctimer_stop(&instance->dao_timer); + + if(default_instance == instance) { + default_instance = NULL; + } + + instance->used = 0; +} +/************************************************************************/ +void +rpl_free_dodag(rpl_dag_t *dag) +{ + if(dag->joined) { + PRINTF("RPL: Leaving the DAG "); + PRINT6ADDR(&dag->dag_id); + PRINTF("\n"); + dag->joined = 0; + + /* Remove routes installed by DAOs. */ + rpl_remove_routes(dag); + + /* Remove autoconfigured address */ + if((dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) { + check_prefix(&dag->prefix_info, NULL); + } + + remove_parents(dag, 0); + } dag->used = 0; - dag->joined = 0; } /************************************************************************/ rpl_parent_t * @@ -303,17 +472,13 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) RPL_STAT(rpl_stats.mem_overflows++); return NULL; } - memcpy(&p->addr, addr, sizeof(p->addr)); p->dag = dag; p->rank = dio->rank; + p->dtsn = dio->dtsn; p->link_metric = INITIAL_LINK_METRIC; - p->dtsn = 0; - memcpy(&p->mc, &dio->mc, sizeof(p->mc)); - list_add(dag->parents, p); - return p; } /************************************************************************/ @@ -327,16 +492,143 @@ rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr) return p; } } - return NULL; } +/************************************************************************/ +rpl_dag_t * +rpl_find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr) +{ + rpl_parent_t *p; + rpl_dag_t *dag, *end; + + for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { + if(dag->used) { + for(p = list_head(dag->parents); p != NULL; p = p->next) { + if(uip_ipaddr_cmp(&p->addr, addr)) { + return dag; + } + } + } + } + return NULL; +} +/************************************************************************/ +rpl_parent_t * +rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr) +{ + rpl_parent_t *p; + rpl_dag_t *dag, *end; + + for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { + if(dag->used) { + for(p = list_head(dag->parents); p != NULL; p = p->next) { + if(uip_ipaddr_cmp(&p->addr, addr)) { + return p; + } + } + } + } + return NULL; +} +/************************************************************************/ +rpl_dag_t * +rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p) +{ + rpl_parent_t *last_parent; + rpl_dag_t *dag, *end, *best_dag; + rpl_rank_t old_rank; + + old_rank = instance->current_dag->rank; + last_parent = instance->current_dag->preferred_parent; + + best_dag = instance->current_dag; + if(best_dag->rank != ROOT_RANK(instance)) { + if(rpl_select_parent(p->dag) != NULL) { + if(p->dag != best_dag) { + best_dag = instance->of->best_dag(best_dag, p->dag); + } + } else if(p->dag == best_dag) { + best_dag = NULL; + for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { + if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != INFINITE_RANK) { + if(best_dag == NULL) { + best_dag = dag; + } else { + best_dag = instance->of->best_dag(best_dag, dag); + } + } + } + } + } + + if(best_dag == NULL) { + /* No parent found: the calling function handle this problem. */ + return NULL; + } + + if(instance->current_dag != best_dag) { + /* Remove routes installed by DAOs. */ + rpl_remove_routes(instance->current_dag); + + PRINTF("RPL: New preferred DODAG: "); + PRINT6ADDR(&best_dag->dag_id); + PRINTF("\n"); + + if(best_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { + check_prefix(&instance->current_dag->prefix_info, &best_dag->prefix_info); + } else if(instance->current_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { + check_prefix(&instance->current_dag->prefix_info, NULL); + } + + best_dag->joined = 1; + instance->current_dag->joined = 0; + instance->current_dag = best_dag; + } + + instance->of->update_metric_container(instance); + /* Update the DAG rank. */ + best_dag->rank = instance->of->calculate_rank(best_dag->preferred_parent, 0); + if(best_dag->rank < best_dag->min_rank) { + best_dag->min_rank = best_dag->rank; + } else if(!acceptable_rank(best_dag, best_dag->rank)) { + PRINTF("RPL: New rank unacceptable!\n"); + instance->current_dag->preferred_parent = NULL; + if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) { + /* Send a No-Path DAO to the removed preferred parent. */ + dao_output(last_parent, ZERO_LIFETIME); + } + return NULL; + } + + if(best_dag->preferred_parent != last_parent) { + rpl_set_default_route(instance, &best_dag->preferred_parent->addr); + PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n", + (unsigned)old_rank, best_dag->rank); + RPL_STAT(rpl_stats.parent_switch++); + if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { + if(last_parent != NULL) { + /* Send a No-Path DAO to the removed preferred parent. */ + dao_output(last_parent, ZERO_LIFETIME); + } + /* The DAO parent set changed - schedule a DAO transmission. */ + RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); + rpl_schedule_dao(instance); + } + rpl_reset_dio_timer(instance, 1); + } else if(best_dag->rank != old_rank) { + PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n", + (unsigned)old_rank, best_dag->rank); + RPL_STAT(rpl_stats.parent_switch++); + rpl_reset_dio_timer(instance, 1); + } + return best_dag; +} /************************************************************************/ rpl_parent_t * rpl_select_parent(rpl_dag_t *dag) { - rpl_parent_t *p; - rpl_parent_t *best; + rpl_parent_t *p, *best; best = NULL; for(p = list_head(dag->parents); p != NULL; p = p->next) { @@ -345,101 +637,139 @@ rpl_select_parent(rpl_dag_t *dag) } else if(best == NULL) { best = p; } else { - best = dag->of->best_parent(best, p); + best = dag->instance->of->best_parent(best, p); } } - if(best == NULL) { - /* need to handle update of best... */ - return NULL; - } - - if(dag->preferred_parent != best) { - if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { - PRINTF("RPL: Sending a No-Path DAO to old DAO parent\n"); - dao_output(dag->preferred_parent, ZERO_LIFETIME); - } - dag->preferred_parent = best; /* Cache the value. */ - dag->of->update_metric_container(dag); - rpl_set_default_route(dag, &best->addr); - /* The DAO parent set changed - schedule a DAO transmission. */ - if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { - rpl_schedule_dao(dag); - } - rpl_reset_dio_timer(dag, 1); - PRINTF("RPL: New preferred parent, rank changed from %u to %u\n", - (unsigned)dag->rank, dag->of->calculate_rank(best, 0)); - RPL_STAT(rpl_stats.parent_switch++); - } - - /* Update the DAG rank, since link-layer information may have changed - the local confidence. */ - dag->rank = dag->of->calculate_rank(best, 0); - if(dag->rank < dag->min_rank) { - dag->min_rank = dag->rank; - } else if(!acceptable_rank(dag, best->rank)) { - /* Send a No-Path DAO to the soon-to-be-removed preferred parent. */ - if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { - dao_output(best, ZERO_LIFETIME); - } - - remove_parents(dag, 0); - return NULL; + if(best != NULL) { + dag->preferred_parent = best; } return best; } /************************************************************************/ -int +void rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t *parent) { - uip_ds6_defrt_t *defrt; - - /* Remove uIPv6 routes that have this parent as the next hop. **/ - uip_ds6_route_rm_by_nexthop(&parent->addr); - defrt = uip_ds6_defrt_lookup(&parent->addr); - if(defrt != NULL) { - PRINTF("RPL: Removing default route "); - PRINT6ADDR(&parent->addr); - PRINTF("\n"); - uip_ds6_defrt_rm(defrt); - dag->def_route = NULL; - } + rpl_nullify_parent(dag, parent); PRINTF("RPL: Removing parent "); PRINT6ADDR(&parent->addr); PRINTF("\n"); - if(parent == dag->preferred_parent) { - dag->preferred_parent = NULL; - } - list_remove(dag->parents, parent); memb_free(&parent_memb, parent); - return 0; +} +/************************************************************************/ +void +rpl_nullify_parent(rpl_dag_t *dag, rpl_parent_t *parent) +{ + if(parent == dag->preferred_parent) { + dag->preferred_parent = NULL; + dag->rank = INFINITE_RANK; + if(dag->joined) { + if(dag->instance->def_route != NULL) { + if(dag->instance->def_route->isused) { + PRINTF("RPL: Removing default route "); + PRINT6ADDR(&parent->addr); + PRINTF("\n"); + uip_ds6_defrt_rm(dag->instance->def_route); + } + dag->instance->def_route = NULL; + } + dao_output(parent, ZERO_LIFETIME); + } + } + + PRINTF("RPL: Nullifying parent "); + PRINT6ADDR(&parent->addr); + PRINTF("\n"); +} +/************************************************************************/ +void +rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent) +{ + if(parent == dag_src->preferred_parent) { + dag_src->preferred_parent = NULL; + dag_src->rank = INFINITE_RANK; + if(dag_src->joined && dag_src->instance->def_route != NULL) { + if(dag_src->instance->def_route->isused) { + PRINTF("RPL: Removing default route "); + PRINT6ADDR(&parent->addr); + PRINTF("\n"); + uip_ds6_defrt_rm(dag_src->instance->def_route); + } + dag_src->instance->def_route = NULL; + } + } else if(dag_src->joined) { + /* Remove uIPv6 routes that have this parent as the next hop. */ + rpl_remove_routes_by_nexthop(&parent->addr, dag_src); + } + + PRINTF("RPL: Moving parent "); + PRINT6ADDR(&parent->addr); + PRINTF("\n"); + + list_remove(dag_src->parents, parent); + parent->dag = dag_dst; + list_add(dag_dst->parents, parent); } /************************************************************************/ rpl_dag_t * -rpl_get_dag(int instance_id) +rpl_get_any_dag(void) { int i; - for(i = 0; i < RPL_MAX_DAG_ENTRIES; i++) { - if(dag_table[i].joined && (instance_id == RPL_ANY_INSTANCE || - dag_table[i].instance_id == instance_id)) { - return &dag_table[i]; + for(i = 0; i < RPL_MAX_INSTANCES; ++i) { + if(instance_table[i].used && instance_table[i].current_dag->joined) { + return instance_table[i].current_dag; } } return NULL; } /************************************************************************/ +rpl_instance_t * +rpl_get_instance(uint8_t instance_id) +{ + int i; + + for(i = 0; i < RPL_MAX_INSTANCES; ++i) { + if(instance_table[i].used && instance_table[i].instance_id == instance_id) { + return &instance_table[i]; + } + } + return NULL; +} +/************************************************************************/ +rpl_dag_t * +rpl_get_dodag(uint8_t instance_id, uip_ipaddr_t *dag_id) +{ + rpl_instance_t *instance; + rpl_dag_t *dag; + int i; + + instance = rpl_get_instance(instance_id); + if(instance == NULL) { + return NULL; + } + + for(i = 0; i < RPL_MAX_DODAG_PER_INSTANCE; ++i) { + dag = &instance->dag_table[i]; + if(dag->used && uip_ipaddr_cmp(&dag->dag_id, dag_id)) { + return dag; + } + } + + return NULL; +} +/************************************************************************/ rpl_of_t * rpl_find_of(rpl_ocp_t ocp) { unsigned int i; for(i = 0; - i < sizeof(objective_functions) / sizeof(objective_functions[0]); + i < sizeof(objective_functions) / sizeof(objective_functions[0]); i++) { if(objective_functions[i]->ocp == ocp) { return objective_functions[i]; @@ -449,27 +779,32 @@ rpl_find_of(rpl_ocp_t ocp) return NULL; } /************************************************************************/ -static void -join_dag(uip_ipaddr_t *from, rpl_dio_t *dio) +void +rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) { + rpl_instance_t *instance; rpl_dag_t *dag; rpl_parent_t *p; rpl_of_t *of; - dag = rpl_alloc_dag(dio->instance_id); + dag = rpl_alloc_dodag(dio->instance_id, &dio->dag_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG object!\n"); return; } + instance = dag->instance; + p = rpl_add_parent(dag, dio, from); PRINTF("RPL: Adding "); PRINT6ADDR(from); PRINTF(" as a parent: "); if(p == NULL) { PRINTF("failed\n"); + instance->used = 0; return; } + p->dtsn = dio->dtsn; PRINTF("succeeded\n"); /* Determine the objective function by using the @@ -478,49 +813,133 @@ join_dag(uip_ipaddr_t *from, rpl_dio_t *dio) if(of == NULL) { PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF\n", dio->instance_id); + rpl_remove_parent(dag, p); + instance->used = 0; return; } /* Autoconfigure an address if this node does not already have an address with this prefix. */ if((dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) { - uip_ipaddr_t ipaddr; - /* assume that the prefix ends with zeros! */ - memcpy(&ipaddr, &dio->prefix_info.prefix, 16); - uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); - if(uip_ds6_addr_lookup(&ipaddr) == NULL) { - PRINTF("RPL: adding global IP address "); - PRINT6ADDR(&ipaddr); - PRINTF("\n"); - uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); - } + check_prefix(NULL, &dio->prefix_info); } dag->joined = 1; - dag->used = 1; - dag->of = of; - dag->grounded = dio->grounded; - dag->mop = dio->mop; dag->preference = dio->preference; - dag->instance_id = dio->instance_id; - - dag->max_rankinc = dio->dag_max_rankinc; - dag->min_hoprankinc = dio->dag_min_hoprankinc; - + dag->grounded = dio->grounded; dag->version = dio->version; - dag->preferred_parent = p; - dag->of->update_metric_container(dag); - dag->dio_intdoubl = dio->dag_intdoubl; - dag->dio_intmin = dio->dag_intmin; - dag->dio_redundancy = dio->dag_redund; + instance->of = of; + instance->mop = dio->mop; + instance->dtsn_out = RPL_LOLLIPOP_INIT; + instance->instance_id = dio->instance_id; + + instance->max_rankinc = dio->dag_max_rankinc; + instance->min_hoprankinc = dio->dag_min_hoprankinc; + instance->dio_intdoubl = dio->dag_intdoubl; + instance->dio_intmin = dio->dag_intmin; + instance->dio_redundancy = dio->dag_redund; + instance->default_lifetime = dio->default_lifetime; + instance->lifetime_unit = dio->lifetime_unit; memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id)); /* copy prefix information into the dag */ memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t)); - dag->rank = dag->of->calculate_rank(p, dio->rank); + dag->preferred_parent = p; + instance->of->update_metric_container(instance); + dag->rank = instance->of->calculate_rank(p, 0); + dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */ + + if(default_instance == NULL) { + default_instance = instance; + } + + PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", + dio->instance_id, dag->rank); + PRINT6ADDR(&dag->dag_id); + PRINTF("\n"); + + ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); + + rpl_reset_dio_timer(instance, 1); + rpl_set_default_route(instance, from); + + if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { + rpl_schedule_dao(instance); + } else { + PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n"); + } +} + +/************************************************************************/ +void +rpl_add_dodag(uip_ipaddr_t *from, rpl_dio_t *dio) +{ + rpl_instance_t *instance; + rpl_dag_t *dag, *previous_dag; + rpl_parent_t *p; + rpl_of_t *of; + + dag = rpl_alloc_dodag(dio->instance_id, &dio->dag_id); + if(dag == NULL) { + PRINTF("RPL: Failed to allocate a DAG object!\n"); + return; + } + + instance = dag->instance; + + previous_dag = rpl_find_parent_dag(instance, from); + if(previous_dag == NULL) { + PRINTF("RPL: Adding "); + PRINT6ADDR(from); + PRINTF(" as a parent: "); + p = rpl_add_parent(dag, dio, from); + if(p == NULL) { + PRINTF("failed\n"); + dag->used = 0; + return; + } + PRINTF("succeeded\n"); + } else { + p = rpl_find_parent(previous_dag, from); + if(p != NULL) { + rpl_move_parent(previous_dag, dag, p); + } + } + + /* Determine the objective function by using the + objective code point of the DIO. */ + of = rpl_find_of(dio->ocp); + if(of != instance->of || + instance->mop != dio->mop || + instance->max_rankinc != dio->dag_max_rankinc || + instance->min_hoprankinc != dio->dag_min_hoprankinc || + instance->dio_intdoubl != dio->dag_intdoubl || + instance->dio_intmin != dio->dag_intmin || + instance->dio_redundancy != dio->dag_redund || + instance->default_lifetime != dio->default_lifetime || + instance->lifetime_unit != dio->lifetime_unit) { + PRINTF("RPL: DIO for DAG instance %u uncompatible with previos DIO\n", + dio->instance_id); + rpl_remove_parent(dag, p); + dag->used = 0; + return; + } + + dag->used = 1; + dag->grounded = dio->grounded; + dag->preference = dio->preference; + dag->version = dio->version; + + memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id)); + + /* copy prefix information into the dag */ + memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t)); + + dag->preferred_parent = p; + dag->rank = instance->of->calculate_rank(p, 0); dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */ PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", @@ -528,21 +947,12 @@ join_dag(uip_ipaddr_t *from, rpl_dio_t *dio) PRINT6ADDR(&dag->dag_id); PRINTF("\n"); - ANNOTATE("#A join=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]); + ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); - - dag->default_lifetime = dio->default_lifetime; - dag->lifetime_unit = dio->lifetime_unit; - - rpl_reset_dio_timer(dag, 1); - rpl_set_default_route(dag, from); - - if(should_send_dao(dag, dio, p)) { - rpl_schedule_dao(dag); - } else { - PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n"); - } + rpl_process_parent_event(instance, p); + p->dtsn = dio->dtsn; } + /************************************************************************/ static void global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio) @@ -551,46 +961,40 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio) remove_parents(dag, 0); dag->version = dio->version; - dag->dtsn_out = 1; - dag->of->reset(dag); - if((p = rpl_add_parent(dag, dio, from)) == NULL) { + dag->instance->of->reset(dag); + dag->min_rank = INFINITE_RANK; + RPL_LOLLIPOP_INCREMENT(dag->instance->dtsn_out); + + p = rpl_add_parent(dag, dio, from); + if(p == NULL) { PRINTF("RPL: Failed to add a parent during the global repair\n"); dag->rank = INFINITE_RANK; } else { - rpl_set_default_route(dag, from); - dag->rank = dag->of->calculate_rank(NULL, dio->rank); - dag->min_rank = dag->rank; - rpl_reset_dio_timer(dag, 1); - if(should_send_dao(dag, dio, p)) { - rpl_schedule_dao(dag); - } + dag->rank = dag->instance->of->calculate_rank(p, 0); + dag->min_rank = dag->rank ; + rpl_process_parent_event(dag->instance, p); } + PRINTF("RPL: Participating in a global repair (version=%u, rank=%hu)\n", dag->version, dag->rank); RPL_STAT(rpl_stats.global_repairs++); } /************************************************************************/ -int -rpl_repair_dag(rpl_dag_t *dag) -{ - if(dag->rank == ROOT_RANK(dag)) { - dag->version++; - dag->dtsn_out = 1; - rpl_reset_dio_timer(dag, 1); - return 1; - } - return 0; -} -/************************************************************************/ void -rpl_local_repair(rpl_dag_t *dag) +rpl_local_repair(rpl_instance_t *instance) { - PRINTF("RPL: Starting a local DAG repair\n"); + int i; - dag->rank = INFINITE_RANK; - remove_parents(dag, 0); - rpl_reset_dio_timer(dag, 1); + PRINTF("RPL: Starting a local instance repair\n"); + for(i = 0; i < RPL_MAX_DODAG_PER_INSTANCE; i++) { + if(instance->dag_table[i].used) { + instance->dag_table[i].rank = INFINITE_RANK; + nullify_parents(&instance->dag_table[i], 0); + } + } + + rpl_reset_dio_timer(instance, 0); RPL_STAT(rpl_stats.local_repairs++); } @@ -598,75 +1002,101 @@ rpl_local_repair(rpl_dag_t *dag) void rpl_recalculate_ranks(void) { - rpl_dag_t *dag; + rpl_instance_t *instance, *end; rpl_parent_t *p; + int i; /* * We recalculate ranks when we receive feedback from the system rather * than RPL protocol messages. This periodical recalculation is called * from a timer in order to keep the stack depth reasonably low. */ - dag = rpl_get_dag(RPL_ANY_INSTANCE); - if(dag != NULL) { - for(p = list_head(dag->parents); p != NULL; p = p->next) { - if(p->updated) { - p->updated = 0; - rpl_process_parent_event(dag, p); - /* - * Stop calculating here because the parent list may have changed. - * If more ranks need to be recalculated, it will be taken care of - * in subsequent calls to this functions. - */ - break; + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { + if(instance->used) { + for(i = 0; i < RPL_MAX_DODAG_PER_INSTANCE; i++) { + if(instance->dag_table[i].used) { + for(p = list_head(instance->dag_table[i].parents); p != NULL; p = p->next) { + if(p->updated) { + p->updated = 0; + if(!rpl_process_parent_event(instance, p)) { + PRINTF("RPL: A parent was dropped\n"); + } + /* + * Stop calculating here because the parent list may have changed. + * If more ranks need to be recalculated, it will be taken care of + * in subsequent calls to this functions. + */ + break; + } + } + } } } } } /************************************************************************/ int -rpl_process_parent_event(rpl_dag_t *dag, rpl_parent_t *p) +rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p) { - rpl_rank_t parent_rank; rpl_rank_t old_rank; + int return_value; - /* Update the parent rank. */ - parent_rank = p->rank; - old_rank = dag->rank; + old_rank = instance->current_dag->rank; + return_value = 1; - if(rpl_select_parent(dag) == NULL) { - /* No suitable parent; trigger a local repair. */ - PRINTF("RPL: No parents found in a DAG\n"); - rpl_local_repair(dag); - return 1; - } - - if(DAG_RANK(old_rank, dag) != DAG_RANK(dag->rank, dag)) { - if(dag->rank < dag->min_rank) { - dag->min_rank = dag->rank; + if(p->rank == INFINITE_RANK) { + /* This parent is no longer valid */ + PRINTF("RPL: This parent is no longer valid \n"); + if(p != instance->current_dag->preferred_parent) { + rpl_nullify_parent(p->dag, p); + return 0; + } else { + rpl_nullify_parent(p->dag, p); + return_value = 0; } - PRINTF("RPL: Moving in the DAG from rank %hu to %hu\n", - DAG_RANK(old_rank, dag), DAG_RANK(dag->rank, dag)); - PRINTF("RPL: The preferred parent is "); - PRINT6ADDR(&dag->preferred_parent->addr); - PRINTF(" (rank %u)\n", - (unsigned)DAG_RANK(dag->preferred_parent->rank, dag)); - rpl_reset_dio_timer(dag, 1); - } - - if(parent_rank == INFINITE_RANK || - !acceptable_rank(dag, dag->of->calculate_rank(NULL, parent_rank))) { + } else if(!acceptable_rank(p->dag, p->rank)) { /* The candidate parent is no longer valid: the rank increase resulting from the choice of it as a parent would be too high. */ + PRINTF("RPL: Unacceptable rank\n"); + if(p != instance->current_dag->preferred_parent) { + rpl_nullify_parent(p->dag, p); + return 0; + } else { + rpl_nullify_parent(p->dag, p); + return_value = 0; + } + } + + if(rpl_select_dodag(instance, p) == NULL) { + /* No suitable parent; trigger a local repair. */ + PRINTF("RPL: No parents found in any DAG\n"); + rpl_local_repair(instance); return 0; } - return 1; +#if DEBUG + if(DAG_RANK(old_rank, instance) != DAG_RANK(instance->current_dag->rank, instance)) { + PRINTF("RPL: Moving in the instance from rank %hu to %hu\n", + DAG_RANK(old_rank, instance), DAG_RANK(instance->current_dag->rank, instance)); + if(instance->current_dag->rank != INFINITE_RANK) { + PRINTF("RPL: The preferred parent is "); + PRINT6ADDR(&instance->current_dag->preferred_parent->addr); + PRINTF(" (rank %u)\n", + (unsigned)DAG_RANK(instance->current_dag->preferred_parent->rank, instance)); + } else { + PRINTF("RPL: We don't have any parent"); + } + } +#endif /* DEBUG */ + + return return_value; } /************************************************************************/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { - rpl_dag_t *dag; + rpl_instance_t *instance; + rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; if(dio->mop != RPL_MOP_DEFAULT) { @@ -674,51 +1104,61 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) return; } - dag = rpl_get_dag(dio->instance_id); + if(dio->rank == INFINITE_RANK) { + PRINTF("RPL: Ignoring DIO from node with infinite rank: "); + PRINT6ADDR(from); + PRINTF("\n"); + return; + } + + instance = rpl_get_instance(dio->instance_id); + if(instance == NULL) { + PRINTF("RPL: New instance detected: Joining...\n"); + rpl_join_instance(from, dio); + return; + } + + dag = rpl_get_dodag(dio->instance_id, &dio->dag_id); if(dag == NULL) { - /* Join the first possible DAG of this RPL instance. */ - if(dio->rank != INFINITE_RANK) { - join_dag(from, dio); - } else { - PRINTF("RPL: Ignoring DIO from node with infinite rank: "); - PRINT6ADDR(from); - PRINTF("\n"); - } + PRINTF("RPL: Adding new dodag to known instance.\n"); + rpl_add_dodag(from, dio); return; } - if(memcmp(&dag->dag_id, &dio->dag_id, sizeof(dag->dag_id))) { - PRINTF("RPL: Ignoring DIO for another DAG within our instance\n"); - return; - } - - if(dio->version > dag->version) { - if(dag->rank == ROOT_RANK(dag)) { + if(RPL_LOLLIPOP_GREATER_THAN(dio->version, dag->version)) { + if(dag->rank == ROOT_RANK(instance)) { PRINTF("RPL: Root received inconsistent DIO version number\n"); - dag->version = dio->version + 1; - rpl_reset_dio_timer(dag, 1); + dag->version = dio->version; + RPL_LOLLIPOP_INCREMENT(dag->version); + rpl_reset_dio_timer(instance, 0); } else { global_repair(from, dag, dio); } return; - } else if(dio->version < dag->version) { - /* Inconsistency detected - someone is still on old version */ - PRINTF("RPL: old version received => inconsistency detected\n"); - rpl_reset_dio_timer(dag, 1); - return; + } else { + if(RPL_LOLLIPOP_GREATER_THAN(dag->version, dio->version)) { + /* The DIO sender is on an older version of the DAG. */ + PRINTF("RPL: old version received => inconsistency detected\n"); + if(dag->joined) { + rpl_reset_dio_timer(instance, 0); + return; + } + } } if(dio->rank == INFINITE_RANK) { - rpl_reset_dio_timer(dag, 1); - } else if(dio->rank < ROOT_RANK(dag)) { + if(dag->joined) { + rpl_reset_dio_timer(instance, 0); + } + } else if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } - if(dag->rank == ROOT_RANK(dag)) { + if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { - dag->dio_counter++; + instance->dio_counter++; } return; } @@ -732,42 +1172,60 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) p = rpl_find_parent(dag, from); if(p == NULL) { - if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS) { - /* Make room for a new parent. */ - remove_worst_parent(dag, dio->rank); - } - - /* Add the DIO sender as a candidate parent. */ - p = rpl_add_parent(dag, dio, from); - if(p == NULL) { - PRINTF("RPL: Failed to add a new parent ("); + previous_dag = rpl_find_parent_dag(instance, from); + if(previous_dag == NULL) { + if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS_PER_DODAG) { + /* Make room for a new parent. */ + remove_worst_parent(dag, dio->rank); + } + /* Add the DIO sender as a candidate parent. */ + p = rpl_add_parent(dag, dio, from); + if(p == NULL) { + PRINTF("RPL: Failed to add a new parent ("); + PRINT6ADDR(from); + PRINTF(")\n"); + return; + } + PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); PRINT6ADDR(from); - PRINTF(")\n"); - return; + PRINTF("\n"); + } else { + p = rpl_find_parent(previous_dag, from); + rpl_move_parent(previous_dag, dag, p); + } + } else { + if(p->rank == dio->rank) { + PRINTF("RPL: Received consistent DIO\n"); + if(dag->joined) { + instance->dio_counter++; + } + } else { + p->rank=dio->rank; } - - PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); - PRINT6ADDR(from); - PRINTF("\n"); - } else if(DAG_RANK(p->rank, dag) == DAG_RANK(dio->rank, dag)) { - PRINTF("RPL: Received consistent DIO\n"); - dag->dio_counter++; } - + + PRINTF("RPL current state: Prefered DODAG: "); + PRINT6ADDR(&instance->current_dag->dag_id); + PRINTF(", rank: %u, min_rank: %u, ", + instance->current_dag->rank, instance->current_dag->min_rank); + PRINTF("parent rank: %u, parent etx: %u, link metric: %u, instance etx %u\n", + p->rank, p->mc.obj.etx, p->link_metric, instance->mc.obj.etx); + /* We have allocated a candidate parent; process the DIO further. */ - memcpy(&p->mc, &dio->mc, sizeof(p->mc)); - p->rank = dio->rank; - if(rpl_process_parent_event(dag, p) == 0) { - /* The candidate parent no longer exists. */ + memcpy(&p->mc, &dio->mc, sizeof(p->mc)); + if(rpl_process_parent_event(instance, p) == 0) { + PRINTF("RPL: The candidate parent is rejected\n"); return; } - - if(should_send_dao(dag, dio, p)) { - rpl_schedule_dao(dag); + + /* We don't use route control, so we can have only one official parent. */ + if(dag->joined && p == dag->preferred_parent) { + if(should_send_dao(instance, dio, p)) { + RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); + rpl_schedule_dao(instance); + } } - p->dtsn = dio->dtsn; } /************************************************************************/ - diff --git a/core/net/rpl/rpl-ext-header.c b/core/net/rpl/rpl-ext-header.c new file mode 100755 index 000000000..827853b60 --- /dev/null +++ b/core/net/rpl/rpl-ext-header.c @@ -0,0 +1,293 @@ +/** + * \addtogroup uip6 + * @{ + */ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ +/** + * \file + * Management of extension headers for ContikiRPL. + * + * \author Vincent Brillault , + * Joakim Eriksson , + * Niclas Finne , + * Nicolas Tsiftes . + */ + +#include "net/uip.h" +#include "net/tcpip.h" +#include "net/uip-ds6.h" +#include "net/rpl/rpl-private.h" + +#define DEBUG DEBUG_NONE +#include "net/uip-debug.h" + +#include +#include + +/************************************************************************/ +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len]) +#define UIP_HBHO_BUF ((struct uip_hbho_hdr *)&uip_buf[uip_l2_l3_hdr_len]) +#define UIP_HBHO_NEXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_HOP_BY_HOP_LEN]) +#define UIP_EXT_HDR_OPT_BUF ((struct uip_ext_hdr_opt *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset]) +#define UIP_EXT_HDR_OPT_PADN_BUF ((struct uip_ext_hdr_opt_padn *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset]) +#define UIP_EXT_HDR_OPT_RPL_BUF ((struct uip_ext_hdr_opt_rpl *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset]) +/************************************************************************/ +int +rpl_verify_header(int uip_ext_opt_offset) +{ + rpl_instance_t *instance; + long diff; + int down; + + if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) { + PRINTF("RPL: Bad header option! (wrong length)\n"); + return 1; + } + + if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { + PRINTF("RPL: Forward error!\n"); + /* We should try to repair it, not implemented for the moment */ + return 2; + } + + instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); + if(instance == NULL) { + PRINTF("RPL: Unknown instance: %u\n", + UIP_EXT_HDR_OPT_RPL_BUF->instance); + return 1; + } + + if(!instance->current_dag->joined) { + PRINTF("RPL: No DAG in the instance\n"); + return 1; + } + + down = 0; + if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) { + down = 1; + } + + PRINTF("RPL: Packet going %s\n", down == 1 ? "down" : "up"); + + diff = UIP_EXT_HDR_OPT_RPL_BUF->senderrank - instance->current_dag->rank; + if((down && diff > 0) || (!down && diff < 0)) { + PRINTF("RPL: Loop detected\n"); + if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) { + PRINTF("RPL: Rank error signalled in RPL option!\n"); + /* We should try to repair it, not implemented for the moment */ + return 3; + } + PRINTF("RPL: Single error tolerated\n"); + UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR; + return 0; + } + + PRINTF("RPL: Rank OK\n"); + + return 0; +} +/************************************************************************/ +static void +set_rpl_opt(unsigned uip_ext_opt_offset) +{ + uint8_t temp_len; + + memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN); + memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN); + UIP_HBHO_BUF->next = UIP_IP_BUF->proto; + UIP_IP_BUF->proto = UIP_PROTO_HBHO; + UIP_HBHO_BUF->len = RPL_HOP_BY_HOP_LEN - 8; + 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->flags = 0; + UIP_EXT_HDR_OPT_RPL_BUF->instance = 0; + UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0; + uip_len += RPL_HOP_BY_HOP_LEN; + temp_len = UIP_IP_BUF->len[1]; + UIP_IP_BUF->len[1] += UIP_HBHO_BUF->len + 8; + if(UIP_IP_BUF->len[1] < temp_len) { + UIP_IP_BUF->len[0]++; + } +} +/************************************************************************/ +void +rpl_update_header_empty(void) +{ + rpl_instance_t *instance; + int uip_ext_opt_offset; + int last_uip_ext_len; + + last_uip_ext_len = uip_ext_len; + uip_ext_len = 0; + uip_ext_opt_offset = 2; + + PRINTF("RPL: Verifying the presence of the RPL header option\n"); + + switch(UIP_IP_BUF->proto) { + case UIP_PROTO_HBHO: + if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) { + PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n"); + uip_ext_len = last_uip_ext_len; + return; + } + instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); + if(instance == NULL || !instance->used || !instance->current_dag->joined) { + PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n"); + return; + } + break; + default: + PRINTF("RPL: No hop-by-hop option found, creating it\n"); + if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_LINK_MTU) { + PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n"); + uip_ext_len = last_uip_ext_len; + return; + } + set_rpl_opt(uip_ext_opt_offset); + uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN; + return; + } + + switch(UIP_EXT_HDR_OPT_BUF->type) { + case UIP_EXT_HDR_OPT_RPL: + PRINTF("RPL: Updating RPL option\n"); + UIP_EXT_HDR_OPT_RPL_BUF->senderrank=instance->current_dag->rank; + uip_ext_len = last_uip_ext_len; + return; + default: + PRINTF("RPL: Multi Hop-by-hop options not implemented\n"); + uip_ext_len = last_uip_ext_len; + return; + } +} +/************************************************************************/ +int +rpl_update_header_final(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; + uip_ext_len = 0; + uip_ext_opt_offset = 2; + + if(UIP_IP_BUF->proto == UIP_PROTO_HBHO) { + if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) { + PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n"); + uip_ext_len = last_uip_ext_len; + return 0; + } + + 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 1; + } + 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 = default_instance->current_dag->rank; + uip_ext_len = last_uip_ext_len; + } + } + } + return 0; +} +/************************************************************************/ +void +rpl_remove_header(void) +{ + int last_uip_ext_len; + uint8_t temp_len; + + last_uip_ext_len = uip_ext_len; + uip_ext_len = 0; + + PRINTF("RPL: Verifying the presence of the RPL header option\n"); + switch(UIP_IP_BUF->proto){ + case UIP_PROTO_HBHO: + PRINTF("RPL: Removing the RPL header option\n"); + UIP_IP_BUF->proto = UIP_HBHO_BUF->next; + temp_len = UIP_IP_BUF->len[1]; + uip_len -= UIP_HBHO_BUF->len + 8; + UIP_IP_BUF->len[1] -= UIP_HBHO_BUF->len + 8; + if(UIP_IP_BUF->len[1] > temp_len) { + UIP_IP_BUF->len[0]--; + } + memmove(UIP_EXT_BUF, UIP_HBHO_NEXT_BUF, uip_len - UIP_IPH_LEN); + break; + default: + PRINTF("RPL: No hop-by-hop Option found\n"); + } +} +/************************************************************************/ +uint8_t +rpl_invert_header(void) +{ + uint8_t uip_ext_opt_offset; + uint8_t last_uip_ext_len; + + last_uip_ext_len = uip_ext_len; + uip_ext_len = 0; + uip_ext_opt_offset = 2; + + PRINTF("RPL: Verifying the presence of the RPL header option\n"); + switch(UIP_IP_BUF->proto) { + case UIP_PROTO_HBHO: + break; + default: + PRINTF("RPL: No hop-by-hop Option found\n"); + uip_ext_len = last_uip_ext_len; + return 0; + } + + switch (UIP_EXT_HDR_OPT_BUF->type) { + case UIP_EXT_HDR_OPT_RPL: + PRINTF("RPL: Updating RPL option (switching direction)\n"); + UIP_EXT_HDR_OPT_RPL_BUF->flags &= RPL_HDR_OPT_DOWN; + UIP_EXT_HDR_OPT_RPL_BUF->flags ^= RPL_HDR_OPT_DOWN; + UIP_EXT_HDR_OPT_RPL_BUF->senderrank = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance)->current_dag->rank; + uip_ext_len = last_uip_ext_len; + return RPL_HOP_BY_HOP_LEN; + default: + PRINTF("RPL: Multi Hop-by-hop options not implemented\n"); + uip_ext_len = last_uip_ext_len; + return 0; + } +} +/************************************************************************/ diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c old mode 100644 new mode 100755 index 3c3a660ca..2dcc33f8b --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -81,8 +81,17 @@ void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *); void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *); #endif +static uint8_t dao_sequence = RPL_LOLLIPOP_INIT; + +/* some debug callbacks useful when debugging RPL networks */ +#ifdef RPL_DEBUG_DIO_INPUT +void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *); +#endif + +#ifdef RPL_DEBUG_DAO_OUTPUT +void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *); +#endif -static uint8_t dao_sequence; /*---------------------------------------------------------------------------*/ static int get_global_addr(uip_ipaddr_t *addr) @@ -135,21 +144,27 @@ set16(uint8_t *buffer, int pos, uint16_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); + } } } } @@ -224,7 +239,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. */ @@ -236,6 +251,7 @@ dio_input(void) dio.rank = get16(buffer, i); 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; @@ -249,6 +265,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]; @@ -274,7 +294,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; @@ -375,19 +394,35 @@ 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 + set16(buffer, pos, INFINITE_RANK); +#else /* RPL_LEAF_ONLY */ set16(buffer, pos, dag->rank); +#endif /* RPL_LEAF_ONLY */ pos += 2; buffer[pos] = 0; @@ -395,8 +430,15 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr) buffer[pos] |= RPL_DIO_GROUNDED; } - buffer[pos++] = dag->mop << RPL_DIO_MOP_SHIFT; - buffer[pos++] = ++dag->dtsn_out; + buffer[pos] |= instance->mop << RPL_DIO_MOP_SHIFT; + buffer[pos] |= dag->preference & RPL_DIO_PREFERENCE_MASK; + pos++; + + 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 */ @@ -405,48 +447,49 @@ 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_OPTION_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; - set16(buffer, pos, dag->mc.obj.etx); + set16(buffer, pos, instance->mc.obj.etx); pos += 2; - } else if(dag->mc.type == RPL_DAG_MC_ENERGY) { + } 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; } } +#endif /* !RPL_LEAF_ONLY */ /* Always add a DAG configuration option. */ buffer[pos++] = RPL_OPTION_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; - set16(buffer, pos, dag->max_rankinc); + buffer[pos++] = instance->dio_intdoubl; + buffer[pos++] = instance->dio_intmin; + buffer[pos++] = instance->dio_redundancy; + set16(buffer, pos, instance->max_rankinc); pos += 2; - set16(buffer, pos, dag->min_hoprankinc); + set16(buffer, pos, instance->min_hoprankinc); pos += 2; /* OCP is in the DAG_CONF option */ - set16(buffer, pos, dag->of->ocp); + set16(buffer, pos, instance->of->ocp); pos += 2; buffer[pos++] = 0; /* reserved */ - buffer[pos++] = dag->default_lifetime; - set16(buffer, pos, dag->lifetime_unit); + buffer[pos++] = instance->default_lifetime; + set16(buffer, pos, instance->lifetime_unit); pos += 2; /* Check if we have a prefix to send also. */ @@ -471,19 +514,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 @@ -491,10 +542,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; @@ -520,32 +572,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 RPL options present. */ @@ -561,7 +618,7 @@ dao_input(void) switch(subopt_type) { case RPL_OPTION_TARGET: - /* handle the target option */ + /* Handle the target option. */ prefixlen = buffer[i + 3]; memset(&prefix, 0, sizeof(prefix)); memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT); @@ -577,7 +634,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"); @@ -585,7 +642,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"); @@ -601,25 +658,25 @@ 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; } } + rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr); if(rep == NULL) { - rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr); - if(rep == NULL) { - RPL_STAT(rpl_stats.mem_overflows++); - PRINTF("RPL: Could not add a route after receiving a DAO\n"); - return; - } + RPL_STAT(rpl_stats.mem_overflows++); + PRINTF("RPL: Could not add a route after receiving a DAO\n"); + return; } - 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) { @@ -629,16 +686,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; @@ -652,7 +711,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; @@ -661,23 +720,32 @@ dao_output(rpl_parent_t *n, rpl_lifetime_t lifetime) dag = n->dag; } + instance = dag->instance; + #ifdef RPL_DEBUG_DAO_OUTPUT RPL_DEBUG_DAO_OUTPUT(n); #endif 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; @@ -726,9 +794,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]; @@ -741,7 +806,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; @@ -751,7 +816,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; diff --git a/core/net/rpl/rpl-of-etx.c b/core/net/rpl/rpl-of-etx.c index 55bbadca4..6f82c1ad3 100644 --- a/core/net/rpl/rpl-of-etx.c +++ b/core/net/rpl/rpl-of-etx.c @@ -52,13 +52,15 @@ static void reset(rpl_dag_t *); static void parent_state_callback(rpl_parent_t *, int, 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); -static void update_metric_container(rpl_dag_t *); +static void update_metric_container(rpl_instance_t *); rpl_of_t rpl_of_etx = { reset, parent_state_callback, best_parent, + best_dag, calculate_rank, update_metric_container, 1 @@ -86,14 +88,14 @@ typedef uint16_t rpl_path_metric_t; static rpl_path_metric_t calculate_path_metric(rpl_parent_t *p) { - if(p == NULL || (p->mc.obj.etx == 0 && p->rank > ROOT_RANK(p->dag))) { + if(p == NULL || (p->mc.obj.etx == 0 && p->rank > ROOT_RANK(p->dag->instance))) { return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR; } return p->mc.obj.etx + NI_ETX_TO_RPL_ETX(p->link_metric); } static void -reset(rpl_dag_t *dag) +reset(rpl_dag_t *sag) { } @@ -114,7 +116,7 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) } rank_increase = NEIGHBOR_INFO_FIX2ETX(INITIAL_LINK_METRIC) * DEFAULT_MIN_HOPRANKINC; } else { - rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric) * p->dag->min_hoprankinc; + rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric) * p->dag->instance->min_hoprankinc; if(base_rank == 0) { base_rank = p->rank; } @@ -132,6 +134,32 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) return new_rank; } +static rpl_dag_t * +best_dag(rpl_dag_t *d1, rpl_dag_t *d2) +{ + if(d1->grounded) { + if (!d2->grounded) { + return d1; + } + } else if(d2->grounded) { + return d2; + } + + if(d1->preference < d2->preference) { + return d2; + } else { + if(d1->preference > d2->preference) { + return d1; + } + } + + if(d2->rank < d1->rank) { + return d2; + } else { + return d1; + } +} + static rpl_parent_t * best_parent(rpl_parent_t *p1, rpl_parent_t *p2) { @@ -142,7 +170,7 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2) dag = p1->dag; /* Both parents must be in the same DAG. */ - min_diff = RPL_DAG_MC_ETX_DIVISOR / + min_diff = RPL_DAG_MC_ETX_DIVISOR / PARENT_SWITCH_THRESHOLD_DIV; p1_metric = calculate_path_metric(p1); @@ -164,18 +192,26 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2) } static void -update_metric_container(rpl_dag_t *dag) +update_metric_container(rpl_instance_t *instance) { rpl_path_metric_t path_metric; + rpl_dag_t *dag; #if RPL_DAG_MC == RPL_DAG_MC_ENERGY uint8_t type; #endif - dag->mc.flags = RPL_DAG_MC_FLAG_P; - dag->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; - dag->mc.prec = 0; + instance->mc.flags = RPL_DAG_MC_FLAG_P; + instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; + instance->mc.prec = 0; - if(dag->rank == ROOT_RANK(dag)) { + dag = instance->current_dag; + + if (!dag->joined) { + /* We should probably do something here */ + return; + } + + if(dag->rank == ROOT_RANK(instance)) { path_metric = 0; } else { path_metric = calculate_path_metric(dag->preferred_parent); @@ -183,27 +219,27 @@ update_metric_container(rpl_dag_t *dag) #if RPL_DAG_MC == RPL_DAG_MC_ETX - dag->mc.type = RPL_DAG_MC_ETX; - dag->mc.length = sizeof(dag->mc.obj.etx); - dag->mc.obj.etx = path_metric; + instance->mc.type = RPL_DAG_MC_ETX; + instance->mc.length = sizeof(instance->mc.obj.etx); + instance->mc.obj.etx = path_metric; PRINTF("RPL: My path ETX to the root is %u.%u\n", - dag->mc.obj.etx / RPL_DAG_MC_ETX_DIVISOR, - (dag->mc.obj.etx % RPL_DAG_MC_ETX_DIVISOR * 100) / RPL_DAG_MC_ETX_DIVISOR); + instance->mc.obj.etx / RPL_DAG_MC_ETX_DIVISOR, + (instance->mc.obj.etx % RPL_DAG_MC_ETX_DIVISOR * 100) / RPL_DAG_MC_ETX_DIVISOR); #elif RPL_DAG_MC == RPL_DAG_MC_ENERGY - dag->mc.type = RPL_DAG_MC_ENERGY; - dag->mc.length = sizeof(dag->mc.obj.energy); + instance->mc.type = RPL_DAG_MC_ENERGY; + instance->mc.length = sizeof(instance->mc.obj.energy); - if(dag->rank == ROOT_RANK(dag)) { + if(dag->rank == ROOT_RANK(instance)) { type = RPL_DAG_MC_ENERGY_TYPE_MAINS; } else { type = RPL_DAG_MC_ENERGY_TYPE_BATTERY; } - dag->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE; - dag->mc.obj.energy.energy_est = path_metric; + instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE; + instance->mc.obj.energy.energy_est = path_metric; #else diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index b9ea90a83..19ea4277c 100644 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -48,6 +48,7 @@ static void reset(rpl_dag_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_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); static void update_metric_container(rpl_dag_t *); @@ -55,6 +56,7 @@ rpl_of_t rpl_of0 = { reset, NULL, best_parent, + best_dag, calculate_rank, update_metric_container, 0 @@ -92,6 +94,32 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) } +static rpl_dag_t * +best_dag(rpl_dag_t *d1, rpl_dag_t *d2) +{ + if(d1->grounded) { + if (!d2->grounded) { + return d1; + } + } else if(d2->grounded) { + return d2; + } + + if(d1->preference < d2->preference) { + return d2; + } else { + if(d1->preference > d2->preference) { + return d1; + } + } + + if(d2->rank < d1->rank) { + return d2; + } else { + return d1; + } +} + static rpl_parent_t * best_parent(rpl_parent_t *p1, rpl_parent_t *p2) { @@ -127,7 +155,7 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2) } static void -update_metric_container(rpl_dag_t *dag) +update_metric_container(rpl_instance_t *instance) { - dag->mc.type = RPL_DAG_MC_NONE; + instance->mc.type = RPL_DAG_MC_NONE; } diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index 5341c06bc..1936c124a 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.h @@ -94,6 +94,16 @@ #define RPL_DAO_K_FLAG 0x80 /* DAO ACK requested */ #define RPL_DAO_D_FLAG 0x40 /* DODAG ID present */ /*---------------------------------------------------------------------------*/ +/* RPL IPv6 extension header option. */ +#define RPL_HDR_OPT_LEN 4 +#define RPL_HOP_BY_HOP_LEN (RPL_HDR_OPT_LEN + 2 + 2) +#define RPL_HDR_OPT_DOWN 0x80 +#define RPL_HDR_OPT_DOWN_SHIFT 7 +#define RPL_HDR_OPT_RANK_ERR 0x40 +#define RPL_HDR_OPT_RANK_ERR_SHIFT 6 +#define RPL_HDR_OPT_FWD_ERR 0x20 +#define RPL_HDR_OPT_FWD_ERR_SHIFT 5 +/*---------------------------------------------------------------------------*/ /* Default values for RPL constants and variables. */ /* The default value for the DAO timer. */ @@ -108,8 +118,8 @@ /* Default route lifetime as a multiple of the lifetime unit. */ #define RPL_DEFAULT_LIFETIME 0xff -#define RPL_LIFETIME(dag, lifetime) \ - ((unsigned long)(dag)->lifetime_unit * lifetime) +#define RPL_LIFETIME(instance, lifetime) \ + (((unsigned long)(instance)->lifetime_unit) * lifetime) #ifndef RPL_CONF_MIN_HOPRANKINC #define DEFAULT_MIN_HOPRANKINC 256 @@ -118,13 +128,13 @@ #endif #define DEFAULT_MAX_RANKINC (3 * DEFAULT_MIN_HOPRANKINC) -#define DAG_RANK(fixpt_rank, dag) ((fixpt_rank) / (dag)->min_hoprankinc) +#define DAG_RANK(fixpt_rank, instance) ((fixpt_rank) / (instance)->min_hoprankinc) /* Rank of a virtual root node that coordinates DAG root nodes. */ #define BASE_RANK 0 /* Rank of a root node. */ -#define ROOT_RANK(dag) (dag)->min_hoprankinc +#define ROOT_RANK(instance) (instance)->min_hoprankinc #define INFINITE_RANK 0xffff @@ -208,7 +218,7 @@ struct rpl_dio { uint8_t dag_intdoubl; uint8_t dag_intmin; uint8_t dag_redund; - rpl_lifetime_t default_lifetime; + uint8_t default_lifetime; uint16_t lifetime_unit; rpl_rank_t dag_max_rankinc; rpl_rank_t dag_min_hoprankinc; @@ -241,33 +251,44 @@ extern rpl_stats_t rpl_stats; #define RPL_STAT(code) #endif /* RPL_CONF_STATS */ /*---------------------------------------------------------------------------*/ +/* Instances */ +extern rpl_instance_t instance_table[]; +rpl_instance_t *default_instance; + /* ICMPv6 functions for RPL. */ void dis_output(uip_ipaddr_t *addr); -void dio_output(rpl_dag_t *, uip_ipaddr_t *uc_addr); -void dao_output(rpl_parent_t *, rpl_lifetime_t lifetime); -void dao_ack_output(rpl_dag_t *, uip_ipaddr_t *, uint8_t); -void uip_rpl_input(void); +void dio_output(rpl_instance_t *, uip_ipaddr_t *uc_addr); +void dao_output(rpl_parent_t *, uint8_t lifetime); +void dao_ack_output(rpl_instance_t *, uip_ipaddr_t *, uint8_t); /* RPL logic functions. */ -void rpl_join_dag(rpl_dag_t *); -void rpl_local_repair(rpl_dag_t *dag); -int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from); +void rpl_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio); +void rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio); +void rpl_local_repair(rpl_instance_t *instance); void rpl_process_dio(uip_ipaddr_t *, rpl_dio_t *); -int rpl_process_parent_event(rpl_dag_t *, rpl_parent_t *); +int rpl_process_parent_event(rpl_instance_t *, rpl_parent_t *); /* DAG object management. */ -rpl_dag_t *rpl_alloc_dag(uint8_t); -void rpl_free_dag(rpl_dag_t *); +rpl_dag_t *rpl_alloc_dodag(uint8_t, uip_ipaddr_t *); +rpl_instance_t *rpl_alloc_instance(uint8_t); +void rpl_free_dodag(rpl_dag_t *); +void rpl_free_instance(rpl_instance_t *); /* DAG parent management function. */ rpl_parent_t *rpl_add_parent(rpl_dag_t *, rpl_dio_t *dio, uip_ipaddr_t *); rpl_parent_t *rpl_find_parent(rpl_dag_t *, uip_ipaddr_t *); -int rpl_remove_parent(rpl_dag_t *, rpl_parent_t *); +rpl_parent_t * rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr); +rpl_dag_t * rpl_find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr); +void rpl_nullify_parent(rpl_dag_t *, rpl_parent_t *); +void rpl_remove_parent(rpl_dag_t *, rpl_parent_t *); +void rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent); rpl_parent_t *rpl_select_parent(rpl_dag_t *dag); +rpl_dag_t *rpl_select_dodag(rpl_instance_t *instance,rpl_parent_t *parent); void rpl_recalculate_ranks(void); /* RPL routing table functions. */ void rpl_remove_routes(rpl_dag_t *dag); +void rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag); uip_ds6_route_t *rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len, uip_ipaddr_t *next_hop); void rpl_purge_routes(void); @@ -276,8 +297,8 @@ void rpl_purge_routes(void); rpl_of_t *rpl_find_of(rpl_ocp_t); /* Timer functions. */ -void rpl_schedule_dao(rpl_dag_t *); -void rpl_reset_dio_timer(rpl_dag_t *, uint8_t); +void rpl_schedule_dao(rpl_instance_t *); +void rpl_reset_dio_timer(rpl_instance_t *, uint8_t); void rpl_reset_periodic_timer(void); /* Route poisoning. */ diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index dbb7d2392..aafd9e734 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -51,7 +51,7 @@ static struct ctimer periodic_timer; static void handle_periodic_timer(void *ptr); -static void new_dio_interval(rpl_dag_t *dag); +static void new_dio_interval(rpl_instance_t *instance); static void handle_dio_timer(void *ptr); static uint16_t next_dis; @@ -69,7 +69,7 @@ handle_periodic_timer(void *ptr) /* handle DIS */ #ifdef RPL_DIS_SEND next_dis++; - if(rpl_get_dag(RPL_ANY_INSTANCE) == NULL && next_dis >= RPL_DIS_INTERVAL) { + if(rpl_get_any_dag() == NULL && next_dis >= RPL_DIS_INTERVAL) { next_dis = 0; dis_output(NULL); } @@ -78,17 +78,17 @@ handle_periodic_timer(void *ptr) } /************************************************************************/ static void -new_dio_interval(rpl_dag_t *dag) +new_dio_interval(rpl_instance_t *instance) { uint32_t time; /* TODO: too small timer intervals for many cases */ - time = 1UL << dag->dio_intcurrent; + time = 1UL << instance->dio_intcurrent; /* Convert from milliseconds to CLOCK_TICKS. */ time = (time * CLOCK_SECOND) / 1000; - dag->dio_next_delay = time; + instance->dio_next_delay = time; /* random number between I/2 and I */ time = time >> 1; @@ -99,36 +99,36 @@ new_dio_interval(rpl_dag_t *dag) * operate efficiently. Therefore we need to calculate the delay between * the randomized time and the start time of the next interval. */ - dag->dio_next_delay -= time; - dag->dio_send = 1; + instance->dio_next_delay -= time; + instance->dio_send = 1; #if RPL_CONF_STATS /* keep some stats */ - dag->dio_totint++; - dag->dio_totrecv += dag->dio_counter; + instance->dio_totint++; + instance->dio_totrecv += instance->dio_counter; ANNOTATE("#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n", - DAG_RANK(dag->rank, dag), - (10 * (dag->rank % dag->min_hoprankinc)) / dag->min_hoprankinc, - dag->version, - dag->dio_totint, dag->dio_totsend, - dag->dio_totrecv,dag->dio_intcurrent, - dag->rank == ROOT_RANK(dag) ? "BLUE" : "ORANGE"); + DAG_RANK(instance->current_dag->rank, instance), + (10 * (instance->current_dag->rank % instance->min_hoprankinc)) / instance->min_hoprankinc, + instance->current_dag->version, + instance->dio_totint, instance->dio_totsend, + instance->dio_totrecv,instance->dio_intcurrent, + instance->current_dag->rank == ROOT_RANK(instance) ? "BLUE" : "ORANGE"); #endif /* RPL_CONF_STATS */ /* reset the redundancy counter */ - dag->dio_counter = 0; + instance->dio_counter = 0; /* schedule the timer */ PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", time); - ctimer_set(&dag->dio_timer, time, &handle_dio_timer, dag); + ctimer_set(&instance->dio_timer, time, &handle_dio_timer, instance); } /************************************************************************/ static void handle_dio_timer(void *ptr) { - rpl_dag_t *dag; + rpl_instance_t *instance; - dag = (rpl_dag_t *)ptr; + instance = (rpl_instance_t *)ptr; PRINTF("RPL: DIO Timer triggered\n"); if(!dio_send_ok) { @@ -136,33 +136,33 @@ handle_dio_timer(void *ptr) dio_send_ok = 1; } else { PRINTF("RPL: Postponing DIO transmission since link local address is not ok\n"); - ctimer_set(&dag->dio_timer, CLOCK_SECOND, &handle_dio_timer, dag); + ctimer_set(&instance->dio_timer, CLOCK_SECOND, &handle_dio_timer, instance); return; } } - if(dag->dio_send) { + if(instance->dio_send) { /* send DIO if counter is less than desired redundancy */ - if(dag->dio_counter < dag->dio_redundancy) { + if(instance->dio_counter < instance->dio_redundancy) { #if RPL_CONF_STATS - dag->dio_totsend++; + instance->dio_totsend++; #endif /* RPL_CONF_STATS */ - dio_output(dag, NULL); + dio_output(instance, NULL); } else { PRINTF("RPL: Supressing DIO transmission (%d >= %d)\n", - dag->dio_counter, dag->dio_redundancy); + instance->dio_counter, instance->dio_redundancy); } - dag->dio_send = 0; - PRINTF("RPL: Scheduling DIO timer %u ticks in future (sent)\n", - dag->dio_next_delay); - ctimer_set(&dag->dio_timer, dag->dio_next_delay, handle_dio_timer, dag); + instance->dio_send = 0; + PRINTF("RPL: Scheduling DIO timer %"PRIu32" ticks in future (sent)\n", + instance->dio_next_delay); + ctimer_set(&instance->dio_timer, instance->dio_next_delay, handle_dio_timer, instance); } else { /* check if we need to double interval */ - if(dag->dio_intcurrent < dag->dio_intmin + dag->dio_intdoubl) { - dag->dio_intcurrent++; - PRINTF("RPL: DIO Timer interval doubled %d\n", dag->dio_intcurrent); + if(instance->dio_intcurrent < instance->dio_intmin + instance->dio_intdoubl) { + instance->dio_intcurrent++; + PRINTF("RPL: DIO Timer interval doubled %d\n", instance->dio_intcurrent); } - new_dio_interval(dag); + new_dio_interval(instance); } } /************************************************************************/ @@ -173,61 +173,64 @@ rpl_reset_periodic_timer(void) ctimer_set(&periodic_timer, CLOCK_SECOND, handle_periodic_timer, NULL); } /************************************************************************/ -/* Resets the DIO timer in the DAG to its minimal interval. */ +/* Resets the DIO timer in the instance to its minimal interval. */ void -rpl_reset_dio_timer(rpl_dag_t *dag, uint8_t force) +rpl_reset_dio_timer(rpl_instance_t *instance, uint8_t force) { - /* only reset if not just reset or started */ - if(force || dag->dio_intcurrent > dag->dio_intmin) { - dag->dio_counter = 0; - dag->dio_intcurrent = dag->dio_intmin; - new_dio_interval(dag); +#if !RPL_LEAF_ONLY + /* Do not reset if we are already on the minimum interval, + unless forced to do so. */ + if(force || instance->dio_intcurrent > instance->dio_intmin) { + instance->dio_counter = 0; + instance->dio_intcurrent = instance->dio_intmin; + new_dio_interval(instance); } #if RPL_CONF_STATS rpl_stats.resets++; -#endif +#endif /* RPL_CONF_STATS */ +#endif /* RPL_LEAF_ONLY */ } /************************************************************************/ static void handle_dao_timer(void *ptr) { - rpl_dag_t *dag; + rpl_instance_t *instance; - dag = (rpl_dag_t *)ptr; + instance = (rpl_instance_t *)ptr; - if (!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) { - PRINTF("RPL: Postpone DAO transmission... \n"); - ctimer_set(&dag->dao_timer, CLOCK_SECOND, handle_dao_timer, dag); + if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) { + PRINTF("RPL: Postpone DAO transmission\n"); + ctimer_set(&instance->dao_timer, CLOCK_SECOND, handle_dao_timer, instance); return; } /* Send the DAO to the DAO parent set -- the preferred parent in our case. */ - if(dag->preferred_parent != NULL) { + if(instance->current_dag->preferred_parent != NULL) { PRINTF("RPL: handle_dao_timer - sending DAO\n"); /* Set the route lifetime to the default value. */ - dao_output(dag->preferred_parent, dag->default_lifetime); + dao_output(instance->current_dag->preferred_parent, instance->default_lifetime); } else { PRINTF("RPL: No suitable DAO parent\n"); } - ctimer_stop(&dag->dao_timer); + ctimer_stop(&instance->dao_timer); } /************************************************************************/ void -rpl_schedule_dao(rpl_dag_t *dag) +rpl_schedule_dao(rpl_instance_t *instance) { clock_time_t expiration_time; - expiration_time = etimer_expiration_time(&dag->dao_timer.etimer); + expiration_time = etimer_expiration_time(&instance->dao_timer.etimer); - if(!etimer_expired(&dag->dao_timer.etimer)) { + if(!etimer_expired(&instance->dao_timer.etimer)) { PRINTF("RPL: DAO timer already scheduled\n"); } else { expiration_time = DEFAULT_DAO_LATENCY / 2 + (random_rand() % (DEFAULT_DAO_LATENCY)); PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n", (unsigned)expiration_time); - ctimer_set(&dag->dao_timer, expiration_time, - handle_dao_timer, dag); + ctimer_set(&instance->dao_timer, expiration_time, + handle_dao_timer, instance); } } /************************************************************************/ diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index 7c5e05d21..b58d8b04e 100644 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -86,6 +86,23 @@ rpl_remove_routes(rpl_dag_t *dag) } } /************************************************************************/ +void +rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag) +{ + uip_ds6_route_t *locroute; + + for(locroute = uip_ds6_routing_table; + locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB; + locroute++) { + if(locroute->isused + && uip_ipaddr_cmp(&locroute->nexthop, nexthop) + && locroute->state.dag == dag) { + locroute->isused = 0; + } + } + ANNOTATE("#L %u 0\n",nexthop->u8[sizeof(uip_ipaddr_t) - 1]); +} +/************************************************************************/ uip_ds6_route_t * rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len, uip_ipaddr_t *next_hop) @@ -107,7 +124,7 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len, uip_ipaddr_copy(&rep->nexthop, next_hop); } rep->state.dag = dag; - rep->state.lifetime = RPL_LIFETIME(dag, dag->default_lifetime); + rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime); rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL; PRINTF("RPL: Added a route to "); @@ -123,8 +140,9 @@ static void rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx) { uip_ipaddr_t ipaddr; - rpl_dag_t *dag; rpl_parent_t *parent; + rpl_instance_t *instance; + rpl_instance_t *end; uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0); uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr); @@ -132,66 +150,55 @@ rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx) PRINT6ADDR(&ipaddr); PRINTF(" is %sknown. ETX = %u\n", known ? "" : "no longer ", NEIGHBOR_INFO_FIX2ETX(etx)); - dag = rpl_get_dag(RPL_DEFAULT_INSTANCE); - if(dag == NULL) { - return; - } + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { + if(instance->used == 1 ) { + parent = rpl_find_parent_any_dag(instance, &ipaddr); + if(parent != NULL) { + /* Trigger DAG rank recalculation. */ + parent->updated = 1; + parent->link_metric = etx; - parent = rpl_find_parent(dag, &ipaddr); - if(parent == NULL) { - if(!known) { - PRINTF("RPL: Deleting routes installed by DAOs received from "); - PRINT6ADDR(&ipaddr); - PRINTF("\n"); - uip_ds6_route_rm_by_nexthop(&ipaddr); + if(instance->of->parent_state_callback != NULL) { + instance->of->parent_state_callback(parent, known, etx); + } + if(!known) { + PRINTF("RPL: Removing parent "); + PRINT6ADDR(&parent->addr); + PRINTF(" in instance %u because of bad connectivity (ETX %d)\n", instance->instance_id, etx); + parent->rank = INFINITE_RANK; + } + } } - return; - } - - /* Trigger DAG rank recalculation. */ - parent->updated = 1; - - parent->link_metric = etx; - - if(dag->of->parent_state_callback != NULL) { - dag->of->parent_state_callback(parent, known, etx); } if(!known) { - PRINTF("RPL: Removing parent "); - PRINT6ADDR(&parent->addr); - PRINTF(" because of bad connectivity (ETX %d)\n", etx); - parent->rank = INFINITE_RANK; + PRINTF("RPL: Deleting routes installed by DAOs received from "); + PRINT6ADDR(&ipaddr); + PRINTF("\n"); + uip_ds6_route_rm_by_nexthop(&ipaddr); } } /************************************************************************/ void rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr) { - rpl_dag_t *dag; rpl_parent_t *p; - - /* This only handles one DODAG - if multiple we need to check all */ - dag = rpl_get_dag(RPL_ANY_INSTANCE); - if(dag == NULL) { - return; - } - - /* if this is our default route then clean the dag->def_route state */ - if(dag->def_route != NULL && - uip_ipaddr_cmp(&dag->def_route->ipaddr, &nbr->ipaddr)) { - dag->def_route = NULL; - } + rpl_instance_t *instance; + rpl_instance_t *end; if(!nbr->isused) { PRINTF("RPL: Removing neighbor "); PRINT6ADDR(&nbr->ipaddr); PRINTF("\n"); - p = rpl_find_parent(dag, &nbr->ipaddr); - if(p != NULL) { - p->rank = INFINITE_RANK; - /* Trigger DAG rank recalculation. */ - p->updated = 1; + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { + if(instance->used == 1 ) { + p = rpl_find_parent_any_dag(instance, &nbr->ipaddr); + if(p != NULL) { + p->rank = INFINITE_RANK; + /* Trigger DAG rank recalculation. */ + p->updated = 1; + } + } } } } @@ -201,6 +208,7 @@ rpl_init(void) { uip_ipaddr_t rplmaddr; PRINTF("RPL started\n"); + default_instance = NULL; rpl_reset_periodic_timer(); neighbor_info_subscribe(rpl_link_neighbor_callback); diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index bcc600b48..77d577988 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -73,19 +73,77 @@ #endif /* RPL_CONF_OF */ /* This value decides which DAG instance we should participate in by default. */ -#define RPL_DEFAULT_INSTANCE 0 +#define RPL_DEFAULT_INSTANCE 0x1e + +/* + * This value decides if this node must stay as a leaf or not + * as allowed by draft-ietf-roll-rpl-19#section-8.5 + */ +#ifdef RPL_CONF_LEAF_ONLY +#define RPL_LEAF_ONLY RPL_CONF_LEAF_ONLY +#else +#define RPL_LEAF_ONLY 0 +#endif + +/* + * Maximum of concurent rpl-instances + */ +#ifndef RPL_CONF_MAX_INSTANCES +#define RPL_MAX_INSTANCES 1 +#else +#define RPL_MAX_INSTANCES RPL_CONF_MAX_INSTANCES +#endif /* !RPL_CONF_MAX_INSTANCES */ + +/* + * Maximum of concurent dodag inside an instance + */ +#ifndef RPL_CONF_MAX_DODAG_PER_INSTANCE +#define RPL_MAX_DODAG_PER_INSTANCE 2 +#else +#define RPL_MAX_DODAG_PER_INSTANCE RPL_CONF_MAX_DODAG_PER_INSTANCE +#endif /* !RPL_CONF_MAX_DODAG_PER_INSTANCE */ + +/* + * + */ +#ifndef RPL_CONF_DAO_SPECIFY_DODAG +#if RPL_MAX_DODAG_PER_INSTANCE > 1 +#define RPL_DAO_SPECIFY_DODAG 1 +#else /* RPL_MAX_DODAG_PER_INSTANCE > 1*/ +#define RPL__DAO_SPECIFY_DODAG 0 +#endif /* RPL_MAX_DODAG_PER_INSTANCE > 1 */ +#else /* RPL_CONF_DAO_SPECIFY_DODAG */ +#define RPL_DAO_SPECIFY_DODAG RPL_CONF_DAO_SPECIFY_DODAG +#endif /* RPL_CONF_DAO_SPECIFY_DODAG */ + -/* This value is used to access an arbitrary DAG. It will likely be - replaced when we support multiple DAGs more. */ -#define RPL_ANY_INSTANCE -1 /*---------------------------------------------------------------------------*/ /* The amount of parents that this node has in a particular DAG. */ #define RPL_PARENT_COUNT(dag) list_length((dag)->parents) /*---------------------------------------------------------------------------*/ typedef uint16_t rpl_rank_t; -typedef uint8_t rpl_lifetime_t; typedef uint16_t rpl_ocp_t; +/*---------------------------------------------------------------------------*/ +/* Lollipop counters */ + +#define RPL_LOLLIPOP_MAX_VALUE 255 +#define RPL_LOLLIPOP_CIRCULAR_REGION 127 +#define RPL_LOLLIPOP_SEQUENCE_WINDOWS 16 +#define RPL_LOLLIPOP_INIT RPL_LOLLIPOP_MAX_VALUE - RPL_LOLLIPOP_SEQUENCE_WINDOWS + 1 +#define RPL_LOLLIPOP_INCREMENT(counter) (counter > RPL_LOLLIPOP_CIRCULAR_REGION ?\ + (counter == RPL_LOLLIPOP_MAX_VALUE ? counter=0 : ++counter):\ + (counter == RPL_LOLLIPOP_CIRCULAR_REGION ? counter=0 : ++counter)) +#define RPL_LOLLIPOP_IS_INIT(counter) (counter > RPL_LOLLIPOP_CIRCULAR_REGION) +#define RPL_LOLLIPOP_GREATER_THAN_LOCAL(A,B) (((A < B) && (RPL_LOLLIPOP_CIRCULAR_REGION + 1 - B + A < RPL_LOLLIPOP_SEQUENCE_WINDOWS)) || \ + ((A > B) && (A - B < RPL_LOLLIPOP_SEQUENCE_WINDOWS))) +#define RPL_LOLLIPOP_GREATER_THAN(A,B) ((A > RPL_LOLLIPOP_CIRCULAR_REGION )?\ + ((B > RPL_LOLLIPOP_CIRCULAR_REGION )?\ + RPL_LOLLIPOP_GREATER_THAN_LOCAL(A,B):\ + 0):\ + ((B > RPL_LOLLIPOP_CIRCULAR_REGION )?\ + 1:\ + RPL_LOLLIPOP_GREATER_THAN_LOCAL(A,B))) /*---------------------------------------------------------------------------*/ /* DAG Metric Container Object Types, to be confirmed by IANA. */ #define RPL_DAG_MC_NONE 0 /* Local identifier for empty MC */ @@ -139,6 +197,7 @@ struct rpl_metric_container { }; typedef struct rpl_metric_container rpl_metric_container_t; /*---------------------------------------------------------------------------*/ +struct rpl_instance; struct rpl_dag; /*---------------------------------------------------------------------------*/ struct rpl_parent { @@ -153,6 +212,35 @@ struct rpl_parent { }; typedef struct rpl_parent rpl_parent_t; /*---------------------------------------------------------------------------*/ +/* RPL DIO prefix suboption */ +struct rpl_prefix { + uip_ipaddr_t prefix; + uint32_t lifetime; + uint8_t length; + uint8_t flags; +}; +typedef struct rpl_prefix rpl_prefix_t; +/*---------------------------------------------------------------------------*/ +/* Directed Acyclic Graph */ +struct rpl_dag { + uip_ipaddr_t dag_id; + rpl_rank_t min_rank; /* should be reset per DODAG iteration! */ + uint8_t version; + uint8_t grounded; + uint8_t preference; + uint8_t used; + /* live data for the DAG */ + uint8_t joined; + rpl_parent_t *preferred_parent; + rpl_rank_t rank; + struct rpl_instance *instance; + void *parent_list; + list_t parents; + rpl_prefix_t prefix_info; +}; +typedef struct rpl_dag rpl_dag_t; +typedef struct rpl_instance rpl_instance_t; +/*---------------------------------------------------------------------------*/ /* * API for RPL objective functions (OF) * @@ -171,6 +259,10 @@ typedef struct rpl_parent rpl_parent_t; * * Compares two parents and returns the best one, according to the OF. * + * best_dag(dodag1, dodag2) + * + * Compares two dodags and returns the best one, according to the OF. + * * calculate_rank(parent, base_rank) * * Calculates a rank value using the parent rank and a base rank. @@ -188,51 +280,36 @@ struct rpl_of { void (*reset)(struct rpl_dag *); void (*parent_state_callback)(rpl_parent_t *, int, int); 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); - void (*update_metric_container)(struct rpl_dag *); + void (*update_metric_container)( rpl_instance_t *); rpl_ocp_t ocp; }; typedef struct rpl_of rpl_of_t; /*---------------------------------------------------------------------------*/ -/* RPL DIO prefix suboption */ -struct rpl_prefix { - uip_ipaddr_t prefix; - uint32_t lifetime; - uint8_t length; - uint8_t flags; -}; -typedef struct rpl_prefix rpl_prefix_t; -/*---------------------------------------------------------------------------*/ -/* Directed Acyclic Graph */ -struct rpl_dag { +/* Instance */ +struct rpl_instance { /* DAG configuration */ rpl_metric_container_t mc; rpl_of_t *of; - uip_ipaddr_t dag_id; + rpl_dag_t *current_dag; + rpl_dag_t dag_table[RPL_MAX_DODAG_PER_INSTANCE]; /* The current default router - used for routing "upwards" */ uip_ds6_defrt_t *def_route; - rpl_rank_t rank; - rpl_rank_t min_rank; /* should be reset per DODAG iteration! */ - uint8_t dtsn_out; uint8_t instance_id; - uint8_t version; - uint8_t grounded; + uint8_t used; + uint8_t dtsn_out; uint8_t mop; - uint8_t preference; uint8_t dio_intdoubl; uint8_t dio_intmin; uint8_t dio_redundancy; + uint8_t default_lifetime; + uint8_t dio_intcurrent; + uint8_t dio_send; /* for keeping track of which mode the timer is in */ + uint8_t dio_counter; rpl_rank_t max_rankinc; rpl_rank_t min_hoprankinc; - uint8_t used; - uint8_t default_lifetime; uint16_t lifetime_unit; /* lifetime in seconds = l_u * d_l */ - /* live data for the DAG */ - uint8_t joined; - uint8_t dio_intcurrent; - uint8_t dio_send; /* for keeping track of which mode the timer is in -*/ - uint8_t dio_counter; #if RPL_CONF_STATS uint16_t dio_totint; uint16_t dio_totsend; @@ -241,19 +318,23 @@ struct rpl_dag { uint32_t dio_next_delay; /* delay for completion of dio interval */ struct ctimer dio_timer; struct ctimer dao_timer; - rpl_parent_t *preferred_parent; - void *parent_list; - list_t parents; - rpl_prefix_t prefix_info; }; -typedef struct rpl_dag rpl_dag_t; + /*---------------------------------------------------------------------------*/ /* Public RPL functions. */ void rpl_init(void); -rpl_dag_t *rpl_set_root(uip_ipaddr_t *); -int rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, int len); -int rpl_repair_dag(rpl_dag_t *dag); -int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from); -rpl_dag_t *rpl_get_dag(int instance_id); +void uip_rpl_input(void); +rpl_dag_t *rpl_set_root(uint8_t instance_id, uip_ipaddr_t * dag_id); +int rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len); +int rpl_repair_root(uint8_t instance_id); +int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from); +rpl_dag_t *rpl_get_any_dag(void); +rpl_dag_t *rpl_get_dodag(uint8_t instance_id, uip_ipaddr_t *dag_id); +rpl_instance_t *rpl_get_instance(uint8_t instance_id); +void rpl_update_header_empty(void); +int rpl_update_header_final(uip_ipaddr_t *addr); +int rpl_verify_header(int); +void rpl_remove_header(void); +uint8_t rpl_invert_header(void); /*---------------------------------------------------------------------------*/ #endif /* RPL_H */ diff --git a/core/net/tcpip.c b/core/net/tcpip.c index 5ddd2fb1d..7556b1239 100644 --- a/core/net/tcpip.c +++ b/core/net/tcpip.c @@ -27,10 +27,8 @@ * SUCH DAMAGE. * * This file is part of the Contiki operating system. - * - * - * $Id: tcpip.c,v 1.30 2010/10/29 05:36:07 adamdunkels Exp $ */ + /** * \file * Code for tunnelling uIP packets over the Rime mesh routing module @@ -39,29 +37,20 @@ * \author Mathilde Durvy (IPv6 related code) * \author Julien Abeille (IPv6 related code) */ + #include "contiki-net.h" - #include "net/uip-split.h" - #include "net/uip-packetqueue.h" -#include - #if UIP_CONF_IPV6 #include "net/uip-nd6.h" #include "net/uip-ds6.h" #endif -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",lladdr->addr[0], lladdr->addr[1], lladdr->addr[2], lladdr->addr[3],lladdr->addr[4], lladdr->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#endif +#include + +#define DEBUG DEBUG_NONE +#include "net/uip-debug.h" #if UIP_LOGGING #include @@ -78,21 +67,21 @@ void uip_log(char *msg); #ifdef UIP_FALLBACK_INTERFACE extern struct uip_fallback_interface UIP_FALLBACK_INTERFACE; #endif + #if UIP_CONF_IPV6_RPL -void rpl_init(void); +#include "rpl/rpl.h" #endif + process_event_t tcpip_event; #if UIP_CONF_ICMP6 process_event_t tcpip_icmp6_event; #endif /* UIP_CONF_ICMP6 */ -/*static struct tcpip_event_args ev_args;*/ - -/*periodic check of active connections*/ +/* Periodic check of active connections. */ static struct etimer periodic; #if UIP_CONF_IPV6 && UIP_CONF_IPV6_REASSEMBLY -/*timer for reassembly*/ +/* Timer for reassembly. */ extern struct etimer uip_reass_timer; #endif @@ -412,21 +401,19 @@ eventhandler(process_event_t ev, process_data_t data) cptr->appstate.p = PROCESS_NONE; cptr->tcpstateflags = UIP_CLOSED; } - } - } #endif /* UIP_TCP */ #if UIP_UDP { register struct uip_udp_conn *cptr; + for(cptr = &uip_udp_conns[0]; cptr < &uip_udp_conns[UIP_UDP_CONNS]; ++cptr) { if(cptr->appstate.p == p) { cptr->lport = 0; } } - } #endif /* UIP_UDP */ break; @@ -477,12 +464,12 @@ eventhandler(process_event_t ev, process_data_t data) * check the different timers for neighbor discovery and * stateless autoconfiguration */ - /*if(data == &uip_nd6_timer_periodic && - etimer_expired(&uip_nd6_timer_periodic)) { - uip_nd6_periodic(); + /*if(data == &uip_ds6_timer_periodic && + etimer_expired(&uip_ds6_timer_periodic)) { + uip_ds6_periodic(); tcpip_ipv6_output(); }*/ -#if !UIP_CONF_ROUTER +#if !UIP_CONF_ROUTER if(data == &uip_ds6_timer_rs && etimer_expired(&uip_ds6_timer_rs)){ uip_ds6_send_rs(); @@ -551,22 +538,24 @@ void tcpip_ipv6_output(void) { uip_ds6_nbr_t *nbr = NULL; - uip_ipaddr_t* nexthop; - + uip_ipaddr_t *nexthop; + if(uip_len == 0) { return; } - + if(uip_len > UIP_LINK_MTU) { UIP_LOG("tcpip_ipv6_output: Packet to big"); uip_len = 0; return; } + if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){ UIP_LOG("tcpip_ipv6_output: Destination address unspecified"); uip_len = 0; return; } + if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { /* Next hop determination */ nbr = NULL; @@ -578,10 +567,18 @@ tcpip_ipv6_output(void) if(locrt == NULL) { if((nexthop = uip_ds6_defrt_choose()) == NULL) { #ifdef UIP_FALLBACK_INTERFACE + printf("FALLBACK: removing ext hdrs & setting proto %d %d\n", + uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40)); + if(uip_ext_len > 0) { + uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40); + remove_ext_hdr(); + /* This should be copied from the ext header... */ + UIP_IP_BUF->proto = proto; + } UIP_FALLBACK_INTERFACE.output(); #else PRINTF("tcpip_ipv6_output: Destination off-link but no route\n"); -#endif +#endif /* !UIP_FALLBACK_INTERFACE */ uip_len = 0; return; } @@ -589,16 +586,20 @@ tcpip_ipv6_output(void) nexthop = &locrt->nexthop; } } - /* end of next hop determination */ + /* End of next hop determination */ +#if UIP_CONF_IPV6_RPL + if(rpl_update_header_final(nexthop)) { + uip_len = 0; + return; + } +#endif /* UIP_CONF_IPV6_RPL */ if((nbr = uip_ds6_nbr_lookup(nexthop)) == NULL) { - // printf("add1 %d\n", nexthop->u8[15]); if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) { - // printf("add n\n"); uip_len = 0; return; } else { #if UIP_CONF_IPV6_QUEUE_PKT - /* copy outgoing pkt in the queuing buffer for later transmmit */ + /* Copy outgoing pkt in the queuing buffer for later transmit. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); @@ -616,59 +617,47 @@ tcpip_ipv6_output(void) uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); } - stimer_set(&(nbr->sendns), uip_ds6_if.retrans_timer / 1000); + stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); nbr->nscount = 1; } } else { if(nbr->state == NBR_INCOMPLETE) { PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n"); #if UIP_CONF_IPV6_QUEUE_PKT - /* copy outgoing pkt in the queuing buffer for later transmmit and set - the destination nbr to nbr */ + /* Copy outgoing pkt in the queuing buffer for later transmit and set + the destination nbr to nbr. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } - /* memcpy(nbr->queue_buf, UIP_IP_BUF, uip_len); - nbr->queue_buf_len = uip_len;*/ #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } - /* if running NUD (nbc->state == STALE, DELAY, or PROBE ) keep - sending in parallel see rfc 4861 Node behavior in section 7.7.3*/ - + /* Send in parallel if we are running NUD (nbc state is either STALE, + DELAY, or PROBE). See RFC 4861, section 7.7.3 on node behavior. */ if(nbr->state == NBR_STALE) { nbr->state = NBR_DELAY; - stimer_set(&(nbr->reachable), - UIP_ND6_DELAY_FIRST_PROBE_TIME); + stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n"); } - - stimer_set(&(nbr->sendns), - uip_ds6_if.retrans_timer / 1000); - - tcpip_output(&(nbr->lladdr)); + stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); + tcpip_output(&nbr->lladdr); #if UIP_CONF_IPV6_QUEUE_PKT - /* Send the queued packets from here, may not be 100% perfect though. + /* + * Send the queued packets from here, may not be 100% perfect though. * This happens in a few cases, for example when instead of receiving a * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves - *to STALE, and you must both send a NA and the queued packet + * to STALE, and you must both send a NA and the queued packet. */ - /* if(nbr->queue_buf_len != 0) { - uip_len = nbr->queue_buf_len; - memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); - nbr->queue_buf_len = 0; - tcpip_output(&(nbr->lladdr)); - }*/ if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); - tcpip_output(&(nbr->lladdr)); + tcpip_output(&nbr->lladdr); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ @@ -676,14 +665,13 @@ tcpip_ipv6_output(void) return; } } - - /*multicast IP destination address */ + + /* Multicast IP destination address. */ tcpip_output(NULL); uip_len = 0; uip_ext_len = 0; - } -#endif +#endif /* UIP_CONF_IPV6 */ /*---------------------------------------------------------------------------*/ #if UIP_UDP void diff --git a/core/net/uip-ds6.c b/core/net/uip-ds6.c index 7e3cf1882..22ebea15a 100644 --- a/core/net/uip-ds6.c +++ b/core/net/uip-ds6.c @@ -5,9 +5,9 @@ /** * \file - * IPv6 data structures handling functions + * IPv6 data structures handling functions. * Comprises part of the Neighbor discovery (RFC 4861) - * and auto configuration (RFC 4862 )state machines + * and auto configuration (RFC 4862) state machines. * \author Mathilde Durvy * \author Julien Abeille */ @@ -148,16 +148,19 @@ uip_ds6_init(void) void uip_ds6_periodic(void) { + /* Periodic processing on unicast addresses */ for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { if(locaddr->isused) { if((!locaddr->isinfinite) && (stimer_expired(&locaddr->vlifetime))) { uip_ds6_addr_rm(locaddr); +#if UIP_ND6_DEF_MAXDADNS > 0 } else if((locaddr->state == ADDR_TENTATIVE) && (locaddr->dadnscount <= uip_ds6_if.maxdadns) && (timer_expired(&locaddr->dadtimer))) { uip_ds6_dad(locaddr); +#endif /* UIP_ND6_DEF_MAXDADNS > 0 */ } } } @@ -366,6 +369,24 @@ uip_ds6_nbr_lookup(uip_ipaddr_t *ipaddr) return NULL; } +/*---------------------------------------------------------------------------*/ +uip_ds6_nbr_t * +uip_ds6_nbr_ll_lookup(uip_lladdr_t *lladdr) +{ + uip_ds6_nbr_t *fin; + + for(locnbr = uip_ds6_nbr_cache, fin = locnbr + UIP_DS6_NBR_NB; + locnbr < fin; + ++locnbr) { + if(locnbr->isused) { + if(!memcmp(lladdr, &locnbr->lladdr, UIP_LLADDR_LEN)) { + return locnbr; + } + } + } + return NULL; +} + /*---------------------------------------------------------------------------*/ uip_ds6_defrt_t * uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval) @@ -549,7 +570,6 @@ uip_ds6_addr_add(uip_ipaddr_t *ipaddr, unsigned long vlifetime, uint8_t type) (uip_ds6_element_t **)&locaddr) == FREESPACE) { locaddr->isused = 1; uip_ipaddr_copy(&locaddr->ipaddr, ipaddr); - locaddr->state = ADDR_TENTATIVE; locaddr->type = type; if(vlifetime == 0) { locaddr->isinfinite = 1; @@ -557,10 +577,15 @@ uip_ds6_addr_add(uip_ipaddr_t *ipaddr, unsigned long vlifetime, uint8_t type) locaddr->isinfinite = 0; stimer_set(&(locaddr->vlifetime), vlifetime); } +#if UIP_ND6_DEF_MAXDADNS > 0 + locaddr->state = ADDR_TENTATIVE; timer_set(&locaddr->dadtimer, random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY * CLOCK_SECOND)); locaddr->dadnscount = 0; +#else /* UIP_ND6_DEF_MAXDADNS > 0 */ + locaddr->state = ADDR_PREFERRED; +#endif /* UIP_ND6_DEF_MAXDADNS > 0 */ uip_create_solicited_node(ipaddr, &loc_fipaddr); uip_ds6_maddr_add(&loc_fipaddr); return locaddr; @@ -759,6 +784,10 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop, uip_ipaddr_copy(&(locroute->nexthop), nexthop); locroute->metric = metric; +#ifdef UIP_DS6_ROUTE_STATE_TYPE + memset(&locroute->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE)); +#endif + PRINTF("DS6: adding route: "); PRINT6ADDR(ipaddr); PRINTF(" via "); @@ -884,6 +913,7 @@ get_match_length(uip_ipaddr_t *src, uip_ipaddr_t *dst) } /*---------------------------------------------------------------------------*/ +#if UIP_ND6_DEF_MAXDADNS > 0 void uip_ds6_dad(uip_ds6_addr_t *addr) { @@ -922,10 +952,11 @@ uip_ds6_dad_failed(uip_ds6_addr_t * addr) uip_ds6_addr_rm(addr); return 1; } +#endif /*UIP_ND6_DEF_MAXDADNS > 0 */ +/*---------------------------------------------------------------------------*/ #if UIP_CONF_ROUTER #if UIP_ND6_SEND_RA -/*---------------------------------------------------------------------------*/ void uip_ds6_send_ra_sollicited(void) { diff --git a/core/net/uip-ds6.h b/core/net/uip-ds6.h index 064587ac2..dc608ef16 100644 --- a/core/net/uip-ds6.h +++ b/core/net/uip-ds6.h @@ -124,6 +124,13 @@ #endif #define UIP_DS6_AADDR_NB UIP_DS6_AADDR_NBS + UIP_DS6_AADDR_NBU +/*--------------------------------------------------*/ +/* Should we use LinkLayer acks in NUD ?*/ +#ifndef UIP_CONF_DS6_LL_NUD +#define UIP_DS6_LL_NUD 0 +#else +#define UIP_DS6_LL_NUD UIP_CONF_DS6_LL_NUD +#endif /*--------------------------------------------------*/ /** \brief Possible states for the nbr cache entries */ @@ -209,8 +216,10 @@ typedef struct uip_ds6_addr { uint8_t type; uint8_t isinfinite; struct stimer vlifetime; +#if UIP_ND6_DEF_MAXDADNS > 0 struct timer dadtimer; uint8_t dadnscount; +#endif /* UIP_ND6_DEF_MAXDADNS > 0 */ } uip_ds6_addr_t; /** \brief Anycast address */ @@ -310,6 +319,7 @@ uip_ds6_nbr_t *uip_ds6_nbr_add(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr, uint8_t isrouter, uint8_t state); void uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr); uip_ds6_nbr_t *uip_ds6_nbr_lookup(uip_ipaddr_t *ipaddr); +uip_ds6_nbr_t *uip_ds6_nbr_ll_lookup(uip_lladdr_t *lladdr); /** @} */ @@ -385,11 +395,13 @@ void uip_ds6_set_addr_iid(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr); /** \brief Get the number of matching bits of two addresses */ uint8_t get_match_length(uip_ipaddr_t * src, uip_ipaddr_t * dst); +#if UIP_ND6_DEF_MAXDADNS >0 /** \brief Perform Duplicate Address Selection on one address */ void uip_ds6_dad(uip_ds6_addr_t * ifaddr); /** \brief Callback when DAD failed */ int uip_ds6_dad_failed(uip_ds6_addr_t * ifaddr); +#endif /* UIP_ND6_DEF_MAXDADNS */ /** \brief Source address selection, see RFC 3484 */ void uip_ds6_select_src(uip_ipaddr_t * src, uip_ipaddr_t * dst); diff --git a/core/net/uip-icmp6.c b/core/net/uip-icmp6.c index 3bb554461..73aaf2a0b 100644 --- a/core/net/uip-icmp6.c +++ b/core/net/uip-icmp6.c @@ -60,14 +60,25 @@ #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) #define UIP_ICMP6_ERROR_BUF ((struct uip_icmp6_error *)&uip_buf[uip_l2_l3_icmp_hdr_len]) +#if UIP_CONF_IPV6_RPL +#define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len]) +#define UIP_FIRST_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[UIP_LLIPH_LEN]) +#endif /* UIP_CONF_IPV6_RPL */ /** \brief temporary IP address */ static uip_ipaddr_t tmp_ipaddr; +#if UIP_CONF_IPV6_RPL +#include "rpl/rpl.h" +#endif /* UIP_CONF_IPV6_RPL */ + /*---------------------------------------------------------------------------*/ void uip_icmp6_echo_request_input(void) { +#if UIP_CONF_IPV6_RPL + u8_t temp_ext_len; +#endif /* UIP_CONF_IPV6_RPL */ /* * we send an echo reply. It is trivial if there was no extension * headers in the request otherwise we need to remove the extension @@ -78,7 +89,7 @@ uip_icmp6_echo_request_input(void) PRINTF("to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); - + /* IP header */ UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit; @@ -92,30 +103,54 @@ uip_icmp6_echo_request_input(void) } if(uip_ext_len > 0) { - /* If there were extension headers*/ - UIP_IP_BUF->proto = UIP_PROTO_ICMP6; - uip_len -= uip_ext_len; - UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); - UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); - /* move the echo request payload (starting after the icmp header) - * to the new location in the reply. - * The shift is equal to the length of the extension headers present - * Note: UIP_ICMP_BUF still points to the echo request at this stage - */ - memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len, - (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, - (uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN)); +#if UIP_CONF_IPV6_RPL + if ((temp_ext_len=rpl_invert_header())) { + /* If there were other extension headers*/ + UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6; + if (uip_ext_len != temp_ext_len) { + uip_len -= (uip_ext_len - temp_ext_len); + UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); + /* move the echo request payload (starting after the icmp header) + * to the new location in the reply. + * The shift is equal to the length of the remaining extension headers present + * Note: UIP_ICMP_BUF still points to the echo request at this stage + */ + memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - (uip_ext_len - temp_ext_len), + (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, + (uip_len - UIP_IPH_LEN - temp_ext_len - UIP_ICMPH_LEN)); + } + uip_ext_len=temp_ext_len; + } else { +#endif /* UIP_CONF_IPV6_RPL */ + /* If there were extension headers*/ + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + uip_len -= uip_ext_len; + UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); + /* move the echo request payload (starting after the icmp header) + * to the new location in the reply. + * The shift is equal to the length of the extension headers present + * Note: UIP_ICMP_BUF still points to the echo request at this stage + */ + memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len, + (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, + (uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN)); + uip_ext_len = 0; +#if UIP_CONF_IPV6_RPL + } +#endif /* UIP_CONF_IPV6_RPL */ } /* Below is important for the correctness of UIP_ICMP_BUF and the * checksum */ - uip_ext_len = 0; + /* Note: now UIP_ICMP_BUF points to the beginning of the echo reply */ UIP_ICMP_BUF->type = ICMP6_ECHO_REPLY; UIP_ICMP_BUF->icode = 0; UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); - + PRINTF("Sending Echo Reply to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("from"); @@ -127,29 +162,45 @@ uip_icmp6_echo_request_input(void) /*---------------------------------------------------------------------------*/ void uip_icmp6_error_output(u8_t type, u8_t code, u32_t param) { - uip_ext_len = 0; /* check if originating packet is not an ICMP error*/ - if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type < 128){ - uip_len = 0; - return; + if (uip_ext_len) { + if(UIP_EXT_BUF->next == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type < 128){ + uip_len = 0; + return; + } + } else { + if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type < 128){ + uip_len = 0; + return; + } } - /* remember data of original packet before shifting */ - uip_ipaddr_copy(&tmp_ipaddr, &UIP_IP_BUF->destipaddr); - - uip_len += UIP_IPICMPH_LEN + UIP_ICMP6_ERROR_LEN; - - if(uip_len > UIP_LINK_MTU) - uip_len = UIP_LINK_MTU; +#if UIP_CONF_IPV6_RPL + uip_ext_len = rpl_invert_header(); +#else /* UIP_CONF_IPV6_RPL */ + uip_ext_len = 0; +#endif /* UIP_CONF_IPV6_RPL */ - memmove((uint8_t *)UIP_ICMP6_ERROR_BUF + UIP_ICMP6_ERROR_LEN, - (void *)UIP_IP_BUF, uip_len - UIP_IPICMPH_LEN - UIP_ICMP6_ERROR_LEN); + /* remember data of original packet before shifting */ + uip_ipaddr_copy(&tmp_ipaddr, &UIP_IP_BUF->destipaddr); + + uip_len += UIP_IPICMPH_LEN + UIP_ICMP6_ERROR_LEN; + + if(uip_len > UIP_LINK_MTU) + uip_len = UIP_LINK_MTU; + + memmove((uint8_t *)UIP_ICMP6_ERROR_BUF + uip_ext_len + UIP_ICMP6_ERROR_LEN, + (void *)UIP_IP_BUF, uip_len - UIP_IPICMPH_LEN - uip_ext_len - UIP_ICMP6_ERROR_LEN); UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 0; UIP_IP_BUF->flow = 0; - UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + if (uip_ext_len) { + UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6; + } else { + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + } UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit; /* the source should not be unspecified nor multicast, the check for @@ -158,7 +209,7 @@ uip_icmp6_error_output(u8_t type, u8_t code, u32_t param) { uip_len = 0; return; } - + uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr); if(uip_is_addr_mcast(&tmp_ipaddr)){ @@ -176,7 +227,7 @@ uip_icmp6_error_output(u8_t type, u8_t code, u32_t param) { uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr); #endif } - + UIP_ICMP_BUF->type = type; UIP_ICMP_BUF->icode = code; UIP_ICMP6_ERROR_BUF->param = uip_htonl(param); diff --git a/core/net/uip-nd6.c b/core/net/uip-nd6.c index 1874cec51..13b650064 100644 --- a/core/net/uip-nd6.c +++ b/core/net/uip-nd6.c @@ -76,16 +76,7 @@ /*------------------------------------------------------------------*/ #define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",lladdr->addr[0], lladdr->addr[1], lladdr->addr[2], lladdr->addr[3],lladdr->addr[4], lladdr->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif +#include "net/uip-debug.h" #if UIP_LOGGING #include @@ -154,11 +145,11 @@ create_llao(uint8_t *llao, uint8_t type) { void uip_nd6_ns_input(void) { - PRINTF("Received NS from"); + PRINTF("Received NS from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); - PRINTF("to"); + PRINTF(" to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); - PRINTF("with target address"); + PRINTF(" with target address"); PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NS_BUF->tgtipaddr)); PRINTF("\n"); UIP_STAT(++uip_stat.nd6.recv); @@ -224,6 +215,7 @@ uip_nd6_ns_input(void) addr = uip_ds6_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr); if(addr != NULL) { +#if UIP_ND6_DEF_MAXDADNS > 0 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { /* DAD CASE */ #if UIP_CONF_IPV6_CHECKS @@ -242,6 +234,11 @@ uip_nd6_ns_input(void) uip_ds6_dad_failed(addr); goto discard; } +#else /* UIP_ND6_DEF_MAXDADNS > 0 */ + if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { + /* DAD CASE */ + goto discard; +#endif /* UIP_ND6_DEF_MAXDADNS > 0 */ } #if UIP_CONF_IPV6_CHECKS if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)) { @@ -307,11 +304,11 @@ create_na: UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; UIP_STAT(++uip_stat.nd6.sent); - PRINTF("Sending NA to"); + PRINTF("Sending NA to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); - PRINTF("from"); + PRINTF(" from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); - PRINTF("with target address"); + PRINTF(" with target address "); PRINT6ADDR(&UIP_ND6_NA_BUF->tgtipaddr); PRINTF("\n"); return; @@ -441,9 +438,11 @@ uip_nd6_na_input(void) addr = uip_ds6_addr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); /* Message processing, including TLLAO if any */ if(addr != NULL) { +#if UIP_ND6_DEF_MAXDADNS > 0 if(addr->state == ADDR_TENTATIVE) { uip_ds6_dad_failed(addr); } +#endif /*UIP_ND6_DEF_MAXDADNS > 0 */ PRINTF("NA received is bad\n"); goto discard; } else { diff --git a/core/net/uip-nd6.h b/core/net/uip-nd6.h index 38597ae63..c62e0363e 100644 --- a/core/net/uip-nd6.h +++ b/core/net/uip-nd6.h @@ -48,8 +48,8 @@ #include "net/uip.h" #include "sys/stimer.h" /** - * \name General - * @{ + * \name General + * @{ */ /** \brief HOP LIMIT to be used when sending ND messages (255) */ #define UIP_ND6_HOP_LIMIT 255 @@ -57,29 +57,21 @@ #define UIP_ND6_INFINITE_LIFETIME 0xFFFFFFFF /** @} */ +#ifndef UIP_CONF_ND6_DEF_MAXDADNS +/** \brief Do not try DAD when using EUI-64 as allowed by draft-ietf-6lowpan-nd-15 section 8.2 */ +#if UIP_CONF_LL_802154 +#define UIP_ND6_DEF_MAXDADNS 0 +#else /* UIP_CONF_LL_802154 */ #define UIP_ND6_DEF_MAXDADNS 1 - -/** \name Configuration options */ -/** @{ */ -#ifndef UIP_CONF_ND6_MAX_NEIGHBORS -/** \brief max number of entries in the neighbor cache */ -#define UIP_CONF_ND6_MAX_NEIGHBORS 4 -#endif /*UIP_CONF_ND6_MAX_NEIGHBORS*/ -#ifndef UIP_CONF_ND6_MAX_DEFROUTERS -/** \brief max number of entries in the default router cache */ -#define UIP_CONF_ND6_MAX_DEFROUTERS 2 -#endif /*UIP_CONF_ND6_MAX_DEFROUTERS*/ -#ifndef UIP_CONF_ND6_MAX_PREFIXES -/** \brief max number of entries in the prefix list */ -#define UIP_CONF_ND6_MAX_PREFIXES 2 -#endif /*UIP_CONF_ND6_MAX_PREFIXES*/ -/** @} */ - +#endif /* UIP_CONF_LL_802154 */ +#else /* UIP_CONF_ND6_DEF_MAXDADNS */ +#define UIP_ND6_DEF_MAXDADNS UIP_CONF_ND6_DEF_MAXDADNS +#endif /* UIP_CONF_ND6_DEF_MAXDADNS */ /** \name RFC 4861 Host constant */ /** @{ */ -#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY 1 -#define UIP_ND6_RTR_SOLICITATION_INTERVAL 4 +#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY 1 +#define UIP_ND6_RTR_SOLICITATION_INTERVAL 4 #define UIP_ND6_MAX_RTR_SOLICITATIONS 3 /** @} */ @@ -115,7 +107,7 @@ #ifdef UIP_CONF_ND6_RETRANS_TIMER #define UIP_ND6_RETRANS_TIMER UIP_CONF_ND6_RETRANS_TIMER #else -#define UIP_ND6_RETRANS_TIMER 1000 +#define UIP_ND6_RETRANS_TIMER 1000 #endif #define UIP_ND6_DELAY_FIRST_PROBE_TIME 5 #define UIP_ND6_MIN_RANDOM_FACTOR(x) (x / 2) @@ -140,8 +132,8 @@ /** \name ND6 message length (excluding options) */ /** @{ */ -#define UIP_ND6_NA_LEN 20 -#define UIP_ND6_NS_LEN 20 +#define UIP_ND6_NA_LEN 20 +#define UIP_ND6_NS_LEN 20 #define UIP_ND6_RA_LEN 12 #define UIP_ND6_RS_LEN 4 /** @} */ @@ -160,7 +152,7 @@ #define UIP_ND6_OPT_SHORT_LLAO_LEN 8 #define UIP_ND6_OPT_LONG_LLAO_LEN 16 /** \brief length of a ND6 LLAO option for 802.15.4 */ -#define UIP_ND6_OPT_LLAO_LEN UIP_ND6_OPT_LONG_LLAO_LEN +#define UIP_ND6_OPT_LLAO_LEN UIP_ND6_OPT_LONG_LLAO_LEN #else /*UIP_CONF_LL_802154*/ #if UIP_CONF_LL_80211 /* If the interface is 802.11 */ @@ -179,93 +171,18 @@ #define UIP_ND6_NA_FLAG_ROUTER 0x80 #define UIP_ND6_NA_FLAG_SOLICITED 0x40 #define UIP_ND6_NA_FLAG_OVERRIDE 0x20 -#define UIP_ND6_RA_FLAG_ONLINK 0x80 -#define UIP_ND6_RA_FLAG_AUTONOMOUS 0x40 +#define UIP_ND6_RA_FLAG_ONLINK 0x80 +#define UIP_ND6_RA_FLAG_AUTONOMOUS 0x40 /** @} */ - -/** - * \brief Possible states for the neighbor cache entries - * - * NO_STATE is for implementation purposes: a router entry contains a pointer - * to a neighbor entry, which holds its ip address. If we do not know the LL - * address of the router, we do not have to create a neighbor entry as per - * RFC 4861. However, we still need to have the IP of the router stored in a - * neighbor entry, hence we create an entry in the NO_STATE state - */ -typedef enum { - INCOMPLETE = 0, - REACHABLE = 1, - STALE = 2, - DELAY = 3, - PROBE = 4, - NO_STATE = 5 -} uip_neighbor_state; - -/** - * \name ND structures - * @{ - */ -/** \brief An entry in the neighbor cache */ -struct uip_nd6_neighbor { - uip_ipaddr_t ipaddr; - uip_lladdr_t lladdr; - u8_t isrouter; - uip_neighbor_state state; - struct stimer reachable; - struct stimer last_send; /**< last time a ND message was sent */ - u8_t count_send; /**< how many ND message were already sent */ - u8_t used; /**< brief is this neighbor currently used */ -#if UIP_CONF_IPV6_QUEUE_PKT - u8_t queue_buf[UIP_BUFSIZE - UIP_LLH_LEN]; - /**< buffer to hold one packet during address resolution */ - u8_t queue_buf_len; - /**< length of the pkt in buffer, used as "boolean" as well*/ -#endif /*UIP_CONF_QUEUE_PKT*/ -}; - - -/** \brief An entry in the default router list */ -struct uip_nd6_defrouter { - struct uip_nd6_neighbor *nb; - struct stimer lifetime; - /**< the lifetime contained in RA corresponds to the interval field - * of the timer - */ - u8_t used; /**< Is this default router entry currently used */ -}; - -/** \brief A prefix list entry */ -struct uip_nd6_prefix { - uip_ipaddr_t ipaddr; - u8_t length; - /**< we do not use preferred lifetime, which is always smaller than - * valid lifetime (for addr, preferred->deprecated) - */ - struct stimer vlifetime; - u8_t is_infinite; /**< Is the prefix lifetime INFINITE */ - u8_t used; /**< Is this prefix entry currently used */ -}; -/** @} */ - -extern struct etimer uip_nd6_timer_periodic; - -/** - * \note - * We do not use a destination cache, do next-hop determination each time - * a packet needs to be sent. (info such as rtt, path mtu could be stored - * in uip_conn) - * - */ - /** * \name ND message structures * @{ */ -/** +/** * \brief A neighbor solicitation constant part - * + * * Possible option is: SLLAO */ typedef struct uip_nd6_ns { @@ -275,19 +192,19 @@ typedef struct uip_nd6_ns { /** * \brief A neighbor advertisement constant part. - * + * * Possible option is: TLLAO - */ + */ typedef struct uip_nd6_na { uint8_t flagsreserved; uint8_t reserved[3]; uip_ipaddr_t tgtipaddr; } uip_nd6_na; -/** +/** * \brief A router solicitation constant part - * - * Possible option is: SLLAO + * + * Possible option is: SLLAO */ typedef struct uip_nd6_rs { uint32_t reserved; @@ -295,7 +212,7 @@ typedef struct uip_nd6_rs { /** * \brief A router advertisement constant part - * + * * Possible options are: SLLAO, MTU, Prefix Information */ typedef struct uip_nd6_ra { @@ -308,13 +225,13 @@ typedef struct uip_nd6_ra { /** * \brief A redirect message constant part - * + * * Possible options are: TLLAO, redirected header */ typedef struct uip_nd6_redirect { uint32_t reserved; - uip_ipaddr_t tgtipaddress; - uip_ipaddr_t destipaddress; + uip_ipaddr_t tgtipaddress; + uip_ipaddr_t destipaddress; } uip_nd6_redirect; /** @} */ @@ -357,102 +274,6 @@ typedef struct uip_nd6_opt_redirected_hdr { } uip_nd6_opt_redirected_hdr; /** @} */ -/** - * \name ND Neighbor Cache, Router List and Prefix List handling functions - * @{ - */ -/** - * \brief Initialize Neighbor Discovery structures - */ -void uip_nd6_init(void); - -/** - * \brief Periodic processing of Neighbor Discovery Structures - */ -void uip_nd6_periodic(void); - -/** - * \brief Look for a neighbor cache entry corresponding to a specific IP - * address - * \param ipaddr the specific IP address - * \return the corresponding neighbor cache entry - */ -struct uip_nd6_neighbor *uip_nd6_nbrcache_lookup(uip_ipaddr_t *ipaddr); - -/** - * \brief Add a neighbor cache entry - * \param ipaddr the IP address of the entry - * \param lladdr the layer 2 address of the entry - * \param isrouter true is the entry is a router - * \param state the state of the entry - * \return the new neighbor or updated cache entry - */ -struct uip_nd6_neighbor * uip_nd6_nbrcache_add(uip_ipaddr_t *ipaddr, - uip_lladdr_t *lladdr, - u8_t isrouter, - uip_neighbor_state state); -/** - * \brief Returns a default router - */ -struct uip_nd6_defrouter * uip_nd6_choose_defrouter(void); - -/** - * \brief Find a default router corresponding to a given neighbor cache entry - * \param neighbor the neighbor cache entry - * \return the corresponding router if any - */ -struct uip_nd6_defrouter * -uip_nd6_defrouter_lookup(struct uip_nd6_neighbor *neighbor); - -/** - * \brief Remove a default router - * \param router to be removed - */ -void uip_nd6_defrouter_rm(struct uip_nd6_defrouter *router); - -/** - * \brief Add a default router - * \param neighbor the corresponding neighbor cache entry - * \param interval the lifetime of the router - * \return the new or updated defrouter entry - */ -struct uip_nd6_defrouter * -uip_nd6_defrouter_add(struct uip_nd6_neighbor *neighbor, unsigned long interval); - -/** - * \brief Check if an IP address in on-link by looking at prefix list - * \param ipaddr an IP address - * \return true if on-link - */ -u8_t uip_nd6_is_addr_onlink(uip_ipaddr_t *ipaddr); - -/** - * \brief Find a given prefix - * \param ipaddr an IP address - * \return the corresponding prefix if any - */ -struct uip_nd6_prefix * -uip_nd6_prefix_lookup(uip_ipaddr_t *ipaddr); - -/** - * \brief Add a prefix - * \param ipaddr the IP address of the prefix - * \param length the length of the prefix - * \param interval the lifetime of the prefix - * \return the new or updated prefix entry - */ -struct uip_nd6_prefix * -uip_nd6_prefix_add(uip_ipaddr_t *ipaddr, u8_t length, unsigned long interval); - -/** - * \brief Remove a prefix from th eprefix list - * \param prefix pointer to the prefix to be removed - */ -void - uip_nd6_prefix_rm(struct uip_nd6_prefix *prefix); -/** @} */ - - /** * \name ND Messages Processing and Generation * @{ @@ -467,7 +288,7 @@ void * address) * * We do: - * - if the tgt belongs to me, reply, otherwise ignore + * - if the tgt belongs to me, reply, otherwise ignore * - if i was performing DAD for the same address, two cases: * -- I already sent a NS, hence I win * -- I did not send a NS yet, hence I lose @@ -476,13 +297,13 @@ void * address resolution, or DAD and there is a conflict), we do it in this * function: set src, dst, tgt address in the three cases, then for all cases * set the rest, including SLLAO - * + * */ void uip_nd6_ns_input(void); /** - * \brief Send a neighbor solicitation, send a Neighbor Advertisement + * \brief Send a neighbor solicitation, send a Neighbor Advertisement * \param src pointer to the src of the NS if known * \param dest pointer to ip address to send the NS, for DAD or ADDR Resol, * MUST be NULL, for NUD, must be correct unicast dest @@ -496,13 +317,13 @@ uip_nd6_ns_input(void); * solicitation. Otherwise, any one of the addresses assigned to the * interface should be used." * This is why we have a src ip address as argument. If NULL, we will do - * src address selection, otherwise we use the argument. - * + * src address selection, otherwise we use the argument. + * * - we check if it is a NS for Address resolution or NUD, if yes we include * a SLLAO option, otherwise no. */ void -uip_nd6_ns_output(uip_ipaddr_t *src, uip_ipaddr_t *dest, uip_ipaddr_t *tgt); +uip_nd6_ns_output(uip_ipaddr_t *src, uip_ipaddr_t *dest, uip_ipaddr_t *tgt); /** * \brief Process a Neighbor Advertisement @@ -528,7 +349,7 @@ uip_nd6_na_input(void); #if UIP_ND6_SEND_RA /** * \brief Process a Router Solicitation - * + * */ void uip_nd6_rs_input(void); @@ -543,12 +364,12 @@ void uip_nd6_ra_output(uip_ipaddr_t *dest); /** * \brief Send a Router Solicitation - * + * * src is chosen through the uip_netif_select_src function. If src is * unspecified (i.e. we do not have a preferred address yet), then we do not * put a SLLAO option (MUST NOT in RFC 4861). Otherwise we do. * - * RS message format, + * RS message format, * possible option is SLLAO, MUST NOT be included if source = unspecified * SHOULD be included otherwise */ @@ -559,7 +380,7 @@ void uip_nd6_rs_output(void); * \brief process a Router Advertisement * * - Possible actions when receiving a RA: add router to router list, - * recalculate reachable time, update link hop limit, update retrans timer. + * recalculate reachable time, update link hop limit, update retrans timer. * - If MTU option: update MTU. * - If SLLAO option: update entry in neighbor cache * - If prefix option: start autoconf, add prefix to prefix list @@ -570,13 +391,13 @@ uip_nd6_ra_input(void); void -uip_appserver_addr_get(uip_ipaddr_t *ipaddr); +uip_appserver_addr_get(uip_ipaddr_t *ipaddr); /*--------------------------------------*/ /******* ANNEX - message formats ********/ /*--------------------------------------*/ -/* - * RS format. possible option is SLLAO +/* + * RS format. possible option is SLLAO * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -644,7 +465,7 @@ uip_appserver_addr_get(uip_ipaddr_t *ipaddr); * | Options ... * +-+-+-+-+-+-+-+-+-+-+-+- * - * + * * Redirect message format. Possible options are TLLAO and Redirected header * * 0 1 2 3 @@ -673,7 +494,7 @@ uip_appserver_addr_get(uip_ipaddr_t *ipaddr); * | Options ... * +-+-+-+-+-+-+-+-+-+-+-+- * - * + * * SLLAO/TLLAO option: * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -681,7 +502,7 @@ uip_appserver_addr_get(uip_ipaddr_t *ipaddr); * | Type | Length | Link-Layer Address ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * + * * Prefix information option * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -712,8 +533,8 @@ uip_appserver_addr_get(uip_ipaddr_t *ipaddr); * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MTU | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * + * + * * Redirected header option * * 0 1 2 3 @@ -728,7 +549,7 @@ uip_appserver_addr_get(uip_ipaddr_t *ipaddr); * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - */ + */ #endif /* __UIP_ND6_H__ */ /** @} */ diff --git a/core/net/uip.h b/core/net/uip.h index bb0fee4b1..c39e81090 100644 --- a/core/net/uip.h +++ b/core/net/uip.h @@ -1770,6 +1770,17 @@ typedef struct uip_ext_hdr_opt_padn { u8_t opt_len; } uip_ext_hdr_opt_padn; +#if UIP_CONF_IPV6_RPL +/* RPL option */ +typedef struct uip_ext_hdr_opt_rpl { + u8_t opt_type; + u8_t opt_len; + u8_t flags; + u8_t instance; + u16_t senderrank; +} uip_ext_hdr_opt_rpl; +#endif /* UIP_CONF_IPV6_RPL */ + /* TCP header */ struct uip_tcp_hdr { u16_t srcport; @@ -1840,6 +1851,10 @@ struct uip_udp_hdr { /** \brief Destination and Hop By Hop extension headers option types */ #define UIP_EXT_HDR_OPT_PAD1 0 #define UIP_EXT_HDR_OPT_PADN 1 +#if UIP_CONF_IPV6_RPL +#define UIP_EXT_HDR_OPT_RPL 0x63 +#endif /* UIP_CONF_IPV6_RPL */ + /** @} */ /** @{ */ @@ -1897,8 +1912,13 @@ struct uip_udp_hdr { */ #define uip_l2_l3_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len) #define uip_l2_l3_icmp_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len + UIP_ICMPH_LEN) +#define uip_l2_l3_udp_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len + UIP_UDPH_LEN) +#define uip_l2_l3_tcp_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len + UIP_TCPH_LEN) + #define uip_l3_hdr_len (UIP_IPH_LEN + uip_ext_len) #define uip_l3_icmp_hdr_len (UIP_IPH_LEN + uip_ext_len + UIP_ICMPH_LEN) +#define uip_l3_udp_hdr_len (UIP_IPH_LEN + uip_ext_len + UIP_UDPH_LEN) +#define uip_l3_tcp_hdr_len (UIP_IPH_LEN + uip_ext_len + UIP_TCPH_LEN) #endif /*UIP_CONF_IPV6*/ diff --git a/core/net/uip6.c b/core/net/uip6.c index 7a054dcc4..9c121c3bd 100644 --- a/core/net/uip6.c +++ b/core/net/uip6.c @@ -95,7 +95,7 @@ #endif #if UIP_CONF_IPV6_RPL -void uip_rpl_input(void); +#include "rpl/rpl.h" #endif /* UIP_CONF_IPV6_RPL */ #if UIP_LOGGING == 1 @@ -163,6 +163,9 @@ u8_t uip_ext_opt_offset = 0; #define UIP_DESTO_BUF ((struct uip_desto_hdr *)&uip_buf[uip_l2_l3_hdr_len]) #define UIP_EXT_HDR_OPT_BUF ((struct uip_ext_hdr_opt *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset]) #define UIP_EXT_HDR_OPT_PADN_BUF ((struct uip_ext_hdr_opt_padn *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset]) +#if UIP_CONF_IPV6_RPL +#define UIP_EXT_HDR_OPT_RPL_BUF ((struct uip_ext_hdr_opt_rpl *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset]) +#endif /* UIP_CONF_IPV6_RPL */ #define UIP_ICMP6_ERROR_BUF ((struct uip_icmp6_error *)&uip_buf[uip_l2_l3_icmp_hdr_len]) /** @} */ /** \name Buffer variables @@ -503,6 +506,24 @@ uip_connect(uip_ipaddr_t *ripaddr, u16_t rport) } #endif /* UIP_TCP && UIP_ACTIVE_OPEN */ /*---------------------------------------------------------------------------*/ +void +remove_ext_hdr(void) +{ + /* Remove ext header before TCP/UDP processing. */ + if(uip_ext_len > 0) { + PRINTF("Cutting ext-header before TCP send (%d)\n", uip_ext_len); + memmove(((uint8_t *)UIP_TCP_BUF) - uip_ext_len, (uint8_t *)UIP_TCP_BUF, + uip_len - UIP_IPH_LEN - uip_ext_len); + + uip_len -= uip_ext_len; + + /* Update the IP length. */ + UIP_IP_BUF->len[0] = (uip_len - UIP_IPH_LEN) >> 8; + UIP_IP_BUF->len[1] = (uip_len - UIP_IPH_LEN) & 0xff; + uip_ext_len = 0; + } +} +/*---------------------------------------------------------------------------*/ #if UIP_UDP struct uip_udp_conn * uip_udp_new(const uip_ipaddr_t *ripaddr, u16_t rport) @@ -828,6 +849,16 @@ ext_hdr_options_process(void) PRINTF("Processing PADN option\n"); uip_ext_opt_offset += UIP_EXT_HDR_OPT_PADN_BUF->opt_len + 2; break; +#if UIP_CONF_IPV6_RPL + case UIP_EXT_HDR_OPT_RPL: + PRINTF("Processing RPL option\n"); + if(rpl_verify_header(uip_ext_opt_offset)) { + PRINTF("RPL Option Error : Dropping Packet"); + return 1; + } + uip_ext_opt_offset += (UIP_EXT_HDR_OPT_RPL_BUF->opt_len) + 2; + return 0; +#endif /* UIP_CONF_IPV6_RPL */ default: /* * check the two highest order bits of the option @@ -1015,7 +1046,7 @@ uip_process(u8_t flag) if(flag == UIP_UDP_TIMER) { if(uip_udp_conn->lport != 0) { uip_conn = NULL; - uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_sappdata = uip_appdata = &uip_buf[uip_l2_l3_udp_hdr_len]; uip_len = uip_slen = 0; uip_flags = UIP_POLL; UIP_UDP_APPCALL(); @@ -1079,6 +1110,35 @@ uip_process(u8_t flag) } #if UIP_CONF_ROUTER + /* + * Next header field processing. In IPv6, we can have extension headers, + * if present, the Hop-by-Hop Option must be processed before forwarding + * the packet. + */ + uip_next_hdr = &UIP_IP_BUF->proto; + uip_ext_len = 0; + uip_ext_bitmap = 0; + if(*uip_next_hdr == UIP_PROTO_HBHO) { +#if UIP_CONF_IPV6_CHECKS + uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_HBHO; +#endif /*UIP_CONF_IPV6_CHECKS*/ + switch(ext_hdr_options_process()) { + case 0: + /*continue*/ + uip_next_hdr = &UIP_EXT_BUF->next; + uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; + break; + case 1: + /*silently discard*/ + goto drop; + case 2: + /* send icmp error message (created in ext_hdr_options_process) + * and discard*/ + goto send; + } + } + + /* TBD Some Parameter problem messages */ if(!uip_ds6_is_my_addr(&UIP_IP_BUF->destipaddr) && !uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) { @@ -1102,6 +1162,11 @@ uip_process(u8_t flag) UIP_STAT(++uip_stat.ip.drop); goto send; } + +#if UIP_CONF_IPV6_RPL + rpl_update_header_empty(); +#endif /* UIP_CONF_IPV6_RPL */ + UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1; PRINTF("Forwarding packet to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); @@ -1132,7 +1197,6 @@ uip_process(u8_t flag) UIP_STAT(++uip_stat.ip.drop); goto drop; } -#endif /* UIP_CONF_ROUTER */ /* * Next header field processing. In IPv6, we can have extension headers, @@ -1141,6 +1205,8 @@ uip_process(u8_t flag) uip_next_hdr = &UIP_IP_BUF->proto; uip_ext_len = 0; uip_ext_bitmap = 0; +#endif /* UIP_CONF_ROUTER */ + while(1) { switch(*uip_next_hdr){ #if UIP_TCP @@ -1374,8 +1440,8 @@ uip_process(u8_t flag) work. If the application sets uip_slen, it has a packet to send. */ #if UIP_UDP_CHECKSUMS - uip_len = uip_len - UIP_IPUDPH_LEN; - uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_len = uip_len - uip_l3_udp_hdr_len; + uip_appdata = &uip_buf[uip_l2_l3_udp_hdr_len]; if(UIP_UDP_BUF->udpchksum != 0 && uip_udpchksum() != 0xffff) { UIP_STAT(++uip_stat.udp.drop); UIP_STAT(++uip_stat.udp.chkerr); @@ -1384,7 +1450,7 @@ uip_process(u8_t flag) goto drop; } #else /* UIP_UDP_CHECKSUMS */ - uip_len = uip_len - UIP_IPUDPH_LEN; + uip_len = uip_len - uip_l3_udp_hdr_len; #endif /* UIP_UDP_CHECKSUMS */ /* Make sure that the UDP destination port number is not zero. */ @@ -1428,7 +1494,7 @@ uip_process(u8_t flag) uip_conn = NULL; uip_flags = UIP_NEWDATA; - uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_sappdata = uip_appdata = &uip_buf[uip_l2_l3_udp_hdr_len]; uip_slen = 0; UIP_UDP_APPCALL(); @@ -1438,7 +1504,8 @@ uip_process(u8_t flag) if(uip_slen == 0) { goto drop; } - uip_len = uip_slen + UIP_IPUDPH_LEN; + /* TODO: ext_header len here ? */ + uip_len = uip_slen + uip_l3_udp_hdr_len; /* UIP_IPUDPH_LEN; */ /* For IPv6, the IP length field does not include the IPv6 IP header length. */ @@ -1474,6 +1541,8 @@ uip_process(u8_t flag) /* TCP input processing. */ tcp_input: + remove_ext_hdr(); + UIP_STAT(++uip_stat.tcp.recv); PRINTF("Receiving TCP packet\n"); /* Start of TCP input header processing code. */ @@ -1482,13 +1551,14 @@ uip_process(u8_t flag) checksum. */ UIP_STAT(++uip_stat.tcp.drop); UIP_STAT(++uip_stat.tcp.chkerr); - UIP_LOG("tcp: bad checksum."); + PRINTF("tcp: bad checksum 0x%04x 0x%04x\n", UIP_TCP_BUF->tcpchksum, + uip_tcpchksum()); goto drop; } /* Make sure that the TCP port number is not zero. */ if(UIP_TCP_BUF->destport == 0 || UIP_TCP_BUF->srcport == 0) { - UIP_LOG("tcp: zero port."); + PRINTF("tcp: zero port."); goto drop; } @@ -1636,7 +1706,7 @@ uip_process(u8_t flag) /* Parse the TCP MSS option, if present. */ if((UIP_TCP_BUF->tcpoffset & 0xf0) > 0x50) { for(c = 0; c < ((UIP_TCP_BUF->tcpoffset >> 4) - 5) << 2 ;) { - opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; + opt = uip_buf[UIP_TCPIP_HLEN + uip_ext_len + UIP_LLH_LEN + c]; if(opt == TCP_OPT_END) { /* End of options. */ break; @@ -1644,10 +1714,10 @@ uip_process(u8_t flag) ++c; /* NOP option. */ } else if(opt == TCP_OPT_MSS && - uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + uip_buf[UIP_TCPIP_HLEN + uip_ext_len + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { /* An MSS option with the right option length. */ - tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | - (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; + tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + uip_ext_len + UIP_LLH_LEN + 2 + c] << 8) | + (u16_t)uip_buf[UIP_IPTCPH_LEN + uip_ext_len + UIP_LLH_LEN + 3 + c]; uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; @@ -1656,12 +1726,12 @@ uip_process(u8_t flag) } else { /* All other options have a length field, so that we easily can skip past them. */ - if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + if(uip_buf[UIP_TCPIP_HLEN + uip_ext_len + UIP_LLH_LEN + 1 + c] == 0) { /* If the length field is zero, the options are malformed and we don't process them further. */ break; } - c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + c += uip_buf[UIP_TCPIP_HLEN + uip_ext_len + UIP_LLH_LEN + 1 + c]; } } } @@ -1684,7 +1754,7 @@ uip_process(u8_t flag) UIP_TCP_BUF->optdata[1] = TCP_OPT_MSS_LEN; UIP_TCP_BUF->optdata[2] = (UIP_TCP_MSS) / 256; UIP_TCP_BUF->optdata[3] = (UIP_TCP_MSS) & 255; - uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN; + uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN + uip_ext_len; UIP_TCP_BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; goto tcp_send; @@ -1710,7 +1780,7 @@ uip_process(u8_t flag) /* uip_len will contain the length of the actual TCP data. This is calculated by subtracing the length of the TCP header (in c) and the length of the IP header (20 bytes). */ - uip_len = uip_len - c - UIP_IPH_LEN; + uip_len = uip_len - c - UIP_IPH_LEN - uip_ext_len; /* First, check if the sequence number of the incoming packet is what we're expecting next. If not, we send out an ACK with the @@ -1817,7 +1887,7 @@ uip_process(u8_t flag) /* Parse the TCP MSS option, if present. */ if((UIP_TCP_BUF->tcpoffset & 0xf0) > 0x50) { for(c = 0; c < ((UIP_TCP_BUF->tcpoffset >> 4) - 5) << 2 ;) { - opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; + opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c + uip_ext_len]; if(opt == TCP_OPT_END) { /* End of options. */ break; @@ -1825,10 +1895,10 @@ uip_process(u8_t flag) ++c; /* NOP option. */ } else if(opt == TCP_OPT_MSS && - uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c + uip_ext_len] == TCP_OPT_MSS_LEN) { /* An MSS option with the right option length. */ - tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | - uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; + tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c + uip_ext_len] << 8) | + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c + uip_ext_len]; uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; @@ -1837,12 +1907,12 @@ uip_process(u8_t flag) } else { /* All other options have a length field, so that we easily can skip past them. */ - if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c + uip_ext_len] == 0) { /* If the length field is zero, the options are malformed and we don't process them further. */ break; } - c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c + uip_ext_len]; } } } @@ -2113,7 +2183,7 @@ uip_process(u8_t flag) UIP_TCP_BUF->flags = TCP_ACK; tcp_send_nodata: - uip_len = UIP_IPTCPH_LEN; + uip_len = UIP_IPTCPH_LEN; /* TODO: maybe ext_len??? */ tcp_send_noopts: UIP_TCP_BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4; diff --git a/core/net/uipopt.h b/core/net/uipopt.h index b409bbd82..d36c1df59 100644 --- a/core/net/uipopt.h +++ b/core/net/uipopt.h @@ -194,12 +194,12 @@ #define UIP_CONF_IPV6_QUEUE_PKT 0 #endif -#ifndef UIP_CONF_IPV6_CHECKS +#ifndef UIP_CONF_IPV6_CHECKS /** Do we do IPv6 consistency checks (highly recommended, default: yes) */ #define UIP_CONF_IPV6_CHECKS 1 #endif -#ifndef UIP_CONF_IPV6_REASSEMBLY +#ifndef UIP_CONF_IPV6_REASSEMBLY /** Do we do IPv6 fragmentation (default: no) */ #define UIP_CONF_IPV6_REASSEMBLY 0 #endif @@ -209,19 +209,19 @@ #define UIP_CONF_NETIF_MAX_ADDRESSES 3 #endif -#ifndef UIP_CONF_ND6_MAX_PREFIXES +#ifndef UIP_CONF_DS6_PREFIX_NBU /** Default number of IPv6 prefixes associated to the node's interface */ -#define UIP_CONF_ND6_MAX_PREFIXES 3 +#define UIP_CONF_DS6_PREFIX_NBU 2 #endif -#ifndef UIP_CONF_ND6_MAX_NEIGHBORS +#ifndef UIP_CONF_DS6_NBR_NBU /** Default number of neighbors that can be stored in the %neighbor cache */ -#define UIP_CONF_ND6_MAX_NEIGHBORS 4 +#define UIP_CONF_DS6_NBR_NBU 4 #endif -#ifndef UIP_CONF_ND6_MAX_DEFROUTERS +#ifndef UIP_CONF_DS6_DEFRT_NBU /** Minimum number of default routers */ -#define UIP_CONF_ND6_MAX_DEFROUTERS 2 +#define UIP_CONF_DS6_DEFRT_NBU 2 #endif /** @} */ diff --git a/examples/ipv6/rpl-border-router/border-router.c b/examples/ipv6/rpl-border-router/border-router.c index b3278aab7..db1b1058d 100644 --- a/examples/ipv6/rpl-border-router/border-router.c +++ b/examples/ipv6/rpl-border-router/border-router.c @@ -240,7 +240,7 @@ PROCESS_THREAD(border_router_process, ev, data) PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); } - dag = rpl_set_root((uip_ip6addr_t *)dag_id); + dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)dag_id); if(dag != NULL) { rpl_set_prefix(dag, &prefix, 64); PRINTF("created a new RPL dag\n"); @@ -258,7 +258,7 @@ PROCESS_THREAD(border_router_process, ev, data) PROCESS_YIELD(); if (ev == sensors_event && data == &button_sensor) { PRINTF("Initiating global repair\n"); - rpl_repair_dag(rpl_get_dag(RPL_ANY_INSTANCE)); + rpl_repair_root(RPL_DEFAULT_INSTANCE); } } diff --git a/examples/ipv6/rpl-collect/udp-sender.c b/examples/ipv6/rpl-collect/udp-sender.c index a04fb2524..2c0faa059 100644 --- a/examples/ipv6/rpl-collect/udp-sender.c +++ b/examples/ipv6/rpl-collect/udp-sender.c @@ -71,7 +71,8 @@ collect_common_net_print(void) { rpl_dag_t *dag; int i; - dag = rpl_get_dag(RPL_ANY_INSTANCE); + /* Let's suppose we have only one instance */ + dag = rpl_get_any_dag(); if(dag->preferred_parent != NULL) { PRINTF("Preferred parent: "); PRINT6ADDR(&dag->preferred_parent->addr); @@ -128,7 +129,8 @@ collect_common_send(void) rimeaddr_copy(&parent, &rimeaddr_null); parent_etx = 0; - dag = rpl_get_dag(RPL_DEFAULT_INSTANCE); + /* Let's suppose we have only one instance */ + dag = rpl_get_any_dag(); if(dag != NULL) { preferred_parent = dag->preferred_parent; if(preferred_parent != NULL) { diff --git a/examples/ipv6/rpl-collect/udp-sink.c b/examples/ipv6/rpl-collect/udp-sink.c index 11a4f7346..b2251b4ff 100644 --- a/examples/ipv6/rpl-collect/udp-sink.c +++ b/examples/ipv6/rpl-collect/udp-sink.c @@ -151,8 +151,7 @@ PROCESS_THREAD(udp_server_process, ev, data) root_if = uip_ds6_addr_lookup(&ipaddr); if(root_if != NULL) { rpl_dag_t *dag; - rpl_set_root((uip_ip6addr_t *)&ipaddr); - dag = rpl_get_dag(RPL_ANY_INSTANCE); + dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr); uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); rpl_set_prefix(dag, &ipaddr, 64); PRINTF("created a new RPL dag\n"); @@ -181,7 +180,7 @@ PROCESS_THREAD(udp_server_process, ev, data) tcpip_handler(); } else if (ev == sensors_event && data == &button_sensor) { PRINTF("Initiaing global repair\n"); - rpl_repair_dag(rpl_get_dag(RPL_ANY_INSTANCE)); + rpl_repair_root(RPL_DEFAULT_INSTANCE); } } diff --git a/examples/ipv6/rpl-udp/Makefile b/examples/ipv6/rpl-udp/Makefile index 6c7e2cb7a..e4ea78e28 100644 --- a/examples/ipv6/rpl-udp/Makefile +++ b/examples/ipv6/rpl-udp/Makefile @@ -4,6 +4,7 @@ CONTIKI=../../.. WITH_UIP6=1 UIP_CONF_IPV6=1 + CFLAGS+= -DUIP_CONF_IPV6_RPL ifdef WITH_COMPOWER diff --git a/examples/ipv6/rpl-udp/udp-server.c b/examples/ipv6/rpl-udp/udp-server.c index 33f8cd761..0e6c88b3b 100644 --- a/examples/ipv6/rpl-udp/udp-server.c +++ b/examples/ipv6/rpl-udp/udp-server.c @@ -135,8 +135,7 @@ PROCESS_THREAD(udp_server_process, ev, data) root_if = uip_ds6_addr_lookup(&ipaddr); if(root_if != NULL) { rpl_dag_t *dag; - rpl_set_root((uip_ip6addr_t *)&ipaddr); - dag = rpl_get_dag(RPL_ANY_INSTANCE); + dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr); uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); rpl_set_prefix(dag, &ipaddr, 64); PRINTF("created a new RPL dag\n"); @@ -169,7 +168,7 @@ PROCESS_THREAD(udp_server_process, ev, data) tcpip_handler(); } else if (ev == sensors_event && data == &button_sensor) { PRINTF("Initiaing global repair\n"); - rpl_repair_dag(rpl_get_dag(RPL_ANY_INSTANCE)); + rpl_repair_root(RPL_DEFAULT_INSTANCE); } } diff --git a/platform/avr-ravenusb/cdc_task.c b/platform/avr-ravenusb/cdc_task.c index a53b8e400..c39e6bf27 100644 --- a/platform/avr-ravenusb/cdc_task.c +++ b/platform/avr-ravenusb/cdc_task.c @@ -620,11 +620,11 @@ extern uip_ds6_netif_t uip_ds6_if; } case 'G': - PRINTF_P(PSTR("Global repair returns %d\n\r"),rpl_repair_dag(rpl_get_dag(RPL_ANY_INSTANCE))); + PRINTF_P(PSTR("Global repair returns %d\n\r"),rpl_repair_root(RPL_DEFAULT_INSTANCE)); break; case 'L': - rpl_local_repair(rpl_get_dag(RPL_ANY_INSTANCE)); + rpl_local_repair(rpl_get_any_dag()); PRINTF_P(PSTR("Local repair initiated\n\r")); break; diff --git a/platform/avr-ravenusb/contiki-raven-main.c b/platform/avr-ravenusb/contiki-raven-main.c index 59595170e..b2abe2e21 100644 --- a/platform/avr-ravenusb/contiki-raven-main.c +++ b/platform/avr-ravenusb/contiki-raven-main.c @@ -164,7 +164,7 @@ PROCESS_THREAD(border_router_process, ev, data) { rpl_dag_t *dag; char buf[sizeof(dag_id)]; memcpy_P(buf,dag_id,sizeof(dag_id)); - dag = rpl_set_root((uip_ip6addr_t *)buf); + dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)buf); /* Assign separate addresses to the jackdaw uip stack and the host network interface, but with the same prefix */ /* E.g. bbbb::200 to the jackdaw and bbbb::1 to the host network interface with $ip -6 address add bbbb::1/64 dev usb0 */ @@ -192,8 +192,6 @@ PROCESS_THREAD(border_router_process, ev, data) while(1) { PROCESS_YIELD(); /* Local and global dag repair can be done from the jackdaw menu */ - // rpl_set_prefix(rpl_get_dag(RPL_ANY_INSTANCE), &ipaddr, 64); - // rpl_repair_dag(rpl_get_dag(RPL_ANY_INSTANCE)); } diff --git a/platform/mb851/contiki-init-net.c b/platform/mb851/contiki-init-net.c index f40513c88..4d81f9c58 100644 --- a/platform/mb851/contiki-init-net.c +++ b/platform/mb851/contiki-init-net.c @@ -120,7 +120,7 @@ void set_net_address(void) print_addresses(); #if RPL_BORDER_ROUTER - dag = rpl_set_root(&ipaddr); + dag = rpl_set_root(RPL_DEFAULT_INSTANCE,&ipaddr); if(dag != NULL) { PRINTF("This node is setted as root of a DAG.\r\n"); } @@ -133,4 +133,4 @@ void set_net_address(void) #endif /* FIXED_GLOBAL_ADDRESS */ -#endif /* UIP_CONF_IPV6 */ \ No newline at end of file +#endif /* UIP_CONF_IPV6 */