void rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr) { rpl_dag_t *dag; rpl_parent_t *p; /* This only handles one DODAG - if multiple we need to check all */ dag = rpl_get_dag(RPL_ANY_INSTANCE); if(dag == NULL) { return; } /* if this is our default route then clean the dag->def_route state */ if(dag->def_route != NULL && uip_ipaddr_cmp(&dag->def_route->ipaddr, &nbr->ipaddr)) { dag->def_route = NULL; } if(!nbr->isused) { PRINTF("RPL: Removing neighbor "); PRINT6ADDR(&nbr->ipaddr); PRINTF("\n"); p = rpl_find_parent(dag, &nbr->ipaddr); if(p != NULL) { p->rank = INFINITE_RANK; /* Trigger DAG rank recalculation. */ p->updated = 1; } } }
static void rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx) { uip_ipaddr_t ipaddr; rpl_dag_t *dag; rpl_parent_t *parent; uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0); uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr); PRINTF("RPL: Neighbor "); PRINT6ADDR(&ipaddr); PRINTF(" is %sknown. ETX = %u\n", known ? "" : "no longer ", NEIGHBOR_INFO_FIX2ETX(etx)); dag = rpl_get_dag(RPL_DEFAULT_INSTANCE); if(dag == NULL) { return; } parent = rpl_find_parent(dag, &ipaddr); if(parent == NULL) { if(!known) { PRINTF("RPL: Deleting routes installed by DAOs received from "); PRINT6ADDR(&ipaddr); PRINTF("\n"); uip_ds6_route_rm_by_nexthop(&ipaddr); } return; } /* Trigger DAG rank recalculation. */ parent->updated = 1; parent->link_metric = etx; if(dag->of->parent_state_callback != NULL) { dag->of->parent_state_callback(parent, known, etx); } if(!known) { PRINTF("RPL: Removing parent "); PRINT6ADDR(&parent->addr); PRINTF(" because of bad connectivity (ETX %d)\n", etx); parent->rank = INFINITE_RANK; } }
/*---------------------------------------------------------------------------*/ int rpl_update_header_final(uip_ipaddr_t *addr) { rpl_parent_t *parent; int uip_ext_opt_offset; int last_uip_ext_len; last_uip_ext_len = uip_ext_len; uip_ext_len = 0; uip_ext_opt_offset = 2; if(UIP_IP_BUF->proto == UIP_PROTO_HBHO) { if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) { PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n"); uip_ext_len = last_uip_ext_len; return 0; } if(UIP_EXT_HDR_OPT_BUF->type == UIP_EXT_HDR_OPT_RPL) { if(UIP_EXT_HDR_OPT_RPL_BUF->senderrank == 0) { PRINTF("RPL: Updating RPL option\n"); if(default_instance == NULL || !default_instance->used || !default_instance->current_dag->joined) { PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect default instance\n"); return 1; } parent = rpl_find_parent(default_instance->current_dag, addr); if(parent == NULL || parent != parent->dag->preferred_parent) { UIP_EXT_HDR_OPT_RPL_BUF->flags = RPL_HDR_OPT_DOWN; } UIP_EXT_HDR_OPT_RPL_BUF->instance = default_instance->instance_id; UIP_EXT_HDR_OPT_RPL_BUF->senderrank = default_instance->current_dag->rank; uip_ext_len = last_uip_ext_len; } } } return 0; }
void rpl_recv_DIO(void) { ipv6_buf = get_rpl_ipv6_buf(); rpl_dio_buf = get_rpl_dio_buf(); DEBUGF("instance %04X ", rpl_dio_buf->rpl_instanceid); DEBUGF("rank %04X\n", byteorder_ntohs(rpl_dio_buf->rank)); int len = DIO_BASE_LEN; rpl_instance_t *dio_inst = rpl_get_instance(rpl_dio_buf->rpl_instanceid); rpl_instance_t *my_inst = rpl_get_my_instance(); if (dio_inst == NULL) { if (my_inst != NULL) { /* already part of a DODAG -> impossible to join other instance */ DEBUGF("Not joining another DODAG!\n"); return; } dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid); if (dio_inst == NULL) { DEBUGF("Failed to create a new RPL instance!\n"); return; } } else if (my_inst == NULL) { DEBUGF("Not joined an instance yet\n"); } else if (my_inst->id != dio_inst->id) { /* TODO: Add support support for several instances. */ /* At the moment, nodes can only join one instance, this is * the instance they join first. * Instances cannot be switched later on. */ DEBUGF("Ignoring instance - we are %d and got %d\n", my_inst->id, dio_inst->id); return; } rpl_dodag_t dio_dodag; memset(&dio_dodag, 0, sizeof(dio_dodag)); memcpy(&dio_dodag.dodag_id, &rpl_dio_buf->dodagid, sizeof(dio_dodag.dodag_id)); dio_dodag.dtsn = rpl_dio_buf->dtsn; dio_dodag.mop = ((rpl_dio_buf->g_mop_prf >> RPL_MOP_SHIFT) & RPL_SHIFTED_MOP_MASK); dio_dodag.grounded = rpl_dio_buf->g_mop_prf >> RPL_GROUNDED_SHIFT; dio_dodag.prf = (rpl_dio_buf->g_mop_prf & RPL_PRF_MASK); dio_dodag.version = rpl_dio_buf->version_number; dio_dodag.instance = dio_inst; uint8_t has_dodag_conf_opt = 0; /* Parse until all options are consumed. * ipv6_buf->length contains the packet length minus ipv6 and * icmpv6 header, so only ICMPV6_HDR_LEN remains to be * subtracted. */ while (len < (NTOHS(ipv6_buf->length) - ICMPV6_HDR_LEN)) { DEBUGF("parsing DIO options\n"); rpl_opt_buf = get_rpl_opt_buf(len); switch (rpl_opt_buf->type) { case (RPL_OPT_PAD1): { len += 1; break; } case (RPL_OPT_PADN): { len += rpl_opt_buf->length; break; } case (RPL_OPT_DAG_METRIC_CONTAINER): { len += rpl_opt_buf->length; break; } case (RPL_OPT_ROUTE_INFO): { len += rpl_opt_buf->length; break; } case (RPL_OPT_DODAG_CONF): { has_dodag_conf_opt = 1; if (rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) { DEBUGF("DODAG configuration is malformed.\n"); /* error malformed */ return; } rpl_opt_dodag_conf_buf = get_rpl_opt_dodag_conf_buf(len); dio_dodag.dio_interval_doubling = rpl_opt_dodag_conf_buf->DIOIntDoubl; dio_dodag.dio_min = rpl_opt_dodag_conf_buf->DIOIntMin; dio_dodag.dio_redundancy = rpl_opt_dodag_conf_buf->DIORedun; dio_dodag.maxrankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MaxRankIncrease); dio_dodag.minhoprankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MinHopRankIncrease); dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime; dio_dodag.lifetime_unit = byteorder_ntohs(rpl_opt_dodag_conf_buf->lifetime_unit); dio_dodag.of = (struct rpl_of_t *) rpl_get_of_for_ocp(byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp)); if (dio_dodag.of == NULL) { DEBUGF("[Error] OCP from DIO is not supported! ocp: %x\n", byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp)); return; } len += RPL_OPT_DODAG_CONF_LEN_WITH_OPT_LEN; break; } case (RPL_OPT_PREFIX_INFO): { if (rpl_opt_buf->length != RPL_OPT_PREFIX_INFO_LEN) { /* error malformed */ return; } rpl_opt_prefix_information_buf = get_rpl_opt_prefix_information_buf(len); /* autonomous address-configuration flag */ if (rpl_opt_prefix_information_buf->flags & (1 << 6)) { ipv6_addr_t tmp; tmp = rpl_opt_prefix_information_buf->prefix; if (!ipv6_addr_is_link_local(&tmp)) { if (byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime) <= byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime)) { ipv6_addr_set_by_eui64(&tmp, rpl_if_id, &tmp); ipv6_net_if_add_addr(rpl_if_id, &tmp, NDP_ADDR_STATE_PREFERRED, byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime), byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime), 0); dio_dodag.prefix = rpl_opt_prefix_information_buf->prefix; dio_dodag.prefix_length = rpl_opt_prefix_information_buf->prefix_length; dio_dodag.prefix_valid_lifetime = byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime); dio_dodag.prefix_preferred_lifetime = byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime); dio_dodag.prefix_flags = rpl_opt_prefix_information_buf->flags; } } } len += RPL_OPT_PREFIX_INFO_LEN_WITH_OPT_LEN; break; } default: DEBUGF("[Error] Unsupported DIO option\n"); return; } } /* handle packet content... */ rpl_dodag_t *my_dodag = rpl_get_joined_dodag(dio_inst->id); if (my_dodag == NULL) { if (!has_dodag_conf_opt) { DEBUGF("send DIS\n"); rpl_send_DIS(&ipv6_buf->srcaddr); } if (byteorder_ntohs(rpl_dio_buf->rank) < ROOT_RANK) { DEBUGF("DIO with Rank < ROOT_RANK\n"); } if (dio_dodag.mop != RPL_DEFAULT_MOP) { DEBUGF("Required MOP not supported\n"); } if (dio_dodag.of == NULL) { DEBUGF("Required objective function not supported\n"); } if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) { DEBUGF("Will join DODAG\n"); rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank)); } else { DEBUGF("Cannot access DODAG because of DIO with infinite rank\n"); } return; } if (rpl_equal_id(&my_dodag->dodag_id, &dio_dodag.dodag_id)) { /* "our" DODAG */ if (RPL_COUNTER_GREATER_THAN(dio_dodag.version, my_dodag->version)) { if (my_dodag->my_rank == ROOT_RANK) { DEBUGF("[Warning] Inconsistent Dodag Version\n"); my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version); trickle_reset_timer(&my_dodag->trickle); } else { DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n"); my_dodag->version = dio_dodag.version; rpl_global_repair(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank)); } return; } else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) { /* lower version number detected -> send more DIOs */ trickle_reset_timer(&my_dodag->trickle); return; } } /* version matches, DODAG matches */ if (byteorder_ntohs(rpl_dio_buf->rank) == INFINITE_RANK) { trickle_reset_timer(&my_dodag->trickle); } /* We are root, all done!*/ if (my_dodag->my_rank == ROOT_RANK) { if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) { trickle_increment_counter(&my_dodag->trickle); } return; } /********************* Parent Handling *********************/ rpl_parent_t *parent; parent = rpl_find_parent(my_dodag, &ipv6_buf->srcaddr); if (parent == NULL) { /* add new parent candidate */ parent = rpl_new_parent(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank)); if (parent == NULL) { return; } } else { /* DIO OK */ trickle_increment_counter(&my_dodag->trickle); } /* update parent rank */ parent->rank = byteorder_ntohs(rpl_dio_buf->rank); rpl_parent_update(my_dodag, parent); if (my_dodag->my_preferred_parent == NULL) { DEBUGF("My dodag has no preferred_parent yet - seems to be odd since I have a parent...\n"); } else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && (parent->dtsn != rpl_dio_buf->dtsn)) { rpl_delay_dao(my_dodag); } parent->dtsn = rpl_dio_buf->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 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; }
/*---------------------------------------------------------------------------*/ rpl_dag_t * 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 NULL; } 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 NULL; } PRINTF("succeeded\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { rpl_move_parent(previous_dag, dag, p); } } p->rank = dio->rank; /* 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 NULL; } 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]); rpl_process_parent_event(instance, p); p->dtsn = dio->dtsn; 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(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_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 recv_rpl_dio(void) { ipv6_buf = get_rpl_ipv6_buf(); rpl_dio_buf = get_rpl_dio_buf(); int len = DIO_BASE_LEN; rpl_instance_t *dio_inst = rpl_get_instance(rpl_dio_buf->rpl_instanceid); rpl_instance_t *my_inst = rpl_get_my_instance(); if (dio_inst == NULL) { if (my_inst != NULL) { /* already part of a DODAG -> impossible to join other instance */ return; } dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid); if (dio_inst == NULL) { return; } } else if (my_inst->id != dio_inst->id) { /* TODO: Add support support for several instances. */ /* At the moment, nodes can only join one instance, this is * the instance they join first. * Instances cannot be switched later on. */ DEBUG("Ignoring instance - we are %d and got %d\n", my_inst->id, dio_inst->id); return; } rpl_dodag_t dio_dodag; memset(&dio_dodag, 0, sizeof(dio_dodag)); memcpy(&dio_dodag.dodag_id, &rpl_dio_buf->dodagid, sizeof(dio_dodag.dodag_id)); dio_dodag.dtsn = rpl_dio_buf->dtsn; dio_dodag.mop = ((rpl_dio_buf->g_mop_prf >> RPL_MOP_SHIFT) & RPL_SHIFTED_MOP_MASK); dio_dodag.grounded = rpl_dio_buf->g_mop_prf >> RPL_GROUNDED_SHIFT; dio_dodag.prf = (rpl_dio_buf->g_mop_prf & RPL_PRF_MASK); dio_dodag.version = rpl_dio_buf->version_number; dio_dodag.instance = dio_inst; uint8_t has_dodag_conf_opt = 0; /* Parse until all options are consumed. * ipv6_buf->length contains the packet length minus ipv6 and * icmpv6 header, so only ICMPV6_HDR_LEN remains to be * subtracted. */ while (len < (ipv6_buf->length - ICMPV6_HDR_LEN)) { rpl_opt_buf = get_rpl_opt_buf(len); switch (rpl_opt_buf->type) { case (RPL_OPT_PAD1): { len += 1; break; } case (RPL_OPT_PADN): { len += rpl_opt_buf->length + 2; break; } case (RPL_OPT_DAG_METRIC_CONTAINER): { len += rpl_opt_buf->length + 2; break; } case (RPL_OPT_ROUTE_INFO): { len += rpl_opt_buf->length + 2; break; } case (RPL_OPT_DODAG_CONF): { has_dodag_conf_opt = 1; if (rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) { /* error malformed */ return; } rpl_opt_dodag_conf_buf = get_rpl_opt_dodag_conf_buf(len); dio_dodag.dio_interval_doubling = rpl_opt_dodag_conf_buf->DIOIntDoubl; dio_dodag.dio_min = rpl_opt_dodag_conf_buf->DIOIntMin; dio_dodag.dio_redundancy = rpl_opt_dodag_conf_buf->DIORedun; dio_dodag.maxrankincrease = rpl_opt_dodag_conf_buf->MaxRankIncrease; dio_dodag.minhoprankincrease = rpl_opt_dodag_conf_buf->MinHopRankIncrease; dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime; dio_dodag.lifetime_unit = rpl_opt_dodag_conf_buf->lifetime_unit; dio_dodag.of = (struct rpl_of_t *) rpl_get_of_for_ocp(rpl_opt_dodag_conf_buf->ocp); len += RPL_OPT_DODAG_CONF_LEN + 2; break; } case (RPL_OPT_PREFIX_INFO): { if (rpl_opt_buf->length != RPL_OPT_PREFIX_INFO_LEN) { /* error malformed */ return; } len += RPL_OPT_PREFIX_INFO_LEN + 2; break; } default: DEBUG("[Error] Unsupported DIO option\n"); return; } } /* handle packet content... */ rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { if (!has_dodag_conf_opt) { DEBUG("send DIS\n"); send_DIS(&ipv6_buf->srcaddr); return; } if (rpl_dio_buf->rank < ROOT_RANK) { DEBUG("DIO with Rank < ROOT_RANK\n"); return; } if (dio_dodag.mop != RPL_DEFAULT_MOP) { DEBUG("Required MOP not supported\n"); return; } if (dio_dodag.of == NULL) { DEBUG("Required objective function not supported\n"); return; } if (rpl_dio_buf->rank != INFINITE_RANK) { char addr_str[IPV6_MAX_ADDR_STR_LEN]; DEBUG("Will join DODAG\n"); printf("%s", ipv6_addr_to_str(addr_str, &dio_dodag.dodag_id)); rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank); } else { DEBUG("Cannot access DODAG because of DIO with infinite rank\n"); return; } } if (rpl_equal_id(&my_dodag->dodag_id, &dio_dodag.dodag_id)) { /* "our" DODAG */ if (RPL_COUNTER_GREATER_THAN(dio_dodag.version, my_dodag->version)) { if (my_dodag->my_rank == ROOT_RANK) { DEBUG("[Warning] Inconsistent Dodag Version\n"); my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version); reset_trickletimer(); } else { DEBUG("[Info] New Version of dodag %d\n", dio_dodag.version); rpl_global_repair(&dio_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank); } return; } else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) { /* ein Knoten hat noch eine kleinere Versionsnummer -> mehr DIOs senden */ reset_trickletimer(); return; } } /* version matches, DODAG matches */ if (rpl_dio_buf->rank == INFINITE_RANK) { reset_trickletimer(); } /* We are root, all done! */ if (my_dodag->my_rank == ROOT_RANK) { if (rpl_dio_buf->rank != INFINITE_RANK) { trickle_increment_counter(); } return; } /********************* Parent Handling *********************/ rpl_parent_t *parent; parent = rpl_find_parent(&ipv6_buf->srcaddr); if (parent == NULL) { /* add new parent candidate */ parent = rpl_new_parent(my_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank); if (parent == NULL) { return; } } else { /* DIO OK */ trickle_increment_counter(); } /* update parent rank */ parent->rank = rpl_dio_buf->rank; rpl_parent_update(parent); if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && (parent->dtsn != rpl_dio_buf->dtsn)) { delay_dao(); } parent->dtsn = rpl_dio_buf->dtsn; }
void recv_rpl_dio(void) { ipv6_buf = get_rpl_ipv6_buf(); rpl_dio_buf = get_rpl_dio_buf(); int len = DIO_BASE_LEN; rpl_instance_t *dio_inst = rpl_get_instance(rpl_dio_buf->rpl_instanceid); rpl_instance_t *my_inst = rpl_get_my_instance(); if(dio_inst == NULL) { if(my_inst != NULL) { /* Dieser Knoten ist schon Teil eines DODAGS -> kein beitritt zu anderer Instanz moeglich */ return; } dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid); if(dio_inst == NULL) { return; } } else if(my_inst->id != dio_inst->id) { printf("Andere Instanz, wir haben %d es kam aber %d\n", my_inst->id, dio_inst->id); /* DIO von fremder Instanz ignorieren, Knoten können Momentan nur * einer Instanz beitreten und das wird die Instanz sein, der sie als * erstes beitreten. Danach kann die Instanz nicht mehr gewechselt * werden Unterstützung für mehrere Instanzen könnte in Zukunft * implementiert werden */ return; } rpl_dodag_t dio_dodag; memset(&dio_dodag, 0, sizeof(dio_dodag)); memcpy(&dio_dodag.dodag_id, &rpl_dio_buf->dodagid, sizeof(dio_dodag.dodag_id)); dio_dodag.dtsn = rpl_dio_buf->dtsn; dio_dodag.mop = ((rpl_dio_buf->g_mop_prf >> RPL_MOP_SHIFT) & RPL_SHIFTED_MOP_MASK); dio_dodag.grounded = rpl_dio_buf->g_mop_prf >> RPL_GROUNDED_SHIFT; dio_dodag.prf = (rpl_dio_buf->g_mop_prf & RPL_PRF_MASK); dio_dodag.version = rpl_dio_buf->version_number; dio_dodag.instance = dio_inst; uint8_t has_dodag_conf_opt = 0; /* So lange das Paket größer ist, als die DIO Größe + Größe der bisher * verarbeiteten Optionen, sind noch weitere Optionen zu bearbeiten */ /* dabei müssen wir jedoch von der ipv6_buf->length die Größe des ICMP * Headers abziehen weil get_rpl_opt_buf die Paketlänge OHNE ipv6 und * icmpv6 header übergeben werden muss in ipv6_buf->length ist die * IPV6_HDR_LEN nicht enthalten, also muss nur noch die ICMPV6_HDR_LEN * abgezogen werden */ while(len < (ipv6_buf->length - ICMPV6_HDR_LEN)) { rpl_opt_buf = get_rpl_opt_buf(len); switch(rpl_opt_buf->type) { case(RPL_OPT_PAD1): { len += 1; break; } case(RPL_OPT_PADN): { len += rpl_opt_buf->length + 2; break; } case(RPL_OPT_DAG_METRIC_CONTAINER): { len += rpl_opt_buf->length + 2; break; } case(RPL_OPT_ROUTE_INFO): { len += rpl_opt_buf->length + 2; break; } case(RPL_OPT_DODAG_CONF): { has_dodag_conf_opt = 1; if(rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) { /* error malformed */ return; } rpl_opt_dodag_conf_buf = get_rpl_opt_dodag_conf_buf(len); dio_dodag.dio_interval_doubling = rpl_opt_dodag_conf_buf->DIOIntDoubl; dio_dodag.dio_min = rpl_opt_dodag_conf_buf->DIOIntMin; dio_dodag.dio_redundancy = rpl_opt_dodag_conf_buf->DIORedun; dio_dodag.maxrankincrease = rpl_opt_dodag_conf_buf->MaxRankIncrease; dio_dodag.minhoprankincrease = rpl_opt_dodag_conf_buf->MinHopRankIncrease; dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime; dio_dodag.lifetime_unit = rpl_opt_dodag_conf_buf->lifetime_unit; dio_dodag.of = rpl_get_of_for_ocp(rpl_opt_dodag_conf_buf->ocp); len += RPL_OPT_DODAG_CONF_LEN + 2; break; } case(RPL_OPT_PREFIX_INFO): { if(rpl_opt_buf->length != RPL_OPT_PREFIX_INFO_LEN) { /* error malformed */ return; } len += RPL_OPT_PREFIX_INFO_LEN + 2; break; } default: printf("[Error] Unsupported DIO option\n"); return; } } /* handle packet content... */ rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if(my_dodag == NULL) { if(!has_dodag_conf_opt) { puts("send DIS"); send_DIS(&ipv6_buf->srcaddr); return; } if(rpl_dio_buf->rank < ROOT_RANK) { printf("DIO with Rank < ROOT_RANK\n"); return; } if(dio_dodag.mop != RPL_DEFAULT_MOP) { printf("Required MOP not supported\n"); return; } if(dio_dodag.of == NULL) { printf("Required objective function not supported\n"); return; } if(rpl_dio_buf->rank != INFINITE_RANK) { puts("Will join DODAG\n"); ipv6_print_addr(&dio_dodag.dodag_id); rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank); } else { printf("Cannot access DODAG because of DIO with infinite rank\n"); return; } } if(rpl_equal_id(&my_dodag->dodag_id, &dio_dodag.dodag_id)) { /* Mein DODAG */ if(RPL_COUNTER_GREATER_THAN(dio_dodag.version, my_dodag->version)) { if(my_dodag->my_rank == ROOT_RANK) { /* Jemand hat ein DIO mit einer höheren Version als der richtigen gesendet */ /* Wir erhöhen diese Version noch einmal, und machen sie zur neuen */ printf("[Warning] Inconsistent Dodag Version\n"); my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version); reset_trickletimer(); } else { printf("[Info] New Version of dodag %d\n", dio_dodag.version); rpl_global_repair(&dio_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank); } return; } else if(RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) { /* ein Knoten hat noch eine kleinere Versionsnummer -> mehr DIOs senden */ reset_trickletimer(); return; } } /* Version stimmt, DODAG stimmt */ if(rpl_dio_buf->rank == INFINITE_RANK) { reset_trickletimer(); } /* Wenn wir root sind, ist nichts weiter zu tun */ if(my_dodag->my_rank == ROOT_RANK) { if(rpl_dio_buf->rank != INFINITE_RANK) { trickle_increment_counter(); } return; } /* */ /* Parent Handling */ /* */ /* Ist Knoten bereits Parent? */ rpl_parent_t *parent; parent = rpl_find_parent(&ipv6_buf->srcaddr); if(parent == NULL) { /* neuen möglichen Elternknoten hinzufuegen */ parent = rpl_new_parent(my_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank); if(parent == NULL) { return; } } else { /* DIO ok */ trickle_increment_counter(); } /* update parent rank */ parent->rank = rpl_dio_buf->rank; rpl_parent_update(parent); if(rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && (parent->dtsn != rpl_dio_buf->dtsn)) { delay_dao(); } parent->dtsn = rpl_dio_buf->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; }