static void 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 instance->mc.flags = RPL_DAG_MC_FLAG_P; instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; instance->mc.prec = 0; 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); } #if RPL_DAG_MC == RPL_DAG_MC_ETX 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", 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 instance->mc.type = RPL_DAG_MC_ENERGY; instance->mc.length = sizeof(instance->mc.obj.energy); 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; instance->mc.obj.energy.energy_est = path_metric; #else #error "Unsupported RPL_DAG_MC configured. See rpl.h." #endif /* RPL_DAG_MC */ }
static void 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 instance->mc.type = RPL_DAG_MC; instance->mc.flags = RPL_DAG_MC_FLAG_P; instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; instance->mc.prec = 0; dag = instance->current_dag; if (!dag->joined) { PRINTF("RPL: Cannot update the metric container when not joined\n"); return; } if(dag->rank == ROOT_RANK(instance)) { path_metric = 0; } else { path_metric = calculate_path_metric(dag->preferred_parent); } #if RPL_DAG_MC == 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", 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 instance->mc.length = sizeof(instance->mc.obj.energy); 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; instance->mc.obj.energy.energy_est = path_metric; #elif RPL_DAG_MC == RPL_DAG_MC_TOTALENERGY instance->mc.length = sizeof(instance->mc.obj.total_energy); instance->mc.obj.total_energy = path_metric; // printf("total_energy path_metric:%u\n", path_metric); #endif /* RPL_DAG_MC == RPL_DAG_MC_ETX */ }
static void update_metric_container(rpl_dag_t *dag) { rpl_path_metric_t path_metric; #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; if(dag->rank == ROOT_RANK(dag)) { path_metric = 0; } else { path_metric = calculate_path_metric(dag->preferred_parent); } #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; 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); #elif RPL_DAG_MC == RPL_DAG_MC_ENERGY dag->mc.type = RPL_DAG_MC_ENERGY; dag->mc.length = sizeof(dag->mc.obj.energy); if(dag->rank == ROOT_RANK(dag)) { 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; #else #error "Unsupported RPL_DAG_MC configured. See rpl.h." #endif /* RPL_DAG_MC */ }
/*---------------------------------------------------------------------------*/ #if !RPL_WITH_MC static void update_metric_container(rpl_instance_t *instance) { instance->mc.type = RPL_DAG_MC_NONE; } #else /* RPL_WITH_MC */ static void update_metric_container(rpl_instance_t *instance) { rpl_dag_t *dag; uint16_t path_cost; uint8_t type; dag = instance->current_dag; if(dag == NULL || !dag->joined) { PRINTF("RPL: Cannot update the metric container when not joined\n"); return; } 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; path_cost = dag->rank; } else { path_cost = parent_path_cost(dag->preferred_parent); } /* Handle the different MC types */ switch(instance->mc.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; case RPL_DAG_MC_ENERGY: instance->mc.length = sizeof(instance->mc.obj.energy); 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; break; default: PRINTF("RPL: MRHOF, non-supported MC %u\n", instance->mc.type); break; } }
/*---------------------------------------------------------------------------*/ int rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len) { rpl_prefix_t last_prefix; uint8_t last_len = dag->prefix_info.length; if(len > 128) { return 0; } if(dag->prefix_info.length != 0) { memcpy(&last_prefix, &dag->prefix_info, sizeof(rpl_prefix_t)); } 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"); if(dag->rank != ROOT_RANK(dag->instance)) { /* Autoconfigure an address if this node does not already have an address with this prefix. Otherwise, update the prefix */ if(last_len == 0) { PRINTF("rpl_set_prefix - prefix NULL\n"); check_prefix(NULL, &dag->prefix_info); } else { PRINTF("rpl_set_prefix - prefix NON-NULL\n"); check_prefix(&last_prefix, &dag->prefix_info); } } return 1; }
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))) { return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR; } return p->mc.obj.etx + NI_ETX_TO_RPL_ETX(p->link_metric); }
/*---------------------------------------------------------------------------*/ static void new_dio_interval(rpl_instance_t *instance, int isReset) { uint32_t time; clock_time_t ticks; /* TODO: too small timer intervals for many cases */ time = 1UL << instance->dio_intcurrent; /* Convert from milliseconds to CLOCK_TICKS. */ ticks = (time * CLOCK_SECOND) / 1000; instance->dio_next_delay = ticks; /* random number between I/2 and I */ ticks = ticks / 2 + (ticks / 2 * (uint32_t)random_rand()) / RANDOM_RAND_MAX; /* opt trickle*/ /* if (isReset == 1) { ticks * (uint32_t)random_rand() / RANDOM_RAND_MAX; } else { ticks = ticks / 2 + (ticks / 2 * (uint32_t)random_rand()) / RANDOM_RAND_MAX; } */ /* * The intervals must be equally long among the nodes for Trickle to * operate efficiently. Therefore we need to calculate the delay between * the randomized time and the start time of the next interval. */ instance->dio_next_delay -= ticks; instance->dio_send = 1; #if RPL_CONF_STATS /* keep some stats */ 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(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 */ instance->dio_counter = 0; /* schedule the timer */ PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", ticks); ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance); }
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->instance))) { return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR; } else { long etx = p->link_metric; etx = (etx * RPL_DAG_MC_ETX_DIVISOR) / NEIGHBOR_INFO_ETX_DIVISOR; return p->mc.obj.etx + (uint16_t) etx; } }
rpl_dag_t * rpl_set_root(uip_ipaddr_t *dag_id) { rpl_dag_t *dag; int version; version = -1; dag = rpl_get_dag(RPL_DEFAULT_INSTANCE); if(dag != NULL) { PRINTF("RPL: Dropping a joined DAG when setting this node as root"); version = dag->version; rpl_free_dag(dag); } dag = rpl_alloc_dag(RPL_DEFAULT_INSTANCE); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG\n"); return NULL; } dag->joined = 1; dag->version = version + 1; dag->grounded = RPL_GROUNDED; dag->mop = RPL_MOP_DEFAULT; dag->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; dag->default_lifetime = RPL_DEFAULT_LIFETIME; dag->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; dag->rank = ROOT_RANK(dag); dag->of->update_metric_container(dag); 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]); rpl_reset_dio_timer(dag, 1); return dag; }
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_opp_routing_reset(void) { rpl_dag_t *dag; dag = rpl_get_any_dag(); if(uip_ds6_is_my_addr(&dag->dag_id)) { we_are_root = 1; current_rank = ROOT_RANK(dag->instance); } else { current_rank = INFINITE_RANK; } }
/*---------------------------------------------------------------------------*/ void rpl_purge_routes(void) { uip_ds6_route_t *r; uip_ipaddr_t prefix; rpl_dag_t *dag; rpl_instance_t *instance; //changed /* First pass, decrement lifetime */ r = uip_ds6_route_head(); while(r != NULL) { if(r->state.lifetime >= 1) { /* * If a route is at lifetime == 1, set it to 0, scheduling it for * immediate removal below. This achieves the same as the original code, * which would delete lifetime <= 1 */ r->state.lifetime--; } r = uip_ds6_route_next(r); } /* Second pass, remove dead routes */ r = uip_ds6_route_head(); while(r != NULL) { /*Pre-change handle second_instance*/ if(r->state.lifetime < 1) { /* Routes with lifetime == 1 have only just been decremented from 2 to 1, * thus we want to keep them. Hence < and not <= */ uip_ipaddr_copy(&prefix, &r->ipaddr); uip_ds6_route_rm(r); r = uip_ds6_route_head(); PRINTF("No more routes to "); PRINT6ADDR(&prefix); /*Changed*/ instance = rpl_get_instance(r->state.instance_id); dag = instance->current_dag; //dag1 = second_instance->current_dag; /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */ if(dag->rank != ROOT_RANK(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 */ return; } PRINTF("\n"); } else { r = uip_ds6_route_next(r); } } }
void rpl_opp_routing_init(void) { nbr_table_register(forwarder_set, NULL); memb_init(&forwarder_set_memb); rpl_dag_t *dag; dag = rpl_get_any_dag(); if(uip_ds6_is_my_addr(&dag->dag_id)) { we_are_root = 1; current_rank = ROOT_RANK(dag->instance); } else { process_start(&rpl_forwarder_set_update_process, NULL); } }
/*---------------------------------------------------------------------------*/ static rpl_parent_t * best_parent(rpl_dag_t *dag) { rpl_parent_t *p, *best; best = NULL; p = nbr_table_head(rpl_parents); while(p != NULL) { if(p->dag != dag || p->rank == INFINITE_RANK || p->rank < ROOT_RANK(dag->instance)) { if(p->rank < ROOT_RANK(dag->instance)) { PRINTF("Parent has invalid rank\n"); } /* ignore this neighbor */ } else if(best == NULL) { best = p; } else { best = dag->instance->of->best_parent(best, p); } p = nbr_table_next(rpl_parents, p); } return best; }
/*---------------------------------------------------------------------------*/ int rpl_repair_root(uint8_t instance_id) { rpl_instance_t *instance; instance = rpl_get_instance(instance_id); if(instance == NULL || instance->current_dag->rank != ROOT_RANK(instance)) { return 0; } RPL_LOLLIPOP_INCREMENT(instance->current_dag->version); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); rpl_reset_dio_timer(instance); return 1; }
static void update_metric_container(rpl_dag_t *dag) { dag->mc.type = RPL_DAG_MC_ETX; dag->mc.flags = RPL_DAG_MC_FLAG_P; dag->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; dag->mc.prec = 0; dag->mc.length = sizeof(dag->mc.etx.etx); if(dag->rank == ROOT_RANK(dag)) { dag->mc.etx.etx = 0; } else { dag->mc.etx.etx = calculate_etx(dag->preferred_parent); } PRINTF("RPL: My path ETX to the root is %u.%u\n", dag->mc.etx.etx / RPL_DAG_MC_ETX_DIVISOR, (dag->mc.etx.etx % RPL_DAG_MC_ETX_DIVISOR * 100) / RPL_DAG_MC_ETX_DIVISOR); }
/*---------------------------------------------------------------------------*/ int rpl_repair_root(uint8_t instance_id) { rpl_instance_t *instance; instance = rpl_get_instance(instance_id); if(instance == NULL || instance->current_dag->rank != ROOT_RANK(instance)) { PRINTF("RPL: rpl_repair_root triggered but not root\n"); return 0; } RPL_LOLLIPOP_INCREMENT(instance->current_dag->version); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); PRINTF("RPL: rpl_repair_root initiating global repair with version %d\n", instance->current_dag->version); rpl_reset_dio_timer(instance); return 1; }
/*---------------------------------------------------------------------------*/ int rpl_dag_root_is_root(void) { rpl_instance_t *instance; instance = rpl_get_default_instance(); if(instance == NULL) { return 0; } if(instance->current_dag && instance->current_dag->rank == ROOT_RANK(instance)) { return 1; } return 0; }
/* Set TSCH EB period based on current RPL DIO period. * To use, set #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_new_dio_interval */ void tsch_rpl_callback_new_dio_interval(uint8_t dio_interval) { /* Transmit EBs only if we have a valid rank as per 6TiSCH minimal */ rpl_dag_t *dag = rpl_get_any_dag(); if(dag != NULL && dag->rank != INFINITE_RANK) { /* If we are root set TSCH as coordinator */ if(dag->rank == ROOT_RANK(dag->instance)) { tsch_set_coordinator(1); } /* Set EB period */ tsch_set_eb_period(TSCH_EB_PERIOD); /* Set join priority based on RPL rank */ tsch_set_join_priority(DAG_RANK(dag->rank, dag->instance) - 1); } else { tsch_set_eb_period(0); } }
/*---------------------------------------------------------------------------*/ int rpl_repair_root(uint8_t instance_id) { rpl_instance_t *instance; instance = rpl_get_instance(instance_id); if(instance == NULL || instance->current_dag->rank != ROOT_RANK(instance)) { PRINTF("RPL: rpl_repair_root triggered but not root\n"); return 0; } RPL_STAT(rpl_stats.root_repairs++); RPL_LOLLIPOP_INCREMENT(instance->current_dag->version); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); #if CETIC_6LBR nvm_data.rpl_version_id = instance->current_dag->version; store_nvm_config(); #endif PRINTF("RPL: rpl_repair_root initiating global repair with version %d\n", instance->current_dag->version); rpl_reset_dio_timer(instance); return 1; }
/*---------------------------------------------------------------------------*/ rpl_dag_t * rpl_select_dag(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; if(instance->current_dag->rank != ROOT_RANK(instance)) { rpl_select_parent(p->dag); } best_dag = NULL; for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_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 DAG: "); 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(last_parent == NULL || 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"); rpl_set_preferred_parent(instance->current_dag, 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, RPL_ZERO_LIFETIME); } return NULL; } if(best_dag->preferred_parent != last_parent) { 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); 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, RPL_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); #if DEBUG rpl_print_neighbor_list(); #endif } 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); } return best_dag; }
rpl_dag_t * rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) { rpl_dag_t *dag; rpl_instance_t *instance; uint8_t version; version = RPL_LOLLIPOP_INIT; dag = rpl_get_dodag(instance_id, dag_id); if(dag != NULL) { version = dag->version; 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_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->grounded = RPL_GROUNDED; instance->mop = RPL_MOP_DEFAULT; instance->of = &RPL_OF; memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); 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 = DEFAULT_RPL_DEF_LIFETIME; instance->lifetime_unit = DEFAULT_RPL_LIFETIME_UNIT; dag->rank = ROOT_RANK(instance); if(instance->current_dag != dag && instance->current_dag != NULL) { /* Remove routes installed by DAOs. */ rpl_remove_routes(instance->current_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]); instance->dio_timer.instance=instance; rpl_reset_dio_timer(instance, 1); return dag; }
/*---------------------------------------------------------------------------*/ rpl_dag_t * rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) { rpl_dag_t *dag; rpl_instance_t *instance; uint8_t version; int i; #if CETIC_6LBR version = nvm_data.rpl_version_id; RPL_LOLLIPOP_INCREMENT(version); nvm_data.rpl_version_id = version; store_nvm_config(); #else version = RPL_LOLLIPOP_INIT; #endif instance = rpl_get_instance(instance_id); if(instance != NULL) { for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) { dag = &instance->dag_table[i]; if(dag->used) { if(uip_ipaddr_cmp(&dag->dag_id, dag_id)) { version = dag->version; RPL_LOLLIPOP_INCREMENT(version); #if CETIC_6LBR nvm_data.rpl_version_id = version; store_nvm_config(); #endif } if(dag == dag->instance->current_dag) { PRINTF("RPL: Dropping a joined DAG when setting this node as root"); rpl_set_default_route(instance, NULL); dag->instance->current_dag = NULL; } else { PRINTF("RPL: Dropping a DAG when setting this node as root"); } rpl_free_dag(dag); } } } dag = rpl_alloc_dag(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->grounded = RPL_GROUNDED; dag->preference = RPL_PREFERENCE; instance->mop = RPL_MOP_DEFAULT; instance->of = &RPL_OF; rpl_set_preferred_parent(dag, NULL); memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); instance->dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS; instance->dio_intmin = RPL_DIO_INTERVAL_MIN; /* The current interval must differ from the minimum interval in order to trigger a DIO timer reset. */ instance->dio_intcurrent = RPL_DIO_INTERVAL_MIN + RPL_DIO_INTERVAL_DOUBLINGS; instance->dio_redundancy = RPL_DIO_REDUNDANCY; instance->max_rankinc = RPL_MAX_RANKINC; instance->min_hoprankinc = RPL_MIN_HOPRANKINC; instance->default_lifetime = RPL_DEFAULT_LIFETIME; instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; dag->rank = ROOT_RANK(instance); if(instance->current_dag != dag && instance->current_dag != NULL) { /* Remove routes installed by DAOs. */ rpl_remove_routes(instance->current_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]); rpl_reset_dio_timer(instance); return dag; }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; #if RPL_CONF_MULTICAST /* If the root is advertising MOP 2 but we support MOP 3 we can still join * In that scenario, we suppress DAOs for multicast targets */ if(dio->mop < RPL_MOP_STORING_NO_MULTICAST) { #else if(dio->mop != RPL_MOP_DEFAULT) { #endif PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); #if CETIC_6LBR if(!cetic_6lbr_dio_input_hook(from, instance, dag, dio)) { return; } #endif if(dag != NULL && instance != NULL) { if(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; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); #if CETIC_6LBR nvm_data.rpl_version_id = dag->version; store_nvm_config(); #endif } else { PRINTF("RPL: Global repair\n"); if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } global_repair(from, dag, dio); } return; } if(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); return; } } } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(instance->current_dag->rank == ROOT_RANK(instance) && instance->current_dag != dag) { PRINTF("RPL: Root ignored DIO for different DAG\n"); return; } if(dag == NULL) { #if RPL_MAX_DAG_PER_INSTANCE > 1 PRINTF("RPL: Adding new DAG to known instance.\n"); dag = rpl_add_dag(from, dio); if(dag == NULL) { PRINTF("RPL: Failed to add DAG.\n"); return; } #else /* RPL_MAX_DAG_PER_INSTANCE > 1 */ PRINTF("RPL: Only one instance supported.\n"); return; #endif /* RPL_MAX_DAG_PER_INSTANCE > 1 */ } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } /* Prefix Information Option treated to add new prefix */ if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } return; } /* The DIO comes from a valid DAG, we can refresh its lifetime */ dag->lifetime = (1UL << (instance->dio_intmin + instance->dio_intdoubl)) * RPL_DAG_LIFETIME / 1000; PRINTF("Set dag "); PRINT6ADDR(&dag->dag_id); PRINTF(" lifetime to %ld\n", dag->lifetime); /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ rpl_update_dag(instance, dag, dio); p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { /* 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"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { 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++; } } } p->rank = dio->rank; /* Parent info has been updated, trigger rank recalculation */ p->flags |= RPL_PARENT_FLAG_UPDATED; PRINTF("RPL: preferred DAG "); 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, -1/*p->mc.obj.etx*/, rpl_get_nbr(p)->link_metric, instance->mc.obj.etx); /* We have allocated a candidate parent; process the DIO further. */ #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } /* 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); } /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ uip_ds6_defrt_add(from, RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime)); } p->dtsn = dio->dtsn; }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; if(dio->mop != RPL_MOP_DEFAULT) { PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); if(dag != NULL && instance != NULL) { if(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; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); } else { PRINTF("RPL: Global Repair\n"); if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } global_repair(from, dag, dio); } return; } if(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); return; } } } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(dag == NULL) { PRINTF("RPL: Adding new DAG to known instance.\n"); rpl_add_dag(from, dio); return; } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } /* Prefix Information Option treated to add new prefix */ if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } #if !WITH_ORPL return; /* With ORPL we want to have neighbors in the "rpl_parents" table as we need their rank and ackcount for routing set. */ #endif } /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { /* 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"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { 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; } } #if WITH_ORPL if(dag->rank == ROOT_RANK(instance)) { /* We have added the parent, now return if we are root */ return; } #endif PRINTF("RPL: preferred DAG "); 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, -1/*p->mc.obj.etx*/, p->link_metric, instance->mc.obj.etx); /* We have allocated a candidate parent; process the DIO further. */ #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } /* 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); } /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); } p->dtsn = dio->dtsn; }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; anycast_update_neighbor_edc(packetbuf_addr(PACKETBUF_ADDR_SENDER), dio->rank); if(dio->mop != RPL_MOP_DEFAULT) { PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); if(dag != NULL && instance != NULL) { if(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; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); } else { global_repair(from, dag, dio); } return; } if(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); return; } } } if(dio->rank == INFINITE_RANK) { PRINTF("RPL: Ignoring DIO from node with infinite rank: "); PRINT6ADDR(from); PRINTF("\n"); return; } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(dag == NULL) { PRINTF("RPL: Adding new DAG to known instance.\n"); rpl_add_dag(from, dio); return; } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } return; } /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS_PER_DAG) { /* 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"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { 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: preferred DAG "); 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)); if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } /* 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; }
/*---------------------------------------------------------------------------*/ void rpl_add_dag(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_dag(dio->instance_id, &dio->dag_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG object!\n"); return; } instance = dag->instance; previous_dag = 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 incompatible with previous DIO\n", dio->instance_id); rpl_remove_parent(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)); rpl_set_preferred_parent(dag, 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 ", 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]); if(dag->rank != ROOT_RANK(instance)) { rpl_process_parent_event(instance, p); } p->dtsn = dio->dtsn; }
void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_dag_t *dag; rpl_parent_t *p; if(dio->mop != RPL_MOP_DEFAULT) { PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } // LVD 24/03/2011 instanceID = dio->instance_id; dag = rpl_get_dag(dio->instance_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"); } 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)) { PRINTF("RPL: Root received inconsistent DIO version number\n"); dag->version = dio->version + 1; rpl_reset_dio_timer(dag, 1); } 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; } if(dio->rank == INFINITE_RANK) { rpl_reset_dio_timer(dag, 1); } else if(dio->rank < ROOT_RANK(dag)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } if(dag->rank == ROOT_RANK(dag)) { if(dio->rank != INFINITE_RANK) { dag->dio_counter++; } return; } /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ 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 ("); PRINT6ADDR(from); PRINTF(")\n"); return; } 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++; } /* 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. */ return; } if(should_send_dao(dag, dio, p)) { rpl_schedule_dao(dag); } p->dtsn = dio->dtsn; }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio, int mobility) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p, *previous_preferred; uint32_t current_t; PRINTF("processing DIO from %u\n", from->u8[15]); if(dio->mop != RPL_MOP_DEFAULT) { PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); previous_preferred = dag->preferred_parent; if(dag != NULL && instance != NULL) { if(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; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); } else { PRINTF("RPL: Global Repair\n"); if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } global_repair(from, dag, dio); } return; } if(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); return; } } } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(instance->current_dag->rank == ROOT_RANK(instance) && instance->current_dag != dag) { PRINTF("RPL: Root ignored DIO for different DAG\n"); return; } if(dag == NULL) { PRINTF("RPL: Adding new DAG to known instance.\n"); rpl_add_dag(from, dio); return; } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } /* Prefix Information Option treated to add new prefix */ if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } return; } /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { /* 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"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { 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: preferred DAG "); 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, -1 /*p->mc.obj.etx */, p->link_metric, instance->mc.obj.etx); /* * If the DIO being processed came from smart-HOP decision, change default route, * schedule DAO and finish the mobility process. */ if(mobility) { rpl_remove_parent(previous_preferred); rpl_set_preferred_parent(dag, p); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); /*dao_output(p, 255);*/ /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ PRINTF("adding default route\n"); current_t = clock_time() * 1000 / CLOCK_SECOND; printf("End %u\n", current_t); rpl_set_default_route(instance, from); rpl_schedule_dao(instance); /*check_dao_ack = 1;*/ process_post(&tcpip_process, RESET_MOBILITY_FLAG, NULL); return; } if(mobility == 0) { #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } } /* 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); } /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); } p->dtsn = dio->dtsn; }