void rpl_global_repair(rpl_dodag_t *dodag, ipv6_addr_t *p_addr, uint16_t rank) { puts("[INFO] Global repair started"); rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { printf("[Error] - no global repair possible, if not part of a DODAG\n"); return; } rpl_delete_all_parents(); my_dodag->version = dodag->version; my_dodag->dtsn++; my_dodag->my_preferred_parent = rpl_new_parent(my_dodag, p_addr, rank); if (my_dodag->my_preferred_parent == NULL) { printf("[Error] no more parent after global repair\n"); my_dodag->my_rank = INFINITE_RANK; } else { /* Calc new Rank */ my_dodag->my_rank = my_dodag->of->calc_rank(my_dodag->my_preferred_parent, my_dodag->my_rank); my_dodag->min_rank = my_dodag->my_rank; reset_trickletimer(); delay_dao(); } printf("Migrated to DODAG Version %d. My new Rank: %d\n", my_dodag->version, my_dodag->my_rank); }
void rpl_parent_update(rpl_parent_t *parent) { rpl_dodag_t *my_dodag = rpl_get_my_dodag(); uint16_t old_rank; if (my_dodag == NULL) { DEBUG("Not part of a dodag - this should not happen"); return; } old_rank = my_dodag->my_rank; /* update Parent lifetime */ if (parent != NULL) { parent->lifetime = my_dodag->default_lifetime * my_dodag->lifetime_unit; } if (rpl_find_preferred_parent() == NULL) { rpl_local_repair(); } if (rpl_calc_rank(old_rank, my_dodag->minhoprankincrease) != rpl_calc_rank(my_dodag->my_rank, my_dodag->minhoprankincrease)) { if (my_dodag->my_rank < my_dodag->min_rank) { my_dodag->min_rank = my_dodag->my_rank; } reset_trickletimer(); } }
rpl_parent_t *rpl_find_preferred_parent(void) { rpl_parent_t *best = NULL; rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { DEBUG("Not part of a dodag\n"); return NULL; } for (uint8_t i = 0; i < RPL_MAX_PARENTS; i++) { if (parents[i].used) { if ((parents[i].rank == INFINITE_RANK) || (parents[i].lifetime <= 1)) { DEBUG("Infinite rank, bad parent\n"); continue; } else if (best == NULL) { DEBUG("possible parent\n"); best = &parents[i]; } else { best = my_dodag->of->which_parent(best, &parents[i]); } } } if (best == NULL) { return NULL; } if (my_dodag->my_preferred_parent == NULL) { my_dodag->my_preferred_parent = best; } if (!rpl_equal_id(&my_dodag->my_preferred_parent->addr, &best->addr)) { if (my_dodag->mop != NO_DOWNWARD_ROUTES) { /* send DAO with ZERO_LIFETIME to old parent */ send_DAO(&my_dodag->my_preferred_parent->addr, 0, false, 0); } my_dodag->my_preferred_parent = best; if (my_dodag->mop != NO_DOWNWARD_ROUTES) { delay_dao(); } reset_trickletimer(); } return best; }
void rpl_local_repair(void) { puts("[INFO] Local Repair started"); rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { printf("[Error] - no local repair possible, if not part of a DODAG\n"); return; } my_dodag->my_rank = INFINITE_RANK; my_dodag->dtsn++; rpl_delete_all_parents(); reset_trickletimer(); }
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; }