diff --git a/core/net/ip/tcpip.c b/core/net/ip/tcpip.c index df3f0608d89..9584401588f 100644 --- a/core/net/ip/tcpip.c +++ b/core/net/ip/tcpip.c @@ -576,7 +576,22 @@ tcpip_ipv6_output(void) /* No route was found - we send to the default route instead. */ if(route == NULL) { PRINTF("tcpip_ipv6_output: no route found, using default route\n"); - nexthop = uip_ds6_defrt_choose(); +#if UIP_CONF_IPV6_RPL && RPL_MAX_INSTANCES > 1 + rpl_instance_t *instance; + instance = rpl_hbh_get_instance(); + if(instance->current_dag->preferred_parent == NULL){ + instance=rpl_get_default_instance(&UIP_IP_BUF->destipaddr); + rpl_hbh_set_instance(instance); + } + printf("tcpip : instance used is %d\n", instance->instance_id); + nexthop = rpl_get_parent_ipaddr(instance->current_dag->preferred_parent); + if(nexthop == NULL){ + /* No default route found, so using ds6 function */ + nexthop = uip_ds6_defrt_choose(); + } +#else + nexthop = uip_ds6_defrt_choose(); +#endif /* UIP_CONF_IPV6_RPL && RPL_MAX_INSTANCES > 1 */ if(nexthop == NULL) { #ifdef UIP_FALLBACK_INTERFACE PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", diff --git a/core/net/ip/uip.h b/core/net/ip/uip.h index 12d77ff1088..d903e4cdec8 100644 --- a/core/net/ip/uip.h +++ b/core/net/ip/uip.h @@ -1407,6 +1407,9 @@ struct uip_udp_conn { uint16_t lport; /**< The local port number in network byte order. */ uint16_t rport; /**< The remote port number in network byte order. */ uint8_t ttl; /**< Default time-to-live. */ +#if UIP_CONF_IPV6_RPL + uint8_t rpl_instance_id; +#endif /* UIP_CONF_IPV6_RPL*/ /** The application state. */ uip_udp_appstate_t appstate; diff --git a/core/net/ipv6/uip-ds6-nbr.h b/core/net/ipv6/uip-ds6-nbr.h index 40a17d1e2eb..05e5bd03ab7 100644 --- a/core/net/ipv6/uip-ds6-nbr.h +++ b/core/net/ipv6/uip-ds6-nbr.h @@ -76,6 +76,9 @@ typedef struct uip_ds6_nbr { struct stimer sendns; uint8_t nscount; #endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA */ +#if UIP_CONF_IPV6_RPL && RPL_LB == RPL_LB_MIN_NOACK + uint8_t noack_count; +#endif /* UIP_CONF_IPV6_RPL */ #if UIP_CONF_IPV6_QUEUE_PKT struct uip_packetqueue_handle packethandle; #define UIP_DS6_NBR_PACKET_LIFETIME CLOCK_SECOND * 4 diff --git a/core/net/ipv6/uip-icmp6.c b/core/net/ipv6/uip-icmp6.c index d246a4d5878..b6c7853d24b 100644 --- a/core/net/ipv6/uip-icmp6.c +++ b/core/net/ipv6/uip-icmp6.c @@ -162,7 +162,7 @@ echo_request_input(void) /* Insert RPL extension headers */ #if UIP_CONF_IPV6_RPL - rpl_insert_header(); + rpl_insert_header(0); #endif /* UIP_CONF_IPV6_RPL */ /* Below is important for the correctness of UIP_ICMP_BUF and the @@ -261,7 +261,7 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) { UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); #if UIP_CONF_IPV6_RPL - rpl_insert_header(); + rpl_insert_header(0); #endif /* UIP_CONF_IPV6_RPL */ UIP_STAT(++uip_stat.icmp.sent); @@ -302,7 +302,7 @@ uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len) UIP_STAT(++uip_stat.ip.sent); #if UIP_CONF_IPV6_RPL - rpl_insert_header(); + rpl_insert_header(0); #endif /* UIP_CONF_IPV6_RPL */ tcpip_ipv6_output(); } diff --git a/core/net/ipv6/uip6.c b/core/net/ipv6/uip6.c index a5475437121..0d1b1595f7d 100644 --- a/core/net/ipv6/uip6.c +++ b/core/net/ipv6/uip6.c @@ -1229,7 +1229,7 @@ uip_process(uint8_t flag) } #if UIP_CONF_IPV6_RPL - if(!rpl_update_header()) { + if(rpl_update_header()) { /* Packet can not be forwarded */ PRINTF("RPL header update error\n"); goto drop; @@ -1583,7 +1583,7 @@ uip_process(uint8_t flag) #endif /* UIP_UDP_CHECKSUMS */ #if UIP_CONF_IPV6_RPL - rpl_insert_header(); + rpl_insert_header(uip_udp_conn->rpl_instance_id); #endif /* UIP_CONF_IPV6_RPL */ UIP_STAT(++uip_stat.udp.sent); diff --git a/core/net/rpl/rpl-conf.h b/core/net/rpl/rpl-conf.h index 97ab8f49dce..9ed94357e80 100644 --- a/core/net/rpl/rpl-conf.h +++ b/core/net/rpl/rpl-conf.h @@ -45,6 +45,16 @@ #define RPL_CONF_STATS 0 #endif /* RPL_CONF_STATS */ +/* + * Specify which metric types are supported/enabled in the Metric container. + * If a DIO contains a unsupported metric type, control packet is dropped. + */ +#ifdef RPL_CONF_DAG_MC_SUPPORTED_METRICS +#define RPL_DAG_MC_SUPPORTED_METRICS RPL_CONF_DAG_MC_SUPPORTED_METRICS +#else +#define RPL_DAG_MC_SUPPORTED_METRICS (RPL_DAG_MC_BITMAP(RPL_DAG_MC_ETX) | RPL_DAG_MC_BITMAP(RPL_DAG_MC_HOPCOUNT) | RPL_DAG_MC_BITMAP(RPL_DAG_MC_ENERGY)) +#endif /* RPL_CONF_DAG_MC_SUPPORTED_METRICS */ + /* * The objective function (OF) used by a RPL root is configurable through * the RPL_CONF_OF_OCP parameter. This is defined as the objective code @@ -67,9 +77,16 @@ #ifdef RPL_CONF_SUPPORTED_OFS #define RPL_SUPPORTED_OFS RPL_CONF_SUPPORTED_OFS #else /* RPL_CONF_SUPPORTED_OFS */ -#define RPL_SUPPORTED_OFS {&rpl_mrhof} +#define RPL_SUPPORTED_OFS {&rpl_mrhof, &rpl_of0} #endif /* RPL_CONF_SUPPORTED_OFS */ + /* + * Functions used to simplify manipulation of MC metric types. + */ +#define RPL_DAG_MC_BITMAP(type) 1 << (type-1) +#define RPL_IS_METRIC_SUPPORTED(type) RPL_DAG_MC_SUPPORTED_METRICS & RPL_DAG_MC_BITMAP(type) +#define RPL_IS_OF_ENABLED(of_name) RPL_OF_ENABLED & of_name + /* * Enable/disable RPL Metric Containers (MC). The actual MC in use * for a given DODAG is decided at runtime, when joining. Note that @@ -81,16 +98,56 @@ #ifdef RPL_CONF_WITH_MC #define RPL_WITH_MC RPL_CONF_WITH_MC #else /* RPL_CONF_WITH_MC */ -#define RPL_WITH_MC 0 +#define RPL_WITH_MC (RPL_DAG_MC_SUPPORTED_METRICS != RPL_DAG_MC_NONE) #endif /* RPL_CONF_WITH_MC */ -/* The MC advertised in DIOs and propagating from the root */ + /* The MC advertised in DIOs and propagating from the root */ #ifdef RPL_CONF_DAG_MC #define RPL_DAG_MC RPL_CONF_DAG_MC #else #define RPL_DAG_MC RPL_DAG_MC_NONE #endif /* RPL_CONF_DAG_MC */ +/* + * Maximum of Metric/Constraint object in a DAG Metric Container + */ +#ifdef RPL_CONF_MAX_DAG_MC_OBJECTS +#define RPL_MAX_DAG_MC_OBJECTS RPL_CONF_MAX_DAG_MC_OBJECTS +#else +#define RPL_MAX_DAG_MC_OBJECTS 1 +#endif /* RPL_CONF_MAX_DAG_MC_OBJECTS */ + +/* + * Maximum of Type-Length-Value field in a DAG Metric Container Object. + */ + +#ifdef RPL_CONF_MAX_DAG_MC_TLV +#define RPL_MAX_DAG_MC_TLV RPL_CONF_MAX_DAG_MC_TLV +#else +#define RPL_MAX_DAG_MC_TLV 0 +#endif /* RPL_CONF_MAX_DAG_MC_TLV */ + +/* + * Energy type to be used in DAG MC energy object. Also used when checking + * advertized constraints. + * If not defined, energy type will be based on DODAG Rank : + * - RPL_DAG_MC_ENERGY_TYPE_MAINS for a DODAG root, + * - RPL_DAG_MC_ENERGY_TYPE_BATTERY for other nodes + */ +#ifdef RPL_CONF_DAG_MC_ENERGY_TYPE +#define RPL_DAG_MC_ENERGY_TYPE RPL_CONF_DAG_MC_ENERGY_TYPE +#endif /* RPL_CONF_DAG_MC_ENERGY_TYPE */ + +/* + * The default objective function used by RPL is configurable through the + * RPL_CONF_DEFAULT_OF parameter. This should be defined to be the name of an + * rpl_of object linked into the system image, e.g., rpl_of0. + */ +#ifdef RPL_CONF_DEFAULT_OF + #define RPL_DEFAULT_OF RPL_CONF_DEFAULT_OF + +#endif /* RPL_CONF_DEFAULT_OF */ + /* This value decides which DAG instance we should participate in by default. */ #ifdef RPL_CONF_DEFAULT_INSTANCE #define RPL_DEFAULT_INSTANCE RPL_CONF_DEFAULT_INSTANCE @@ -98,6 +155,28 @@ #define RPL_DEFAULT_INSTANCE 0x1e #endif /* RPL_CONF_DEFAULT_INSTANCE */ +/* Enable DIO filter based on constraints found and authorized instance IDs */ +#ifdef RPL_CONF_FILTER_DIO +#define RPL_FILTER_DIO RPL_CONF_FILTER_DIO +#else +#define RPL_FILTER_DIO 1 +#endif /* RPL_CONF_FILTER_DIO */ + + +/* Load balancing mechanism, RPL_LB_NONE to set no mechanism*/ +#ifdef RPL_CONF_LB +#define RPL_LB RPL_CONF_LB +#else +#define RPL_LB RPL_LB_NONE +#endif /* RPL_CONF_LB */ + +/* Authorized instances array. "{0}" results in authorizing all instances */ +#ifdef RPL_CONF_AUTHORIZED_INSTANCES +#define RPL_AUTHORIZED_INSTANCES RPL_CONF_AUTHORIZED_INSTANCES +#else +#define RPL_AUTHORIZED_INSTANCES {0} +#endif /* RPL_CONF_AUTHORIZED_INSTANCES */ + /* * This value decides if this node must stay as a leaf or not * as allowed by draft-ietf-roll-rpl-19#section-8.5 diff --git a/core/net/rpl/rpl-dag-root.c b/core/net/rpl/rpl-dag-root.c index 57a10ef80bd..6d65ef00796 100644 --- a/core/net/rpl/rpl-dag-root.c +++ b/core/net/rpl/rpl-dag-root.c @@ -252,7 +252,7 @@ rpl_dag_root_is_root(void) { rpl_instance_t *instance; - instance = rpl_get_default_instance(); + instance = last_joined_instance; if(instance == NULL) { return 0; diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index 2077c4eb4ff..c7592ea0f92 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -70,6 +70,10 @@ void RPL_CALLBACK_PARENT_SWITCH(rpl_parent_t *old, rpl_parent_t *new); extern rpl_of_t rpl_of0, rpl_mrhof; static rpl_of_t * const objective_functions[] = RPL_SUPPORTED_OFS; +#if RPL_LB == RPL_LB_ROUND_ROBIN +rpl_instance_t *last_instance_used = NULL; +#endif + /*---------------------------------------------------------------------------*/ /* RPL definitions. */ @@ -78,50 +82,56 @@ static rpl_of_t * const objective_functions[] = RPL_SUPPORTED_OFS; #else #define RPL_GROUNDED RPL_CONF_GROUNDED #endif /* !RPL_CONF_GROUNDED */ - -/*---------------------------------------------------------------------------*/ -/* Per-parent RPL information */ -NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents); /*---------------------------------------------------------------------------*/ /* Allocate instance table. */ rpl_instance_t instance_table[RPL_MAX_INSTANCES]; -rpl_instance_t *default_instance; +rpl_instance_t *last_joined_instance; + +static uint8_t const authorized_instances[] = RPL_AUTHORIZED_INSTANCES; /*---------------------------------------------------------------------------*/ void rpl_print_neighbor_list(void) { - if(default_instance != NULL && default_instance->current_dag != NULL && - default_instance->of != NULL) { - int curr_dio_interval = default_instance->dio_intcurrent; - int curr_rank = default_instance->current_dag->rank; - rpl_parent_t *p = nbr_table_head(rpl_parents); - clock_time_t clock_now = clock_time(); - - printf("RPL: MOP %u OCP %u rank %u dioint %u, nbr count %u\n", - default_instance->mop, default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num()); - while(p != NULL) { - const struct link_stats *stats = rpl_get_parent_link_stats(p); - printf("RPL: nbr %3u %5u, %5u => %5u -- %2u %c%c (last tx %u min ago)\n", - rpl_get_parent_ipaddr(p)->u8[15], - p->rank, - rpl_get_parent_link_metric(p), - rpl_rank_via_parent(p), - stats != NULL ? stats->freshness : 0, - link_stats_is_fresh(stats) ? 'f' : ' ', - p == default_instance->current_dag->preferred_parent ? 'p' : ' ', - (unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND)) - ); - p = nbr_table_next(rpl_parents, p); - } - printf("RPL: end of list\n"); + rpl_instance_t *instance, *end; + int curr_dio_interval; + int curr_rank; + + clock_time_t clock_now = clock_time(); + + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; + instance < end; ++instance) { + if(instance->used == 1 && instance->current_dag != NULL && instance->of) { + curr_dio_interval = instance->dio_intcurrent; + curr_rank = instance->current_dag->rank; + rpl_parent_t *p = nbr_table_head(&instance->nbr_table); + + printf("RPL: Instance %u, rank %u dioint %u, neighbors :\n", instance->instance_id, + curr_rank, curr_dio_interval); + while(p != NULL) { + const struct link_stats *stats = rpl_get_parent_link_stats(p); + printf("RPL: nbr %3u %5u, %5u => %5u -- %2u %c%c (last tx %u min ago)\n", + rpl_get_parent_lladdr(p)->u8[7], + p->rank, + rpl_get_parent_link_metric(p), + rpl_rank_via_parent(p), + stats != NULL ? stats->freshness : 0, + link_stats_is_fresh(stats) ? 'f' : ' ', + p == instance->current_dag->preferred_parent ? 'p' : ' ', + (unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND)) + ); + p = nbr_table_next(&instance->nbr_table, p); + } + } } + printf("RPL: end of list\n"); } /*---------------------------------------------------------------------------*/ uip_ds6_nbr_t * rpl_get_nbr(rpl_parent_t *parent) { - const linkaddr_t *lladdr = rpl_get_parent_lladdr(parent); + const linkaddr_t *lladdr = NULL; + lladdr = rpl_get_parent_lladdr(parent); if(lladdr != NULL) { return nbr_table_get_from_lladdr(ds6_neighbors, lladdr); } else { @@ -138,27 +148,18 @@ nbr_callback(void *ptr) void rpl_dag_init(void) { - nbr_table_register(rpl_parents, (nbr_table_callback *)nbr_callback); } /*---------------------------------------------------------------------------*/ rpl_parent_t * rpl_get_parent(uip_lladdr_t *addr) { - rpl_parent_t *p = nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)addr); + uip_ds6_nbr_t *nbr; + nbr = nbr_table_get_from_lladdr(ds6_neighbors, (const linkaddr_t *)addr); + rpl_parent_t *p = rpl_find_parent_any_dag_any_instance(&nbr->ipaddr); + return p; } /*---------------------------------------------------------------------------*/ -rpl_rank_t -rpl_get_parent_rank(uip_lladdr_t *addr) -{ - rpl_parent_t *p = nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)addr); - if(p != NULL) { - return p->rank; - } else { - return INFINITE_RANK; - } -} -/*---------------------------------------------------------------------------*/ uint16_t rpl_get_parent_link_metric(rpl_parent_t *p) { @@ -186,7 +187,7 @@ rpl_rank_via_parent(rpl_parent_t *p) const linkaddr_t * rpl_get_parent_lladdr(rpl_parent_t *p) { - return nbr_table_get_lladdr(rpl_parents, p); + return nbr_table_get_lladdr(&p->dag->instance->nbr_table, p); } /*---------------------------------------------------------------------------*/ uip_ipaddr_t * @@ -251,8 +252,8 @@ rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p) /* Always keep the preferred parent locked, so it remains in the * neighbor table. */ - nbr_table_unlock(rpl_parents, dag->preferred_parent); - nbr_table_lock(rpl_parents, p); + nbr_table_unlock(&dag->instance->nbr_table, dag->preferred_parent); + nbr_table_lock(&dag->instance->nbr_table, p); dag->preferred_parent = p; } } @@ -282,12 +283,12 @@ remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank) PRINTF("RPL: Removing parents (minimum rank %u)\n", minimum_rank); - p = nbr_table_head(rpl_parents); + p = nbr_table_head(&dag->instance->nbr_table); while(p != NULL) { if(dag == p->dag && p->rank >= minimum_rank) { rpl_remove_parent(p); } - p = nbr_table_next(rpl_parents, p); + p = nbr_table_next(&dag->instance->nbr_table, p); } } /*---------------------------------------------------------------------------*/ @@ -299,12 +300,12 @@ nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank) PRINTF("RPL: Nullifying parents (minimum rank %u)\n", minimum_rank); - p = nbr_table_head(rpl_parents); + p = nbr_table_head(&dag->instance->nbr_table); while(p != NULL) { if(dag == p->dag && p->rank >= minimum_rank) { rpl_nullify_parent(p); } - p = nbr_table_next(rpl_parents, p); + p = nbr_table_next(&dag->instance->nbr_table, p); } } /*---------------------------------------------------------------------------*/ @@ -392,12 +393,6 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) dag->grounded = RPL_GROUNDED; dag->preference = RPL_PREFERENCE; instance->mop = RPL_MOP_DEFAULT; - instance->of = rpl_find_of(RPL_OF_OCP); - if(instance->of == NULL) { - PRINTF("RPL: OF with OCP %u not supported\n", RPL_OF_OCP); - return NULL; - } - rpl_set_preferred_parent(dag, NULL); memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); @@ -427,8 +422,16 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) instance->current_dag = dag; instance->dtsn_out = RPL_LOLLIPOP_INIT; - instance->of->update_metric_container(instance); - default_instance = instance; + last_joined_instance = instance; + + /* Set default Objective function if it has not been set before setting + root */ + if(instance->of == NULL){ + rpl_set_of(instance_id, RPL_OF_OCP); + } + else{ + instance->of->update_metric_container(instance); + } PRINTF("RPL: Node set to be a DAG root with DAG ID "); PRINT6ADDR(&dag->dag_id); @@ -566,6 +569,56 @@ rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from) } /*---------------------------------------------------------------------------*/ rpl_instance_t * +rpl_get_default_instance(uip_ipaddr_t *dest) +{ + rpl_instance_t *instance, *end; +#if RPL_LB == RPL_LB_ROUND_ROBIN + rpl_instance_t *first_candidate = NULL; + uint8_t choose_next = 0; +#elif RPL_LB == RPL_LB_MIN_NOACK + rpl_instance_t *preferred_instance = NULL; +#endif /* RPL_LB == RPL_LB_ROUND_ROBIN */ + if(dest != NULL) { + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; + instance < end; ++instance) { + if(instance->used == 1 && instance->current_dag != NULL && instance->current_dag->preferred_parent != NULL + && &instance->current_dag->prefix_info != NULL + && uip_ipaddr_prefixcmp(dest, &instance->current_dag->prefix_info.prefix, instance->current_dag->prefix_info.length)) { +#if RPL_LB == RPL_LB_ROUND_ROBIN + if(choose_next || last_instance_used == NULL){ + last_instance_used = instance; + return instance; + } + else if(instance == last_instance_used){ + choose_next = 1; + } + + if(first_candidate == NULL){ + first_candidate = instance; + } +#elif RPL_LB == RPL_LB_MIN_NOACK + if(preferred_instance == NULL || rpl_get_nbr(instance->current_dag->preferred_parent)->noack_count < rpl_get_nbr(preferred_instance->current_dag->preferred_parent)->noack_count){ + preferred_instance = instance; + } +#else + return instance; +#endif /* RPL_LB == RPL_LB_ROUND_ROBIN */ + } + } + } +#if RPL_LB == RPL_LB_ROUND_ROBIN + if(first_candidate != NULL){ + last_instance_used = first_candidate; + } + return first_candidate; +#elif RPL_LB == RPL_LB_MIN_NOACK + return preferred_instance; +#else + return NULL; +#endif /* RPL_LB == RPL_LB_ROUND_ROBIN */ +} +/*---------------------------------------------------------------------------*/ +rpl_instance_t * rpl_alloc_instance(uint8_t instance_id) { rpl_instance_t *instance, *end; @@ -577,6 +630,16 @@ rpl_alloc_instance(uint8_t instance_id) instance->instance_id = instance_id; instance->def_route = NULL; instance->used = 1; + + instance->nbr_table.index = 0; + instance->nbr_table.item_size = sizeof(rpl_parent_t); + instance->nbr_table.callback = NULL; + instance->nbr_table.data = (nbr_table_item_t *)instance->parents_mem; + + if(instance->nbr_table.index == 0 && + !nbr_table_register(&instance->nbr_table, (nbr_table_callback *)nbr_callback)){ + return NULL; + } #if RPL_WITH_PROBING rpl_schedule_probing(instance); #endif /* RPL_WITH_PROBING */ @@ -617,18 +680,6 @@ rpl_alloc_dag(uint8_t instance_id, uip_ipaddr_t *dag_id) } /*---------------------------------------------------------------------------*/ void -rpl_set_default_instance(rpl_instance_t *instance) -{ - default_instance = instance; -} -/*---------------------------------------------------------------------------*/ -rpl_instance_t * -rpl_get_default_instance(void) -{ - return default_instance; -} -/*---------------------------------------------------------------------------*/ -void rpl_free_instance(rpl_instance_t *instance) { rpl_dag_t *dag; @@ -652,8 +703,8 @@ rpl_free_instance(rpl_instance_t *instance) ctimer_stop(&instance->dao_timer); ctimer_stop(&instance->dao_lifetime_timer); - if(default_instance == instance) { - default_instance = NULL; + if(last_joined_instance == instance) { + last_joined_instance = rpl_get_any_dag()->instance; } instance->used = 0; @@ -695,8 +746,8 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) PRINT6ADDR(addr); PRINTF("\n"); if(lladdr != NULL) { - /* Add parent in rpl_parents - again this is due to DIO */ - p = nbr_table_add_lladdr(rpl_parents, (linkaddr_t *)lladdr, + /* Add parent in instance nbr table - again this is due to DIO */ + p = nbr_table_add_lladdr(&dag->instance->nbr_table, (linkaddr_t *)lladdr, NBR_TABLE_REASON_RPL_DIO, dio); if(p == NULL) { PRINTF("RPL: rpl_add_parent p NULL\n"); @@ -713,18 +764,38 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) return p; } /*---------------------------------------------------------------------------*/ -static rpl_parent_t * -find_parent_any_dag_any_instance(uip_ipaddr_t *addr) +rpl_parent_t * +rpl_find_parent_any_dag_any_instance(uip_ipaddr_t *addr) { + rpl_instance_t *instance, *end; + rpl_parent_t *p; + uip_ds6_nbr_t *ds6_nbr = uip_ds6_nbr_lookup(addr); const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_nbr); - return nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)lladdr); + + + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; + instance < end; ++instance) { + p = nbr_table_head(&instance->nbr_table); + while(p != NULL) { + if(linkaddr_cmp(rpl_get_parent_lladdr(p), (linkaddr_t *) lladdr)){ + return p; + } + p = nbr_table_next(&instance->nbr_table, p); + } + } + return NULL; } /*---------------------------------------------------------------------------*/ rpl_parent_t * rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr) { - rpl_parent_t *p = find_parent_any_dag_any_instance(addr); + rpl_parent_t *p; + + uip_ds6_nbr_t *ds6_nbr = uip_ds6_nbr_lookup(addr); + const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_nbr); + + p = nbr_table_get_from_lladdr(&dag->instance->nbr_table, (linkaddr_t *)lladdr); if(p != NULL && p->dag == dag) { return p; } else { @@ -735,23 +806,28 @@ rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr) static rpl_dag_t * find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr) { - rpl_parent_t *p = find_parent_any_dag_any_instance(addr); - if(p != NULL) { + rpl_parent_t *p = rpl_find_parent_any_dag(instance, addr); + if(p != NULL){ return p->dag; - } else { - return NULL; } + return NULL; } /*---------------------------------------------------------------------------*/ rpl_parent_t * rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr) { - rpl_parent_t *p = find_parent_any_dag_any_instance(addr); - if(p && p->dag && p->dag->instance == instance) { - return p; - } else { + rpl_parent_t *p; + + if(instance == NULL){ return NULL; } + + uip_ds6_nbr_t *ds6_nbr = uip_ds6_nbr_lookup(addr); + const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_nbr); + + p = nbr_table_get_from_lladdr(&instance->nbr_table, (linkaddr_t *)lladdr); + + return p; } /*---------------------------------------------------------------------------*/ rpl_dag_t * @@ -833,6 +909,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) rpl_set_default_route(instance, rpl_get_parent_ipaddr(best_dag->preferred_parent)); PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n", (unsigned)old_rank, best_dag->rank); + // TODO : handle RPL stats for each instance RPL_STAT(rpl_stats.parent_switch++); if(RPL_IS_STORING(instance) && last_parent != NULL) { /* Send a No-Path DAO to the removed preferred parent. */ @@ -863,9 +940,9 @@ best_parent(rpl_dag_t *dag, int fresh_only) return NULL; } - of = dag->instance->of; +of = dag->instance->of; /* Search for the best parent according to the OF */ - for(p = nbr_table_head(rpl_parents); p != NULL; p = nbr_table_next(rpl_parents, p)) { + for(p = nbr_table_head(&dag->instance->nbr_table); p != NULL; p = nbr_table_next(&dag->instance->nbr_table, p)) { /* Exclude parents from other DAGs or announcing an infinite rank */ if(p->dag != dag || p->rank == INFINITE_RANK) { @@ -939,7 +1016,7 @@ rpl_remove_parent(rpl_parent_t *parent) rpl_nullify_parent(parent); - nbr_table_remove(rpl_parents, parent); + nbr_table_remove(&parent->dag->instance->nbr_table, parent); } /*---------------------------------------------------------------------------*/ void @@ -1130,10 +1207,6 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) instance->of = of; instance->mop = dio->mop; - instance->mc.type = dio->mc.type; - instance->mc.flags = dio->mc.flags; - instance->mc.aggr = dio->mc.aggr; - instance->mc.prec = dio->mc.prec; instance->current_dag = dag; instance->dtsn_out = RPL_LOLLIPOP_INIT; @@ -1151,17 +1224,21 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) /* Copy prefix information from the DIO into the DAG object. */ memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t)); +#if RPL_WITH_MC + memcpy(&instance->mc, &dio->mc, sizeof(dio->mc)); +#endif /* RPL_WITH_MC */ + rpl_set_preferred_parent(dag, p); instance->of->update_metric_container(instance); dag->rank = rpl_rank_via_parent(p); /* So far this is the lowest rank we are aware of. */ dag->min_rank = dag->rank; - if(default_instance == NULL) { - default_instance = instance; + if(last_joined_instance == NULL) { + last_joined_instance = instance; } - PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", + PRINTF("RPL: Joined DAG with instance ID %u, rank %u, DAG ID ", dio->instance_id, dag->rank); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); @@ -1251,7 +1328,7 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio) dag->rank = rpl_rank_via_parent(p); 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 ", + PRINTF("RPL: Joined DAG with instance ID %u, rank %u, DAG ID ", dio->instance_id, dag->rank); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); @@ -1296,7 +1373,7 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio) rpl_process_parent_event(dag->instance, p); } - PRINTF("RPL: Participating in a global repair (version=%u, rank=%hu)\n", + PRINTF("RPL: Participating in a global repair (version=%u, rank=%u)\n", dag->version, dag->rank); RPL_STAT(rpl_stats.global_repairs++); @@ -1334,23 +1411,27 @@ void rpl_recalculate_ranks(void) { rpl_parent_t *p; + rpl_instance_t *instance, *end; /* * 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. */ - p = nbr_table_head(rpl_parents); - while(p != NULL) { - if(p->dag != NULL && p->dag->instance && (p->flags & RPL_PARENT_FLAG_UPDATED)) { - p->flags &= ~RPL_PARENT_FLAG_UPDATED; - PRINTF("RPL: rpl_process_parent_event recalculate_ranks\n"); - if(!rpl_process_parent_event(p->dag->instance, p)) { - PRINTF("RPL: A parent was dropped\n"); + for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; + instance < end; ++instance) { + p = nbr_table_head(&instance->nbr_table); + while(p != NULL) { + if(p->dag != NULL && p->dag->instance && (p->flags & RPL_PARENT_FLAG_UPDATED)) { + p->flags &= ~RPL_PARENT_FLAG_UPDATED; + PRINTF("RPL: rpl_process_parent_event recalculate_ranks\n"); + if(!rpl_process_parent_event(p->dag->instance, p)) { + PRINTF("RPL: A parent was dropped\n"); + } + } + p = nbr_table_next(&instance->nbr_table, p); } - } - p = nbr_table_next(rpl_parents, p); - } + } } /*---------------------------------------------------------------------------*/ int @@ -1399,7 +1480,7 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p) #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", + PRINTF("RPL: Moving in the instance from rank %u to %u\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 "); @@ -1449,6 +1530,12 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); +#if RPL_FILTER_DIO + if(rpl_filter_dio(from, dio)){ + return; + } +#endif /* RPL_FILTER_DIO */ + if(dag != NULL && instance != NULL) { if(lollipop_greater_than(dio->version, dag->version)) { if(dag->rank == ROOT_RANK(instance)) { @@ -1621,4 +1708,197 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) p->dtsn = dio->dtsn; } /*---------------------------------------------------------------------------*/ +#if RPL_FILTER_DIO +int +rpl_filter_dio(uip_ipaddr_t *from, rpl_dio_t *dio) +{ +#if RPL_WITH_MC + rpl_metric_object_t *mc_object, *end, *metric; + rpl_parent_t *p; + rpl_instance_t *instance; +#endif /* RPL_WITH_MC */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) + uint8_t type; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) + uint16_t link_metric; +#endif + uint8_t i; + uint8_t authorized = 0; + + /* Non-empty array, must check if joining instance is authorized */ + if(authorized_instances[0] != 0){ + /* Check if advertised instance is authorized */ + for(i =0; i < sizeof(authorized_instances); i++){ + if(authorized_instances[i] == dio->instance_id){ + authorized = 1; + break; + } + } + + if(authorized == 0){ + PRINTF("RPL: Ignoring a DIO with an unauthorized instance ID: %d\n", + dio->instance_id); + return 1; + } + } + + /* check DAG MC constraints */ +#if RPL_WITH_MC + for(mc_object = dio->mc.objects, end = mc_object + RPL_MAX_DAG_MC_OBJECTS; mc_object < end; ++mc_object) { + if(mc_object != NULL && mc_object->flags & RPL_DAG_MC_FLAG_C){ + switch(mc_object->type){ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) + case RPL_DAG_MC_ENERGY: +#ifdef RPL_DAG_MC_ENERGY_TYPE + type = RPL_DAG_MC_ENERGY_TYPE; +#else + instance = rpl_get_instance(dio->instance_id); + if(instance != NULL + && instance->current_dag->rank == ROOT_RANK(instance)) { + type = RPL_DAG_MC_ENERGY_TYPE_MAINS; + } else { + type = RPL_DAG_MC_ENERGY_TYPE_BATTERY; + } +#endif /* RPL_DAG_MC_ENERGY_TYPE */ + if(mc_object->obj.energy.flags & RPL_DAG_MC_ENERGY_FLAG_INCLUDED + && (mc_object->obj.energy.flags & RPL_DAG_MC_ENERGY_FLAG_TYPE)>>1 != type){ + printf("RPL: DIO dropped: Energy type not allowed\n"); + return 1; + } + else if((mc_object->obj.energy.flags & RPL_DAG_MC_ENERGY_FLAG_INCLUDED) == 0 + && (mc_object->obj.energy.flags & RPL_DAG_MC_ENERGY_FLAG_TYPE)>>1 == type){ + printf("RPL: DIO dropped: Energy type not allowed\n"); + return 1; + } + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + metric = rpl_find_metric(&dio->mc, RPL_DAG_MC_HOPCOUNT, + RPL_DAG_MC_METRIC_OBJECT); + if (metric == NULL + || metric->obj.hopcount.count > mc_object->obj.hopcount.count){ + printf("RPL: DIO dropped: Hopcount limit reached\n"); + return 1; + } + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) + case RPL_DAG_MC_THROUGHPUT: + metric = rpl_find_metric(&dio->mc, RPL_DAG_MC_THROUGHPUT, + RPL_DAG_MC_METRIC_OBJECT); + if (metric == NULL + || metric->obj.throughput.subobject >= mc_object->obj.throughput.subobject){ + PRINTF("RPL: DIO dropped: max. throughput reached\n"); + return 1; + } + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) + case RPL_DAG_MC_LATENCY: + metric = rpl_find_metric(&dio->mc, RPL_DAG_MC_LATENCY, + RPL_DAG_MC_METRIC_OBJECT); + if (metric == NULL + || metric->obj.latency.subobject >= mc_object->obj.latency.subobject){ + PRINTF("RPL: DIO dropped: max. latency exceeded\n"); + return 1; + } + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) + case RPL_DAG_MC_ETX: + p = rpl_find_parent_any_dag(rpl_get_instance(dio->instance_id), from); + link_metric = rpl_get_parent_link_metric(p); + if(link_metric == 0) { + // TODO : handle that case + //link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; + } + if(mc_object->aggr == RPL_DAG_MC_AGGR_MAXIMUM + && link_metric > mc_object->obj.etx.subobject){ + printf("RPL: DIO dropped: max. link ETX exceeded (%u > %u)\n", + link_metric, + mc_object->obj.etx.subobject); + instance = rpl_get_instance(dio->instance_id); + if(p != NULL && instance != NULL && p == instance->current_dag->preferred_parent){ + rpl_nullify_parent(p); + } + return 1; + } + else if(mc_object->aggr == RPL_DAG_MC_AGGR_ADDITIVE){ + if (dio->rank + link_metric > mc_object->obj.etx.subobject){ + PRINTF("RPL: DIO dropped: max. path ETX exceeded (%u.%u > %u.%u)\n", + dio->rank + link_metric, + mc_object->obj.etx.subobject); + instance = rpl_get_instance(dio->instance_id); + if(p != NULL && instance != NULL && p == instance->current_dag->preferred_parent){ + rpl_nullify_parent(p); + } + return 1; + } + } + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) */ + default: + PRINTF("RPL: Unable to check DAG MC mc_object of unhandled DAG MC type %u\n", + (unsigned)mc_object->type); + return 1; + } + } + } + + return 0; +} +#endif /* RPL_WITH_MC */ +#endif /* RPL_FILTER_DIO */ +/*---------------------------------------------------------------------------*/ +rpl_metric_object_t* +rpl_find_metric(rpl_metric_container_t *mc, int mc_routing_type, + int object_type){ + int i; + for(i =0; i < RPL_MAX_DAG_MC_OBJECTS; i++){ + if(mc->objects[i].type == mc_routing_type && (mc->objects[i].flags & RPL_DAG_MC_FLAG_C) == object_type){ + return &mc->objects[i]; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +rpl_metric_object_t* +rpl_find_metric_any_routing_type(rpl_metric_container_t *mc, int object_type ){ + int i; + for(i =0; i < RPL_MAX_DAG_MC_OBJECTS; i++){ + if(mc->objects[i].type != RPL_DAG_MC_NONE && + (mc->objects[i].flags & RPL_DAG_MC_FLAG_C) == object_type){ + return &mc->objects[i]; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +rpl_metric_object_t *rpl_alloc_metric(rpl_metric_container_t *mc){ + int i; + for(i =0; i < RPL_MAX_DAG_MC_OBJECTS; i++){ + if(mc->objects[i].type == RPL_DAG_MC_NONE){ + return &mc->objects[i]; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void rpl_remove_metric(rpl_metric_object_t *metric){ + memset(metric, 0, sizeof(*metric)); + return ; +} +/*---------------------------------------------------------------------------*/ +void rpl_set_of(uint8_t instance_id, rpl_ocp_t ocp){ + rpl_instance_t *instance; + rpl_of_t *of = rpl_find_of(ocp); + instance = rpl_get_instance(instance_id); + if(instance != NULL && of != NULL){ + instance->of = of; + instance->of->update_metric_container(instance); + } +} + /** @} */ diff --git a/core/net/rpl/rpl-ext-header.c b/core/net/rpl/rpl-ext-header.c index b6d17d4a9ff..ec0a9651909 100644 --- a/core/net/rpl/rpl-ext-header.c +++ b/core/net/rpl/rpl-ext-header.c @@ -77,6 +77,7 @@ rpl_verify_hbh_header(int uip_ext_opt_offset) uint8_t sender_closer; uip_ds6_route_t *route; rpl_parent_t *sender = NULL; + uip_ds6_nbr_t *nbr; if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)) { PRINTF("RPL: Hop-by-hop extension header has wrong size\n"); @@ -130,7 +131,9 @@ rpl_verify_hbh_header(int uip_ext_opt_offset) } sender_rank = UIP_HTONS(UIP_EXT_HDR_OPT_RPL_BUF->senderrank); - sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER)); + + nbr = nbr_table_get_from_lladdr(ds6_neighbors, (const linkaddr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); + sender = rpl_find_parent_any_dag(instance, &nbr->ipaddr); if(sender != NULL && (UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR)) { /* A rank error was signalled, attempt to repair it by updating @@ -569,7 +572,7 @@ update_hbh_header(void) } /*---------------------------------------------------------------------------*/ static int -insert_hbh_header(void) +insert_hbh_header(rpl_instance_t *instance) { int uip_ext_opt_offset; int last_uip_ext_len; @@ -600,8 +603,8 @@ insert_hbh_header(void) UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL; UIP_EXT_HDR_OPT_RPL_BUF->opt_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_EXT_HDR_OPT_RPL_BUF->instance = instance->instance_id; + UIP_EXT_HDR_OPT_RPL_BUF->senderrank = instance->current_dag->rank; uip_len += RPL_HOP_BY_HOP_LEN; temp_len = UIP_IP_BUF->len[1]; UIP_IP_BUF->len[1] += RPL_HOP_BY_HOP_LEN; @@ -634,16 +637,21 @@ rpl_finalize_header(uip_ipaddr_t *addr) 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"); + rpl_instance_t *instance; + instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); + parent = rpl_find_parent_any_dag(instance, addr); + if(parent != NULL && + (parent->dag->instance == NULL || !parent->dag->instance->used || + !parent->dag->joined)) { + PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect parent instance\n"); return 0; } - parent = rpl_find_parent(default_instance->current_dag, addr); if(parent == NULL || parent != parent->dag->preferred_parent) { UIP_EXT_HDR_OPT_RPL_BUF->flags = RPL_HDR_OPT_DOWN; } - UIP_EXT_HDR_OPT_RPL_BUF->instance = default_instance->instance_id; - UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(default_instance->current_dag->rank); + UIP_EXT_HDR_OPT_RPL_BUF->instance = parent->dag->instance->instance_id; + PRINTF("Using instance %d\n", UIP_EXT_HDR_OPT_RPL_BUF->instance); + UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(parent->dag->instance->current_dag->rank); } } } @@ -696,23 +704,30 @@ rpl_remove_header(void) } /*---------------------------------------------------------------------------*/ void -rpl_insert_header(void) +rpl_insert_header(uint8_t instance_id) { - if(default_instance == NULL || default_instance->current_dag == NULL + rpl_instance_t *instance; + if(instance_id == 0){ + instance = rpl_get_default_instance(&UIP_IP_BUF->destipaddr); + } + else{ + instance = rpl_get_instance(instance_id); + } + + if(instance == NULL || instance->current_dag == NULL || uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) || uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { return; } - if(RPL_IS_STORING(default_instance)) { - insert_hbh_header(); + if(RPL_IS_STORING(instance) || instance->mop == RPL_MOP_NO_DOWNWARD_ROUTES) { + insert_hbh_header(instance); } - - if(RPL_IS_NON_STORING(default_instance)) { - if(default_instance->current_dag != NULL) { - if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) { + else if(RPL_IS_NON_STORING(instance)) { + if(instance->current_dag != NULL) { + if(instance->current_dag->rank == ROOT_RANK(instance)) { insert_srh_header(); } else { - insert_hbh_header(); + insert_hbh_header(instance); } } } @@ -721,19 +736,24 @@ rpl_insert_header(void) int rpl_update_header(void) { - if(default_instance == NULL) { + rpl_instance_t *instance; + int uip_ext_opt_offset = 2; + + instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); + + if(instance == NULL) { return 0; } - if(default_instance->current_dag != NULL) { - if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) { + if(instance->current_dag != NULL) { + if(instance->current_dag->rank == ROOT_RANK(instance)) { /* At the root, remove headers if any, and insert SRH or HBH * (SRH is inserted only if the destination is in the DODAG) */ rpl_remove_header(); - if(RPL_IS_NON_STORING(default_instance)) { + if(RPL_IS_NON_STORING(instance)) { return insert_srh_header(); } else { - return insert_hbh_header(); + return insert_hbh_header(instance); } } else { return update_hbh_header(); @@ -742,5 +762,18 @@ rpl_update_header(void) return 0; } } +/*---------------------------------------------------------------------------*/ +rpl_instance_t* +rpl_hbh_get_instance(void) +{ + int uip_ext_opt_offset = 2-8; + return rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); +} +void +rpl_hbh_set_instance(rpl_instance_t *instance) +{ + int uip_ext_opt_offset = 2-8; + UIP_EXT_HDR_OPT_RPL_BUF->instance = instance->instance_id; +} /** @}*/ diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 9ffc61dea85..511d3e46911 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -228,7 +228,7 @@ dis_input(void) if(instance->used == 1) { #if RPL_LEAF_ONLY if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { - PRINTF("RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n"); + PRINTF("RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n"); #else /* !RPL_LEAF_ONLY */ if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { PRINTF("RPL: Multicast DIS => reset DIO timer\n"); @@ -295,6 +295,10 @@ dio_input(void) int len; uip_ipaddr_t from; +#if RPL_WITH_MC + int i_mc_object = 0; +#endif /* RPL_WITH_MC */ + memset(&dio, 0, sizeof(dio)); /* Set default values in case the DIO configuration option is missing. */ @@ -303,7 +307,6 @@ dio_input(void) dio.dag_redund = RPL_DIO_REDUNDANCY; dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC; dio.dag_max_rankinc = RPL_MAX_RANKINC; - dio.ocp = RPL_OF_OCP; dio.default_lifetime = RPL_DEFAULT_LIFETIME; dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; @@ -365,37 +368,127 @@ dio_input(void) switch(subopt_type) { case RPL_OPTION_DAG_METRIC_CONTAINER: +#if !RPL_WITH_MC + PRINTF("RPL: DIO contains MC but MC is supported\n"); + goto discard; +#else if(len < 6) { PRINTF("RPL: Invalid DAG MC, len = %d\n", len); - RPL_STAT(rpl_stats.malformed_msgs++); + RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } - dio.mc.type = buffer[i + 2]; - dio.mc.flags = buffer[i + 3] << 1; - dio.mc.flags |= buffer[i + 4] >> 7; - dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3; - dio.mc.prec = buffer[i + 4] & 0xf; - dio.mc.length = buffer[i + 5]; - - if(dio.mc.type == RPL_DAG_MC_NONE) { - /* No metric container: do nothing */ - } else if(dio.mc.type == RPL_DAG_MC_ETX) { - dio.mc.obj.etx = get16(buffer, i + 6); - - PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n", - (unsigned)dio.mc.type, - (unsigned)dio.mc.flags, - (unsigned)dio.mc.aggr, - (unsigned)dio.mc.prec, - (unsigned)dio.mc.length, - (unsigned)dio.mc.obj.etx); - } else if(dio.mc.type == RPL_DAG_MC_ENERGY) { - dio.mc.obj.energy.flags = buffer[i + 6]; - dio.mc.obj.energy.energy_est = buffer[i + 7]; - } else { - PRINTF("RPL: Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type); - goto discard; + + i += 2; + len -= 2; + + for(; len > 0; len -= 4+dio.mc.objects[i_mc_object-1].length) { + + if(i_mc_object >= RPL_MAX_DAG_MC_OBJECTS){ + PRINTF("RPL: Maximum objects in DAG MC reached\n"); + goto discard; + } + + dio.mc.objects[i_mc_object].type = buffer[i]; + dio.mc.objects[i_mc_object].flags = buffer[i + 1] << 1; + dio.mc.objects[i_mc_object].flags |= buffer[i + 2] >> 7; + dio.mc.objects[i_mc_object].aggr = (buffer[i + 2] >> 4) & 0x3; + dio.mc.objects[i_mc_object].prec = buffer[i + 2] & 0xf; + dio.mc.objects[i_mc_object].length = buffer[i + 3]; + + PRINTF("RPL: MC Obj: type %u, flags %u, aggr %u, prec %u, length %u", + (unsigned)dio.mc.objects[i_mc_object].type, + (unsigned)dio.mc.objects[i_mc_object].flags, + (unsigned)dio.mc.objects[i_mc_object].aggr, + (unsigned)dio.mc.objects[i_mc_object].prec, + (unsigned)dio.mc.objects[i_mc_object].length); + + switch(dio.mc.objects[i_mc_object].type){ + case RPL_DAG_MC_NONE: + /* No metric container: do nothing */ + break; +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_NSA) + case RPL_DAG_MC_NSA: + dio.mc.objects[i_mc_object].obj.nsa.flags = get16(buffer, i + 4); + PRINTF(", NSA flags %u",(unsigned)dio.mc.objects[i_mc_object].obj.nsa.flags); + /* TODO: Handle TLVs*/ + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_NSA) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) + case RPL_DAG_MC_ENERGY: + dio.mc.objects[i_mc_object].obj.energy.flags = buffer[i + 4]; + dio.mc.objects[i_mc_object].obj.energy.energy_est = buffer[i + 5]; + PRINTF(", Energy est. %u",(unsigned)dio.mc.objects[i_mc_object].obj.energy.energy_est); + PRINTF(", Energy flags %u",(unsigned)dio.mc.objects[i_mc_object].obj.energy.flags); + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + dio.mc.objects[i_mc_object].obj.hopcount.flags = buffer[i + 4]; + dio.mc.objects[i_mc_object].obj.hopcount.count = buffer[i + 5]; + PRINTF(", Hopcount %u",(unsigned)dio.mc.objects[i_mc_object].obj.hopcount.count); + /* TODO: Handle TLVs*/ + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) + case RPL_DAG_MC_THROUGHPUT: + dio.mc.objects[i_mc_object].obj.throughput.subobject = get32(buffer, i + 4); + PRINTF(", Throughput %u",(unsigned)dio.mc.objects[i_mc_object].obj.throughput.subobject); + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) + case RPL_DAG_MC_LATENCY: + dio.mc.objects[i_mc_object].obj.latency.subobject = get32(buffer, i + 4); + PRINTF(", Latency %u",(unsigned)dio.mc.objects[i_mc_object].obj.latency.subobject); + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LQL) + case RPL_DAG_MC_LQL: + dio.mc.objects[i_mc_object].obj.lql.flags = buffer[i + 4]; + PRINTF(", LQL Flags %u",(unsigned)dio.mc.objects[i_mc_object].obj.lql.flags); + /* TODO: Handle LQL value-counter */ + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LQL) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) + case RPL_DAG_MC_ETX: + dio.mc.objects[i_mc_object].obj.etx.subobject = get16(buffer, i + 4); + PRINTF(", ETX %u",(unsigned)dio.mc.objects[i_mc_object].obj.etx.subobject); + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LC) + case RPL_DAG_MC_LC: + dio.mc.objects[i_mc_object].obj.lc.flags = buffer[i + 4]; + /* If used as a constraint, use type 2 sub-object */ + if(dio.mc.objects[i_mc_object].flags & RPL_DAG_MC_FLAG_C) { + dio.mc.objects[i_mc_object].obj.lc.subobject.type2.color = buffer[i + 5] << 2; + dio.mc.objects[i_mc_object].obj.lc.subobject.type2.color |= buffer[i + 6] >> 6; + dio.mc.objects[i_mc_object].obj.lc.subobject.type2.flags = buffer[i + 6] << 2; + PRINTF(", LC flags %u",(unsigned)dio.mc.objects[i_mc_object].obj.lc.subobject.type2.flags); + } + else { /* else, it is used as a metric so use type 1 sub-object*/ + dio.mc.objects[i_mc_object].obj.lc.subobject.type1.color = buffer[i + 5] << 2; + dio.mc.objects[i_mc_object].obj.lc.subobject.type1.color |= buffer[i + 6] >> 6; + dio.mc.objects[i_mc_object].obj.lc.subobject.type1.counter = buffer[i + 6] << 2; + PRINTF(", LC counter %u",(unsigned)dio.mc.objects[i_mc_object].obj.lc.subobject.type1.counter); + } + PRINTF(", LC color %u",(unsigned)dio.mc.objects[i_mc_object].obj.lc.subobject.type2.color); + + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LC) */ + default: + PRINTF("RPL: Unhandled DAG MC Object type: %u\n", (unsigned)dio.mc.objects[i_mc_object].type); + goto discard; + } + i+=4+dio.mc.objects[i_mc_object].length; + i_mc_object++; + PRINTF("\n"); } + + if(len != 0) { + PRINTF("RPL: Invalid DIO packet\n"); + RPL_STAT(rpl_stats.malformed_msgs++); + goto discard; + } +#endif /* !RPL_WITH_MC */ break; case RPL_OPTION_ROUTE_INFO: if(len < 9) { @@ -424,7 +517,7 @@ dio_input(void) case RPL_OPTION_DAG_CONF: if(len != 16) { PRINTF("RPL: Invalid DAG configuration option, len = %d\n", len); - RPL_STAT(rpl_stats.malformed_msgs++); + RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } @@ -483,6 +576,10 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) rpl_dag_t *dag = instance->current_dag; #if !RPL_LEAF_ONLY uip_ipaddr_t addr; +#if RPL_WITH_MC + int i = 0; + uint8_t metric_data_len = 0; +#endif /* RPL_WITH_MC */ #endif /* !RPL_LEAF_ONLY */ #if RPL_LEAF_ONLY @@ -535,31 +632,97 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id)); pos += 16; -#if !RPL_LEAF_ONLY - if(instance->mc.type != RPL_DAG_MC_NONE) { - instance->of->update_metric_container(instance); +#if !RPL_LEAF_ONLY && RPL_WITH_MC + + instance->of->update_metric_container(instance); + /* Calculating Metric Container Metric Data length */ + for(; i < RPL_MAX_DAG_MC_OBJECTS; i++){ + if(instance->mc.objects[i].type != RPL_DAG_MC_NONE){ + metric_data_len += 4 + instance->mc.objects[i].length; + } + } + /* add metric container object only if there is at least one object in the MC */ + if(metric_data_len > 0){ buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER; - buffer[pos++] = 6; - 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, instance->mc.obj.etx); - pos += 2; - } else if(instance->mc.type == RPL_DAG_MC_ENERGY) { - buffer[pos++] = 2; - 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)instance->mc.type); - return; + buffer[pos++] = metric_data_len; + for(i =0; i < RPL_MAX_DAG_MC_OBJECTS; i++){ + if(instance->mc.objects[i].type != RPL_DAG_MC_NONE){ + buffer[pos++] = instance->mc.objects[i].type; + buffer[pos++] = instance->mc.objects[i].flags >> 1; + buffer[pos] = (instance->mc.objects[i].flags & 1) << 7; + buffer[pos++] |= (instance->mc.objects[i].aggr << 4) | instance->mc.objects[i].prec; + buffer[pos++] = instance->mc.objects[i].length; + switch(instance->mc.objects[i].type){ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_NSA) + case RPL_DAG_MC_NSA: + set16(buffer, pos, instance->mc.objects[i].obj.nsa.flags); + pos += 2; + /* TODO: Handle TLVs*/ + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_NSA) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) + case RPL_DAG_MC_ENERGY: + buffer[pos++] = instance->mc.objects[i].obj.energy.flags; + buffer[pos++] = instance->mc.objects[i].obj.energy.energy_est; + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + buffer[pos++] = instance->mc.objects[i].obj.hopcount.flags; + buffer[pos++] = instance->mc.objects[i].obj.hopcount.count; + /* TODO: Handle TLVs*/ + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) + case RPL_DAG_MC_THROUGHPUT: + set32(buffer, pos, instance->mc.objects[i].obj.throughput.subobject); + pos += 4; + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) + case RPL_DAG_MC_LATENCY: + set32(buffer, pos, instance->mc.objects[i].obj.latency.subobject); + pos += 4; + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LQL) + case RPL_DAG_MC_LQL: + buffer[pos++] = instance->mc.objects[i].obj.lql.flags; + /* TODO: Handle LQL value-counter */ + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LQL) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) + case RPL_DAG_MC_ETX: + set16(buffer, pos, instance->mc.objects[i].obj.etx.subobject); + pos += 2; + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LC) + case RPL_DAG_MC_LC: + buffer[pos++] = instance->mc.objects[i].obj.lc.flags; + /* If used as a constraint, use type 2 sub-object */ + if(instance->mc.objects[i].flags & RPL_DAG_MC_FLAG_C) { + buffer[pos++] = instance->mc.objects[i].obj.lc.subobject.type2.color >> 2; + buffer[pos] = instance->mc.objects[i].obj.lc.subobject.type2.color << 6; + buffer[pos++] |= instance->mc.objects[i].obj.lc.subobject.type2.flags; + } + else { /* else, it is used as a metric so use type 1 sub-object*/ + buffer[pos++] = instance->mc.objects[i].obj.lc.subobject.type1.color >> 2; + buffer[pos] = instance->mc.objects[i].obj.lc.subobject.type1.color << 6; + buffer[pos++] |= instance->mc.objects[i].obj.lc.subobject.type1.counter; + } + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LC) */ + default: + PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type %u\n", + (unsigned)instance->mc.objects[i].type); + return; + } + } } } -#endif /* !RPL_LEAF_ONLY */ +#endif /* !RPL_LEAF_ONLY && RPL_WITH_MC */ /* Always add a DAG configuration option. */ buffer[pos++] = RPL_OPTION_DAG_CONF; diff --git a/core/net/rpl/rpl-mrhof.c b/core/net/rpl/rpl-mrhof.c index c51ac869422..26317fb8341 100644 --- a/core/net/rpl/rpl-mrhof.c +++ b/core/net/rpl/rpl-mrhof.c @@ -132,31 +132,56 @@ parent_link_metric(rpl_parent_t *p) static uint16_t parent_path_cost(rpl_parent_t *p) { - uint16_t base; + uint32_t path_cost = 0; if(p == NULL || p->dag == NULL || p->dag->instance == NULL) { return 0xffff; } #if RPL_WITH_MC - /* Handle the different MC types */ - switch(p->dag->instance->mc.type) { - case RPL_DAG_MC_ETX: - base = p->mc.obj.etx; - break; + rpl_metric_object_t *metric_object; + /* Handle the different MC object types */ + metric_object = rpl_find_metric_any_routing_type(&p->mc, RPL_DAG_MC_METRIC_OBJECT); + if(metric_object == NULL){ + path_cost = p->rank + parent_link_metric(p); + } + else{ + switch(metric_object->type){ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) case RPL_DAG_MC_ENERGY: - base = p->mc.obj.energy.energy_est << 8; + path_cost = metric_object->obj.energy.energy_est + parent_link_metric(p); + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + path_cost = p->rank + 1; break; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) + case RPL_DAG_MC_LATENCY: + + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) + case RPL_DAG_MC_ETX: + /* + As specified in RFC 6719, Section 3.4, Approximation of ETX MUST be made + from advertised rank and ETX Metric object in MC must be ignored. + */ + path_cost = p->rank + parent_link_metric(p); + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) */ default: - base = p->rank; + PRINTF("RPL: MRHOF, Unhandled DAG MC Object type: %u\n", (unsigned)metric_object->type); break; + } } #else /* RPL_WITH_MC */ - base = p->rank; + path_cost = p->rank + parent_link_metric(p); #endif /* RPL_WITH_MC */ /* path cost upper bound: 0xffff */ - return MIN((uint32_t)base + parent_link_metric(p), 0xffff); + return MIN(path_cost, 0xffff); } /*---------------------------------------------------------------------------*/ static rpl_rank_t @@ -245,15 +270,21 @@ best_dag(rpl_dag_t *d1, rpl_dag_t *d2) static void update_metric_container(rpl_instance_t *instance) { - instance->mc.type = RPL_DAG_MC_NONE; + metric_object = rpl_find_metric_any_routing_type(&instance->mc, RPL_DAG_MC_METRIC_OBJECT); + if(metric_object != NULL){ + rpl_remove_metric(metric_object); + } } #else /* RPL_WITH_MC */ static void update_metric_container(rpl_instance_t *instance) { - rpl_dag_t *dag; + rpl_metric_object_t *metric_object, *parent_metric_object; uint16_t path_cost; + rpl_dag_t *dag; +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) uint8_t type; +#endif dag = instance->current_dag; if(dag == NULL || !dag->joined) { @@ -261,39 +292,82 @@ update_metric_container(rpl_instance_t *instance) return; } + metric_object = rpl_find_metric_any_routing_type(&instance->mc, RPL_DAG_MC_METRIC_OBJECT); + parent_metric_object = rpl_find_metric_any_routing_type(&dag->preferred_parent->mc, RPL_DAG_MC_METRIC_OBJECT); + if(dag->rank == ROOT_RANK(instance)) { /* Configure MC at root only, other nodes are auto-configured when joining */ - instance->mc.type = RPL_DAG_MC; - instance->mc.flags = 0; - instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; - instance->mc.prec = 0; +#if RPL_DAG_MC != RPL_DAG_MC_NONE + if(metric_object == NULL){ + metric_object = rpl_alloc_metric(&instance->mc); + if(metric_object == NULL){ + PRINTF("RPL: Cannot update the metric container, no metric object available\n"); + return; + } + metric_object->type = RPL_DAG_MC; + metric_object->flags = RPL_DAG_MC_FLAG_P; + metric_object->aggr = RPL_DAG_MC_AGGR_ADDITIVE; + metric_object->prec = 0; + + switch(metric_object->type){ + case RPL_DAG_MC_HOPCOUNT: + metric_object->obj.hopcount.count = 1; + break; + case RPL_DAG_MC_LATENCY: + metric_object->obj.latency.subobject = 0; + break; + } + } +#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ path_cost = dag->rank; } else { path_cost = parent_path_cost(dag->preferred_parent); } - /* Handle the different MC types */ - switch(instance->mc.type) { + /* Handle the different MC object types */ + switch(metric_object->type){ case RPL_DAG_MC_NONE: + break; - case RPL_DAG_MC_ETX: - instance->mc.length = sizeof(instance->mc.obj.etx); - instance->mc.obj.etx = path_cost; - break; +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) case RPL_DAG_MC_ENERGY: - instance->mc.length = sizeof(instance->mc.obj.energy); + metric_object->length = 2; +#ifdef RPL_DAG_MC_ENERGY_TYPE + type = RPL_DAG_MC_ENERGY_TYPE; +#else /* RPL_DAG_MC_ENERGY_TYPE */ if(dag->rank == ROOT_RANK(instance)) { type = RPL_DAG_MC_ENERGY_TYPE_MAINS; } else { type = RPL_DAG_MC_ENERGY_TYPE_BATTERY; } - instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE; - /* Energy_est is only one byte, use the least significant byte of the path metric. */ - instance->mc.obj.energy.energy_est = path_cost >> 8; +#endif /* RPL_DAG_MC_ENERGY_TYPE */ + metric_object->obj.energy.flags = type << RPL_DAG_MC_ENERGY_FLAG_TYPE; + metric_object->obj.energy.energy_est = path_cost; break; - default: - PRINTF("RPL: MRHOF, non-supported MC %u\n", instance->mc.type); +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + metric_object->obj.hopcount.count = parent_metric_object->obj.hopcount.count + 1; + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) + case RPL_DAG_MC_LATENCY: + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) */ +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) + case RPL_DAG_MC_ETX: + PRINTF("RPL: Removed ETX Metric Obj. in MC, Rank used instead\n"); + /* + As specified in RFC 6719, Section 3.4, ETX metric MUST NOT be advertised + in the Metric Container. + */ + rpl_remove_metric(metric_object); + break; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) */ + default: + PRINTF("RPL: MRHOF, Unhandled DAG MC Object type: %u\n", (unsigned)metric_object->type); + return; } } #endif /* RPL_WITH_MC */ diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index d0bfd1296fa..cbc5fdbb7ca 100644 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -217,7 +217,17 @@ best_dag(rpl_dag_t *d1, rpl_dag_t *d2) static void update_metric_container(rpl_instance_t *instance) { - instance->mc.type = RPL_DAG_MC_NONE; + rpl_metric_object_t* metric_object, *constraint_object; + metric_object = rpl_find_metric_any_routing_type(&instance->mc, RPL_DAG_MC_METRIC_OBJECT); + if(metric_object != NULL){ + /* Only remove if there is no constraint of same type, + which means it is use by the receiver for the constrint*/ + constraint_object = rpl_find_metric(&instance->mc, metric_object->type, RPL_DAG_MC_CONSTRAINT_OBJECT); + if(constraint_object == NULL){ + PRINTF("RPL: Removed unused metric object in OF0 ..\n"); + rpl_remove_metric(metric_object); + } + } } /*---------------------------------------------------------------------------*/ rpl_of_t rpl_of0 = { diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index 34d2e4445be..71c4c921831 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.h @@ -259,6 +259,14 @@ #define RPL_MCAST_LIFETIME 3 #endif +/* Values used to specify which OFs to support / enable */ +#define RPL_OF_OF0 0x1 /* Objective Function Zero */ +#define RPL_OF_MRHOF 0x2 /* MRHOF */ + + #define RPL_LB_NONE 0 + #define RPL_LB_ROUND_ROBIN 1 + #define RPL_LB_MIN_NOACK 2 + /* DIS related */ #define RPL_DIS_SEND 1 @@ -301,7 +309,7 @@ struct rpl_dio { rpl_rank_t dag_min_hoprankinc; rpl_prefix_t destination_prefix; rpl_prefix_t prefix_info; - struct rpl_metric_container mc; + rpl_metric_container_t mc; }; typedef struct rpl_dio rpl_dio_t; @@ -336,7 +344,7 @@ extern rpl_stats_t rpl_stats; /*---------------------------------------------------------------------------*/ /* Instances */ extern rpl_instance_t instance_table[]; -extern rpl_instance_t *default_instance; +extern rpl_instance_t *last_joined_instance; /* ICMPv6 functions for RPL. */ void dis_output(uip_ipaddr_t *addr); @@ -353,6 +361,7 @@ 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_filter_dio(uip_ipaddr_t *, rpl_dio_t *); int rpl_process_parent_event(rpl_instance_t *, rpl_parent_t *); /* DAG object management. */ @@ -366,6 +375,7 @@ void rpl_purge_dags(void); 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 *); rpl_parent_t *rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr); +rpl_parent_t *rpl_find_parent_any_dag_any_instance(uip_ipaddr_t *addr); void rpl_nullify_parent(rpl_parent_t *); void rpl_remove_parent(rpl_parent_t *); void rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent); @@ -380,9 +390,6 @@ 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); -/* Objective function. */ -rpl_of_t *rpl_find_of(rpl_ocp_t); - /* Timer functions. */ void rpl_schedule_dao(rpl_instance_t *); void rpl_schedule_dao_immediately(rpl_instance_t *); @@ -396,7 +403,4 @@ void rpl_reset_periodic_timer(void); /* Route poisoning. */ void rpl_poison_routes(rpl_dag_t *, rpl_parent_t *); - -rpl_instance_t *rpl_get_default_instance(void); - #endif /* RPL_PRIVATE_H */ diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 8149401b40f..0891de5be19 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -84,13 +84,11 @@ handle_periodic_timer(void *ptr) rpl_dag_t *dag = rpl_get_any_dag(); rpl_purge_dags(); - if(dag != NULL) { - if(RPL_IS_STORING(dag->instance)) { - rpl_purge_routes(); - } - if(RPL_IS_NON_STORING(dag->instance)) { - rpl_ns_periodic(); - } + if(dag != NULL && RPL_IS_STORING(dag->instance)) { + rpl_purge_routes(); + } + if(dag != NULL && RPL_IS_NON_STORING(dag->instance)) { + rpl_ns_periodic(); } rpl_recalculate_ranks(); @@ -423,7 +421,7 @@ get_probing_target(rpl_dag_t *dag) /* With 50% probability: probe best non-fresh parent */ if(random_rand() % 2 == 0) { - p = nbr_table_head(rpl_parents); + p = nbr_table_head(&dag->instance->nbr_table); while(p != NULL) { if(p->dag == dag && !rpl_parent_is_fresh(p)) { /* p is in our dag and needs probing */ @@ -434,13 +432,13 @@ get_probing_target(rpl_dag_t *dag) probing_target_rank = p_rank; } } - p = nbr_table_next(rpl_parents, p); + p = nbr_table_next(&dag->instance->nbr_table, p); } } /* If we still do not have a probing target: pick the least recently updated parent */ if(probing_target == NULL) { - p = nbr_table_head(rpl_parents); + p = nbr_table_head(&dag->instance->nbr_table); while(p != NULL) { const struct link_stats *stats =rpl_get_parent_link_stats(p); if(p->dag == dag && stats != NULL) { @@ -450,7 +448,7 @@ get_probing_target(rpl_dag_t *dag) probing_target_age = clock_now - stats->last_tx_time; } } - p = nbr_table_next(rpl_parents, p); + p = nbr_table_next(&dag->instance->nbr_table, p); } } @@ -469,7 +467,7 @@ handle_probing_timer(void *ptr) const struct link_stats *stats = rpl_get_parent_link_stats(probing_target); (void)stats; PRINTF("RPL: probing %u %s last tx %u min ago\n", - rpl_get_parent_lladdr(probing_target)->u8[7], + nbr_table_get_lladdr(&instance->nbr_table, probing_target)->u8[7], instance->urgent_probing_target != NULL ? "(urgent)" : "", probing_target != NULL ? (unsigned)((clock_time() - stats->last_tx_time) / (60 * CLOCK_SECOND)) : 0 diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index fd03e3cb6a5..45a6df2e178 100644 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -69,7 +69,7 @@ rpl_get_mode(void) } /*---------------------------------------------------------------------------*/ enum rpl_mode -rpl_set_mode(enum rpl_mode m) +rpl_set_mode(enum rpl_mode m, rpl_instance_t *instance) { enum rpl_mode oldmode = mode; @@ -84,20 +84,20 @@ rpl_set_mode(enum rpl_mode m) PRINTF("RPL: switching to mesh mode\n"); mode = m; - if(default_instance != NULL) { - rpl_schedule_dao_immediately(default_instance); + if(instance != NULL) { + rpl_schedule_dao_immediately(instance); } } else if(m == RPL_MODE_FEATHER) { PRINTF("RPL: switching to feather mode\n"); - if(default_instance != NULL) { + if(instance != NULL) { PRINTF("rpl_set_mode: RPL sending DAO with zero lifetime\n"); - if(default_instance->current_dag != NULL) { - dao_output(default_instance->current_dag->preferred_parent, RPL_ZERO_LIFETIME); + if(instance->current_dag != NULL) { + dao_output(instance->current_dag->preferred_parent, RPL_ZERO_LIFETIME); } - rpl_cancel_dao(default_instance); + rpl_cancel_dao(instance); } else { - PRINTF("rpl_set_mode: no default instance\n"); + PRINTF("rpl_set_mode: no valid instance\n"); } mode = m; @@ -145,9 +145,10 @@ rpl_purge_routes(void) r = uip_ds6_route_head(); PRINTF("No more routes to "); PRINT6ADDR(&prefix); - dag = default_instance->current_dag; + // TODO : is it always correct ? + dag = r->state.dag; /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */ - if(dag->rank != ROOT_RANK(default_instance)) { + if(dag->rank != ROOT_RANK(dag->instance)) { PRINTF(" -> generate No-Path DAO\n"); dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME); /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */ @@ -260,6 +261,17 @@ rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx) uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0); uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr); +#if RPL_LB == RPL_LB_MIN_NOACK + uip_ds6_nbr_t *nbr = nbr_table_get_from_lladdr(ds6_neighbors, addr); + + if(status == MAC_TX_NOACK){ + nbr->noack_count++; + } + else if(status == MAC_TX_OK){ + nbr->noack_count = 0; + } +#endif /* RPL_LB == RPL_LB_MIN_NOACK */ + 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); @@ -267,9 +279,28 @@ rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx) /* Trigger DAG rank recalculation. */ PRINTF("RPL: rpl_link_neighbor_callback triggering update\n"); parent->flags |= RPL_PARENT_FLAG_UPDATED; + +#if RPL_LB == RPL_LB_MIN_NOACK + if(status == MAC_TX_NOACK){ + if(nbr->noack_count == 5){ + PRINTF("remove parent no ack\n"); + rpl_remove_parent(parent); + } + else{ + PRINTF("No Ack counter for node %d : %d\n", addr->u8[7], nbr->noack_count); + } + } +#endif /* RPL_LB == RPL_LB_MIN_NOACK */ } } } + +#if RPL_LB == RPL_LB_MIN_NOACK + if(nbr->noack_count == 5){ + PRINTF("remove nbr\n"); + uip_ds6_nbr_rm(nbr); + } +#endif /* RPL_LB == RPL_LB_MIN_NOACK */ } /*---------------------------------------------------------------------------*/ void @@ -332,7 +363,7 @@ rpl_init(void) { uip_ipaddr_t rplmaddr; PRINTF("RPL started\n"); - default_instance = NULL; + last_joined_instance = NULL; rpl_dag_init(); rpl_reset_periodic_timer(); diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index 26ee71edc49..119cffd1e8d 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -60,11 +60,15 @@ typedef uint16_t rpl_ocp_t; #define RPL_DAG_MC_ETX 7 /* Expected Transmission Count */ #define RPL_DAG_MC_LC 8 /* Link Color */ -/* IANA Routing Metric/Constraint Common Header Flag field as defined in RFC6551 (bit indexes) */ -#define RPL_DAG_MC_FLAG_P 5 -#define RPL_DAG_MC_FLAG_C 6 -#define RPL_DAG_MC_FLAG_O 7 -#define RPL_DAG_MC_FLAG_R 8 +/* DAG Metric Container flags. */ +#define RPL_DAG_MC_FLAG_P 0x8 +#define RPL_DAG_MC_FLAG_C 0x4 +#define RPL_DAG_MC_FLAG_O 0x2 +#define RPL_DAG_MC_FLAG_R 0x1 + +/* DAG Metric Container Object Types*/ +#define RPL_DAG_MC_METRIC_OBJECT 0x0 +#define RPL_DAG_MC_CONSTRAINT_OBJECT 0x4 /* IANA Routing Metric/Constraint Common Header A Field as defined in RFC6551 */ #define RPL_DAG_MC_AGGR_ADDITIVE 0 @@ -72,37 +76,174 @@ typedef uint16_t rpl_ocp_t; #define RPL_DAG_MC_AGGR_MINIMUM 2 #define RPL_DAG_MC_AGGR_MULTIPLICATIVE 3 -/* The bit index within the flags field of the rpl_metric_object_energy structure. */ -#define RPL_DAG_MC_ENERGY_INCLUDED 3 -#define RPL_DAG_MC_ENERGY_TYPE 1 -#define RPL_DAG_MC_ENERGY_ESTIMATION 0 +/* The bit masks for the flag field of + the rpl_metric_object_energy structure. */ +#define RPL_DAG_MC_ENERGY_FLAG_INCLUDED 0x8 +#define RPL_DAG_MC_ENERGY_FLAG_TYPE 0x6 +#define RPL_DAG_MC_ENERGY_FLAG_ESTIMATION 0 /* IANA Node Type Field as defined in RFC6551 */ -#define RPL_DAG_MC_ENERGY_TYPE_MAINS 0 -#define RPL_DAG_MC_ENERGY_TYPE_BATTERY 1 -#define RPL_DAG_MC_ENERGY_TYPE_SCAVENGING 2 +#define RPL_DAG_MC_ENERGY_TYPE_MAINS 0 +#define RPL_DAG_MC_ENERGY_TYPE_BATTERY 1 +#define RPL_DAG_MC_ENERGY_TYPE_SCAVENGING 2 /* IANA Objective Code Point as defined in RFC6550 */ #define RPL_OCP_OF0 0 #define RPL_OCP_MRHOF 1 +/* NSA Object flags . */ +#define RPL_DAG_MC_NSA_FLAG_A 0x2 +#define RPL_DAG_MC_NSA_FLAG_O 0x1 + +/* Link Color Type 2 Sub-Object flags . */ +#define RPL_DAG_MC_LC_FLAG_I 0x1 + +#if RPL_MAX_DAG_MC_TLV > 0 +/* Representation of a Type-Length-Value Object. + * Specified in RFC 6551, Section 2.1 + */ +struct tlv { + uint8_t type; + uint8_t length; + uint8_t value; +}; +typedef struct tlv rpl_tlv_t; +#endif /* RPL_MAX_DAG_MC_TLV */ + +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_NSA) +/* Representation of a Node State and Attribute (NSA) Metric/Constraint Object. + * Specified in RFC 6551, Section 3.1 + */ +struct rpl_metric_object_nsa { + uint16_t flags; +#if RPL_MAX_DAG_MC_TLV > 0 + uint8_t tlv_table_len; + rpl_tlv_t *tlv_table; +#endif /* RPL_MAX_DAG_MC_TLV */ +}; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_NSA) */ + +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) +/* Representation of a Node Energy (NE) Metric/Constraint Object. + * Specified in RFC 6551, Section 3.2 + */ struct rpl_metric_object_energy { uint8_t flags; uint8_t energy_est; }; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) */ -/* Logical representation of a DAG Metric Container. */ -struct rpl_metric_container { +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) +/* Representation of a Hop Count Metric/Constraint Object. + * Specified in RFC 6551, Section 3.3 + */ +struct rpl_metric_object_hopcount { + uint8_t flags; + uint8_t count; +#if RPL_MAX_DAG_MC_TLV > 0 + rpl_tlv_t tlv_table[RPL_MAX_DAG_MC_TLV]; +#endif /* RPL_MAX_DAG_MC_TLV */ +}; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) */ + +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) +/* Representation of a Throughput Metric/Constraint Object. + * Specified in RFC 6551, Section 4.1 + */ +struct rpl_metric_object_throughput { + uint32_t subobject; +}; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) */ + +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) +/* Representation of a Latency Metric/Constraint Object. + * Specified in RFC 6551, Section 4.2 + */ +struct rpl_metric_object_latency { + uint32_t subobject; +}; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) */ + +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LQL) +/* Representation of a LQL Metric/Constraint Object. + * Specified in RFC 6551, Section 4.3.1 + */ +struct rpl_metric_object_lql { + uint8_t flags; + uint8_t subobjects[8]; /* array where ith element is counter value of LQL value i */ +}; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LQL) */ + +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) +/* Representation of a ETX Reliability Metric/Constraint Object. + * Specified in RFC 6551, Section 4.3.2 + */ +struct rpl_metric_object_etx { + uint16_t subobject; +}; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) */ + +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LC) +/* Representation of a Link Color (LC) Object with Type1 / Type2 + * Sub Object. + * Specified in RFC 6551, Section 4.4 + */ +struct rpl_metric_object_lc { + uint8_t flags; + union { + struct { + uint16_t color; + uint8_t counter; + } type1; + struct { + uint8_t color; + uint8_t flags; + }type2; + } subobject; +}; +#endif /* RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LC) */ + +/* Representation of a Metric/Constraint object (in a DAG Metric Container). */ +struct rpl_metric_object { uint8_t type; uint8_t flags; uint8_t aggr; uint8_t prec; uint8_t length; - union metric_object { + + union { +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_NSA) + struct rpl_metric_object_nsa nsa; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ENERGY) struct rpl_metric_object_energy energy; - uint16_t etx; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_HOPCOUNT) + struct rpl_metric_object_hopcount hopcount; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_THROUGHPUT) + struct rpl_metric_object_throughput throughput; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LATENCY) + struct rpl_metric_object_latency latency; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LQL) + struct rpl_metric_object_lql lql; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_ETX) + struct rpl_metric_object_etx etx; +#endif +#if RPL_IS_METRIC_SUPPORTED(RPL_DAG_MC_LC) + struct rpl_metric_object_lc lc; +#endif } obj; }; +typedef struct rpl_metric_object rpl_metric_object_t; + +/* Logical representation of a DAG Metric Container. */ +struct rpl_metric_container { + rpl_metric_object_t objects[RPL_MAX_DAG_MC_OBJECTS]; +}; typedef struct rpl_metric_container rpl_metric_container_t; /*---------------------------------------------------------------------------*/ struct rpl_instance; @@ -117,6 +258,7 @@ struct rpl_parent { rpl_metric_container_t mc; #endif /* RPL_WITH_MC */ rpl_rank_t rank; + clock_time_t last_tx_time; uint8_t dtsn; uint8_t flags; }; @@ -186,6 +328,13 @@ typedef struct rpl_instance rpl_instance_t; * * Compares two DAGs 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. + * If "parent" is NULL, the objective function selects a default increment + * that is adds to the "base_rank". Otherwise, the OF uses information known + * about "parent" to select an increment to the "base_rank". + * * update_metric_container(dag) * * Updates the metric container for outgoing DIOs in a certain DAG. @@ -222,6 +371,8 @@ struct rpl_instance { rpl_of_t *of; rpl_dag_t *current_dag; rpl_dag_t dag_table[RPL_MAX_DAG_PER_INSTANCE]; + rpl_parent_t parents_mem[NBR_TABLE_MAX_NEIGHBORS]; + nbr_table_t nbr_table; /* The current default router - used for routing "upwards" */ uip_ds6_defrt_t *def_route; uint8_t instance_id; @@ -277,7 +428,7 @@ rpl_instance_t *rpl_get_instance(uint8_t instance_id); int rpl_update_header(void); int rpl_finalize_header(uip_ipaddr_t *addr); int rpl_verify_hbh_header(int); -void rpl_insert_header(void); +void rpl_insert_header(uint8_t instance_id); void rpl_remove_header(void); const struct link_stats *rpl_get_parent_link_stats(rpl_parent_t *p); int rpl_parent_is_fresh(rpl_parent_t *p); @@ -285,17 +436,23 @@ int rpl_parent_is_reachable(rpl_parent_t *p); uint16_t rpl_get_parent_link_metric(rpl_parent_t *p); rpl_rank_t rpl_rank_via_parent(rpl_parent_t *p); const linkaddr_t *rpl_get_parent_lladdr(rpl_parent_t *p); +rpl_instance_t *rpl_hbh_get_instance(void); +void rpl_hbh_set_instance(rpl_instance_t *instance); uip_ipaddr_t *rpl_get_parent_ipaddr(rpl_parent_t *nbr); rpl_parent_t *rpl_get_parent(uip_lladdr_t *addr); -rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr); void rpl_dag_init(void); uip_ds6_nbr_t *rpl_get_nbr(rpl_parent_t *parent); +rpl_instance_t *rpl_get_default_instance(uip_ipaddr_t *dest); void rpl_print_neighbor_list(void); int rpl_process_srh_header(void); int rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr); -/* Per-parent RPL information */ -NBR_TABLE_DECLARE(rpl_parents); +void rpl_set_of(uint8_t instance_id, rpl_ocp_t ocp); +rpl_of_t *rpl_find_of(rpl_ocp_t); +rpl_metric_object_t *rpl_find_metric(rpl_metric_container_t *mc, int mc_routing_type, int is_constraint); +rpl_metric_object_t *rpl_find_metric_any_routing_type(rpl_metric_container_t *mc, int object_type ); +rpl_metric_object_t *rpl_alloc_metric(rpl_metric_container_t *mc); +void rpl_remove_metric(rpl_metric_object_t *metric); /** * RPL modes @@ -319,7 +476,7 @@ enum rpl_mode { * \param mode The new RPL mode * \retval The previous RPL mode */ -enum rpl_mode rpl_set_mode(enum rpl_mode mode); +enum rpl_mode rpl_set_mode(enum rpl_mode mode, rpl_instance_t *instance); /** * Get the RPL mode