void rpl_recv_DIS(void) { ipv6_buf = get_rpl_ipv6_buf(); rpl_dis_buf = get_rpl_dis_buf(); int len = DIS_BASE_LEN; rpl_dodag_t *dodag, *end; uint8_t options_missing = 1; while (len < (NTOHS(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; break; } case (RPL_OPT_SOLICITED_INFO): { options_missing = 0; len += RPL_OPT_SOLICITED_INFO_LEN; /* extract and check */ if (rpl_opt_buf->length != RPL_OPT_SOLICITED_INFO_LEN) { /* error malformed */ return; } rpl_opt_solicited_buf = get_rpl_opt_solicited_buf(len); for (dodag = rpl_dodags, end = dodag + RPL_MAX_DODAGS; dodag < end; dodag++) { if (dodag->joined) { if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_I_MASK) { if (dodag->instance->id != rpl_opt_solicited_buf->rplinstanceid) { continue; } } if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_D_MASK) { if (!rpl_equal_id(&dodag->dodag_id, &rpl_opt_solicited_buf->dodagid)) { continue; } } if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_V_MASK) { if (dodag->version != rpl_opt_solicited_buf->version) { continue; } } rpl_send_DIO(dodag, &ipv6_buf->srcaddr); trickle_reset_timer(&dodag->trickle); } } break; } default: return; } } if (options_missing) { for (dodag = rpl_dodags, end = dodag + RPL_MAX_DODAGS; dodag < end; dodag++) { if (dodag->joined) { rpl_send_DIO(dodag, &ipv6_buf->srcaddr); trickle_reset_timer(&dodag->trickle); } } } }
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_recv_DAO(void) { #if RPL_DEFAULT_MOP == RPL_MOP_NON_STORING_MODE if (!i_am_root) { DEBUGF("[Error] something went wrong - got a DAO.\n"); return; } #endif ipv6_buf = get_rpl_ipv6_buf(); rpl_dao_buf = get_rpl_dao_buf(); DEBUG("instance %04X ", rpl_dao_buf->rpl_instanceid); DEBUG("sequence %04X\n", rpl_dao_buf->dao_sequence); rpl_dodag_t *my_dodag = rpl_get_joined_dodag(rpl_dao_buf->rpl_instanceid); if (my_dodag == NULL) { DEBUG("[Error] got DAO although not a DODAG\n"); return; } int len = DAO_BASE_LEN; uint8_t increment_seq = 0; while (len < (NTOHS(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 + RPL_OPT_LEN); break; } case (RPL_OPT_DAG_METRIC_CONTAINER): { len += (rpl_opt_buf->length + RPL_OPT_LEN); break; } case (RPL_OPT_TARGET): { rpl_opt_target_buf = get_rpl_opt_target_buf(len); if (rpl_opt_target_buf->prefix_length != RPL_DODAG_ID_LEN) { DEBUGF("prefixes are not supported yet\n"); break; } len += (rpl_opt_target_buf->length + RPL_OPT_LEN); rpl_opt_transit_buf = get_rpl_opt_transit_buf(len); if (rpl_opt_transit_buf->type != RPL_OPT_TRANSIT) { DEBUGF("[Error] - no transit information for target option type = %d\n", rpl_opt_transit_buf->type); break; } len += (rpl_opt_transit_buf->length + RPL_OPT_LEN); /* route lifetime seconds = (DAO lifetime) * (Unit Lifetime) */ #if (RPL_DEFAULT_MOP == RPL_MOP_NON_STORING_MODE) && (RPL_MAX_ROUTING_ENTRIES != 0) rpl_add_srh_entry(&rpl_opt_target_buf->target, &rpl_opt_transit_buf->parent, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); #elif (RPL_MAX_ROUTING_ENTRIES != 0) DEBUG("Adding routing information: Target: %s, Source: %s, Lifetime: %u\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_opt_target_buf->target), ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_buf->srcaddr), (rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit)); rpl_add_routing_entry(&rpl_opt_target_buf->target, &ipv6_buf->srcaddr, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); #endif increment_seq = 1; break; } case (RPL_OPT_TRANSIT): { len += (rpl_opt_buf->length + RPL_OPT_LEN); break; } case (RPL_OPT_TARGET_DESC): { len += (rpl_opt_buf->length + RPL_OPT_LEN); break; } default: return; } } #if RPL_DEFAULT_MOP != RPL_MOP_NON_STORING_MODE rpl_send_DAO_ACK(my_dodag, &ipv6_buf->srcaddr); #endif if (increment_seq) { RPL_COUNTER_INCREMENT(my_dodag->dao_seq); rpl_delay_dao(my_dodag); } }
void recv_rpl_dis(void) { rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { return; } ipv6_buf = get_rpl_ipv6_buf(); rpl_dis_buf = get_rpl_dis_buf(); int len = DIS_BASE_LEN; 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_SOLICITED_INFO): { len += RPL_OPT_SOLICITED_INFO_LEN + 2; /* extract and check */ if (rpl_opt_buf->length != RPL_OPT_SOLICITED_INFO_LEN) { /* error malformed */ return; } rpl_opt_solicited_buf = get_rpl_opt_solicited_buf(len); if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_I_MASK) { if (my_dodag->instance->id != rpl_opt_solicited_buf->rplinstanceid) { return; } } if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_D_MASK) { if (!rpl_equal_id(&my_dodag->dodag_id, &rpl_opt_solicited_buf->dodagid)) { return; } } if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_V_MASK) { if (my_dodag->version != rpl_opt_solicited_buf->version) { return; } } break; } default: return; } } send_DIO(&ipv6_buf->srcaddr); }
void recv_rpl_dao(void) { rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { DEBUG("[Error] got DAO although not a DODAG\n"); return; } ipv6_buf = get_rpl_ipv6_buf(); rpl_dao_buf = get_rpl_dao_buf(); int len = DAO_BASE_LEN; uint8_t increment_seq = 0; 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_TARGET): { rpl_opt_target_buf = get_rpl_opt_target_buf(len); if (rpl_opt_target_buf->prefix_length != RPL_DODAG_ID_LEN) { DEBUG("prefixes are not supported yet"); break; } len += rpl_opt_target_buf->length + 2; rpl_opt_transit_buf = get_rpl_opt_transit_buf(len); if (rpl_opt_transit_buf->type != RPL_OPT_TRANSIT) { DEBUG("[Error] - no transit information for target option type = %d\n", rpl_opt_transit_buf->type); break; } len += rpl_opt_transit_buf->length + 2; /* route lifetime seconds = (DAO lifetime) * (Unit Lifetime) */ rpl_add_routing_entry(&rpl_opt_target_buf->target, &ipv6_buf->srcaddr, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); increment_seq = 1; break; } case (RPL_OPT_TRANSIT): { len += rpl_opt_buf->length + 2; break; } case (RPL_OPT_TARGET_DESC): { len += rpl_opt_buf->length + 2; break; } default: return; } } send_DAO_ACK(&ipv6_buf->srcaddr); if (increment_seq) { RPL_COUNTER_INCREMENT(my_dodag->dao_seq); delay_dao(); } }
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_dao(void) { rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if(my_dodag == NULL) { printf("[Error] got DAO without beeing part of a Dodag\n"); return; } ipv6_buf = get_rpl_ipv6_buf(); rpl_dao_buf = get_rpl_dao_buf(); int len = DAO_BASE_LEN; uint8_t increment_seq = 0; 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_TARGET): { rpl_opt_target_buf = get_rpl_opt_target_buf(len); if(rpl_opt_target_buf->prefix_length != RPL_DODAG_ID_LEN) { printf("prefixes are not supported yet"); break; } len += rpl_opt_target_buf->length + 2; rpl_opt_transit_buf = get_rpl_opt_transit_buf(len); if(rpl_opt_transit_buf->type != RPL_OPT_TRANSIT) { printf("[Error] - no Transit Inforamtion to Target Option, type = %d\n", rpl_opt_transit_buf->type); break; } len += rpl_opt_transit_buf->length + 2; /* Die eigentliche Lebenszeit einer Route errechnet sich aus (Lifetime aus DAO) * (Lifetime Unit) Sekunden */ rpl_add_routing_entry(&rpl_opt_target_buf->target, &ipv6_buf->srcaddr, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); /* puts("Updated route \n"); */ increment_seq = 1; break; } case(RPL_OPT_TRANSIT): { len += rpl_opt_buf->length + 2; break; } case(RPL_OPT_TARGET_DESC): { len += rpl_opt_buf->length + 2; break; } default: return; } } send_DAO_ACK(&ipv6_buf->srcaddr); if(increment_seq) { RPL_COUNTER_INCREMENT(my_dodag->dao_seq); delay_dao(); } }
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 recv_rpl_dao(void) { DEBUG("%s, %d: Received DAO with ", __FILE__, __LINE__); rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { DEBUG("%s, %d: [Error] got DAO although not a DODAG\n", __FILE__, __LINE__); return; } ipv6_buf = get_rpl_ipv6_buf(); rpl_dao_buf = get_rpl_dao_buf(); DEBUG("instance %04X ", rpl_dao_buf->rpl_instanceid); DEBUG("sequence %04X\n", rpl_dao_buf->dao_sequence); int len = DAO_BASE_LEN; uint8_t increment_seq = 0; while (len < (NTOHS(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_TARGET): { rpl_opt_target_buf = get_rpl_opt_target_buf(len); if (rpl_opt_target_buf->prefix_length != RPL_DODAG_ID_LEN) { DEBUG("%s, %d: prefixes are not supported yet", __FILE__, __LINE__); break; } len += rpl_opt_target_buf->length + 2; rpl_opt_transit_buf = get_rpl_opt_transit_buf(len); if (rpl_opt_transit_buf->type != RPL_OPT_TRANSIT) { DEBUG("%s, %d: [Error] - no transit information for target option type = %d\n", __FILE__, __LINE__, rpl_opt_transit_buf->type); break; } len += rpl_opt_transit_buf->length + 2; /* route lifetime seconds = (DAO lifetime) * (Unit Lifetime) */ DEBUG("%s, %d: Adding routing information: Target: %s, Source: %s, Lifetime: %u\n", __FILE__, __LINE__, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_buf->srcaddr), ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_buf->srcaddr), (rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit)); rpl_add_routing_entry(&rpl_opt_target_buf->target, &ipv6_buf->srcaddr, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); increment_seq = 1; break; } case (RPL_OPT_TRANSIT): { len += rpl_opt_buf->length + 2; break; } case (RPL_OPT_TARGET_DESC): { len += rpl_opt_buf->length + 2; break; } default: return; } } send_DAO_ACK(&ipv6_buf->srcaddr); if (increment_seq) { RPL_COUNTER_INCREMENT(my_dodag->dao_seq); delay_dao(); } }
void rpl_recv_DAO_mode(void) { rpl_dodag_t *my_dodag = rpl_get_my_dodag(); if (my_dodag == NULL) { DEBUGF("[Error] got DAO although not a DODAG.\n"); return; } if (!i_am_root) { DEBUGF("[Error] something went wrong - got a DAO.\n"); return; } ipv6_buf = get_rpl_ipv6_buf(); rpl_dao_buf = get_rpl_dao_buf(); int len = DAO_BASE_LEN; uint8_t increment_seq = 0; while (len < (NTOHS(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; break; } case (RPL_OPT_DAG_METRIC_CONTAINER): { len += rpl_opt_buf->length; break; } case (RPL_OPT_TARGET): { rpl_opt_target_buf = get_rpl_opt_target_buf(len); if (rpl_opt_target_buf->prefix_length != RPL_DODAG_ID_LEN) { DEBUGF("prefixes are not supported yet\n"); break; } len += rpl_opt_target_buf->length; rpl_opt_transit_buf = get_rpl_opt_transit_buf(len); if (rpl_opt_transit_buf->type != RPL_OPT_TRANSIT) { DEBUGF("[Error] - no transit information for target option type = %d\n", rpl_opt_transit_buf->type); break; } len += rpl_opt_transit_buf->length; /* route lifetime seconds = (DAO lifetime) * (Unit Lifetime) */ DEBUGF("Target: %s\n", ipv6_addr_to_str(addr_str_mode, IPV6_MAX_ADDR_STR_LEN, &rpl_opt_target_buf->target)); DEBUGF("Transit: %s\n", ipv6_addr_to_str(addr_str_mode, IPV6_MAX_ADDR_STR_LEN, &rpl_opt_transit_buf->parent)); #if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE rpl_add_srh_entry(&rpl_opt_target_buf->target, &rpl_opt_transit_buf->parent, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); #endif increment_seq = 1; break; } case (RPL_OPT_TRANSIT): { len += rpl_opt_buf->length; break; } case (RPL_OPT_TARGET_DESC): { len += rpl_opt_buf->length; break; } default: return; } } if (increment_seq) { RPL_COUNTER_INCREMENT(my_dodag->dao_seq); delay_dao(); } }