void gnrc_rpl_recv_DIS(gnrc_rpl_dis_t *dis, ipv6_addr_t *src, ipv6_addr_t *dst, uint16_t len) { /* TODO handle Solicited Information Option */ (void) dis; (void) len; if (!_gnrc_rpl_check_DIS_validity(dis, len)) { return; } if (ipv6_addr_is_multicast(dst)) { for (uint8_t i = 0; i < GNRC_RPL_DODAGS_NUMOF; ++i) { if (gnrc_rpl_dodags[i].state != 0) { trickle_reset_timer(&gnrc_rpl_dodags[i].trickle); } } } else { for (uint8_t i = 0; i < GNRC_RPL_DODAGS_NUMOF; ++i) { if (gnrc_rpl_dodags[i].state != 0) { gnrc_rpl_dodags[i].dodag_conf_counter = 0; gnrc_rpl_send_DIO(&gnrc_rpl_dodags[i], src); } } } }
void gnrc_rpl_recv_DIS(gnrc_rpl_dis_t *dis, ipv6_addr_t *src, ipv6_addr_t *dst, uint16_t len) { /* TODO handle Solicited Information Option */ (void) dis; (void) len; if (!_gnrc_rpl_check_DIS_validity(dis, len)) { return; } if (ipv6_addr_is_multicast(dst)) { for (uint8_t i = 0; i < GNRC_RPL_INSTANCES_NUMOF; ++i) { if ((gnrc_rpl_instances[i].state != 0) /* a leaf node should only react to unicast DIS */ && (gnrc_rpl_instances[i].dodag.node_status != GNRC_RPL_LEAF_NODE)) { trickle_reset_timer(&(gnrc_rpl_instances[i].dodag.trickle)); } } } else { for (uint8_t i = 0; i < GNRC_RPL_INSTANCES_NUMOF; ++i) { if (gnrc_rpl_instances[i].state != 0) { gnrc_rpl_instances[i].dodag.dodag_conf_requested = true; gnrc_rpl_instances[i].dodag.prefix_info_requested = true; gnrc_rpl_send_DIO(&gnrc_rpl_instances[i], src); } } } }
void gnrc_rpl_recv_DIS(gnrc_rpl_dis_t *dis, kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst, uint16_t len) { /* TODO handle Solicited Information Option */ (void)iface; if (!_gnrc_rpl_check_DIS_validity(dis, len)) { return; } if (ipv6_addr_is_multicast(dst)) { for (uint8_t i = 0; i < GNRC_RPL_INSTANCES_NUMOF; ++i) { if ((gnrc_rpl_instances[i].state != 0) /* a leaf node should only react to unicast DIS */ && (gnrc_rpl_instances[i].dodag.node_status != GNRC_RPL_LEAF_NODE)) { #ifdef MODULE_GNRC_RPL_P2P if (gnrc_rpl_instances[i].mop == GNRC_RPL_P2P_MOP) { DEBUG("RPL: Not responding to DIS for P2P-RPL DODAG\n"); continue; } #endif trickle_reset_timer(&(gnrc_rpl_instances[i].dodag.trickle)); } } } else { for (uint8_t i = 0; i < GNRC_RPL_INSTANCES_NUMOF; ++i) { if (gnrc_rpl_instances[i].state != 0) { gnrc_rpl_instances[i].dodag.dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; gnrc_rpl_send_DIO(&gnrc_rpl_instances[i], src); } } } }
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; }
/* RFC 6206 Rule 6 */ void trickle_inconsistent_heard(trickle_t *t, const trickle_params_t *params) { if (t->I != params->Imin || !trickle_running(t, params)) { trickle_reset_timer(t, params); } }