diff --git a/sys/include/net/gnrc/rpl/structs.h b/sys/include/net/gnrc/rpl/structs.h index 165832e536..87e7e3d7c8 100644 --- a/sys/include/net/gnrc/rpl/structs.h +++ b/sys/include/net/gnrc/rpl/structs.h @@ -235,7 +235,8 @@ struct gnrc_rpl_dodag { uint8_t dao_seq; /**< dao sequence number */ uint8_t dao_counter; /**< amount of retried DAOs */ bool dao_ack_received; /**< flag to check for DAO-ACK */ - uint8_t dodag_conf_counter; /**< limitation of the sending of DODAG_CONF options */ + bool dodag_conf_requested; /**< flag to send DODAG_CONF options */ + bool prefix_info_requested; /**< flag to send PREFIX_INFO options */ msg_t dao_msg; /**< msg_t for firing a dao */ uint64_t dao_time; /**< time to schedule the next DAO */ xtimer_t dao_timer; /**< timer to schedule the next DAO */ diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl.c b/sys/net/gnrc/routing/rpl/gnrc_rpl.c index cc38b578ce..144ff8e5a4 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl.c @@ -94,6 +94,8 @@ gnrc_rpl_dodag_t *gnrc_rpl_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id) dodag->grounded = GNRC_RPL_GROUNDED; dodag->node_status = GNRC_RPL_ROOT_NODE; dodag->my_rank = GNRC_RPL_ROOT_RANK; + dodag->dodag_conf_requested = true; + dodag->prefix_info_requested = true; trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_INTERVAL, GNRC_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c index 69cf04ce86..89bb36a9df 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c @@ -101,8 +101,11 @@ void gnrc_rpl_send_DIO(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination) uint8_t *pos; int size = sizeof(icmpv6_hdr_t) + sizeof(gnrc_rpl_dio_t); - if ((dodag->dodag_conf_counter % 3) == 0) { + if (dodag->dodag_conf_requested) { size += sizeof(gnrc_rpl_opt_dodag_conf_t); + } + + if (dodag->prefix_info_requested) { size += sizeof(gnrc_rpl_opt_prefix_info_t); } @@ -126,7 +129,7 @@ void gnrc_rpl_send_DIO(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination) pos += sizeof(*dio); - if ((dodag->dodag_conf_counter % 3) == 0) { + if (dodag->dodag_conf_requested) { gnrc_rpl_opt_dodag_conf_t *dodag_conf; dodag_conf = (gnrc_rpl_opt_dodag_conf_t *) pos; dodag_conf->type = GNRC_RPL_OPT_DODAG_CONF; @@ -142,7 +145,10 @@ void gnrc_rpl_send_DIO(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination) dodag_conf->default_lifetime = dodag->default_lifetime; dodag_conf->lifetime_unit = byteorder_htons(dodag->lifetime_unit); pos += sizeof(*dodag_conf); + dodag->dodag_conf_requested = false; + } + if (dodag->prefix_info_requested) { gnrc_rpl_opt_prefix_info_t *prefix_info; prefix_info = (gnrc_rpl_opt_prefix_info_t *) pos; prefix_info->type = GNRC_RPL_OPT_PREFIX_INFO; @@ -156,15 +162,14 @@ void gnrc_rpl_send_DIO(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination) memset(&prefix_info->prefix, 0, sizeof(prefix_info->prefix)); ipv6_addr_init_prefix(&prefix_info->prefix, &dodag->dodag_id, dodag->prefix_len); + dodag->prefix_info_requested = false; } - dodag->dodag_conf_counter++; gnrc_rpl_send(pkt, NULL, destination, &dodag->dodag_id); } void gnrc_rpl_send_DIS(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination) { - (void) dodag; gnrc_pktsnip_t *pkt; icmpv6_hdr_t *icmp; gnrc_rpl_dis_t *dis; @@ -227,7 +232,8 @@ void gnrc_rpl_recv_DIS(gnrc_rpl_dis_t *dis, ipv6_addr_t *src, ipv6_addr_t *dst, 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_dodags[i].dodag_conf_requested = true; + gnrc_rpl_dodags[i].prefix_info_requested = true; gnrc_rpl_send_DIO(&gnrc_rpl_dodags[i], src); } } @@ -322,12 +328,13 @@ static bool _gnrc_rpl_check_options_validity(int msg_type, gnrc_rpl_dodag_t *dod /** @todo allow target prefixes in target options to be of variable length */ bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt, uint16_t len, - ipv6_addr_t *src) + ipv6_addr_t *src, uint32_t *included_opts) { uint16_t l = 0; gnrc_rpl_opt_target_t *first_target = NULL; eui64_t iid; kernel_pid_t if_id = KERNEL_PID_UNDEF; + *included_opts = 0; if (!_gnrc_rpl_check_options_validity(msg_type, dodag, opt, len)) { return false; @@ -337,16 +344,20 @@ bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt, switch(opt->type) { case (GNRC_RPL_OPT_PAD1): DEBUG("RPL: PAD1 option parsed\n"); + *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PAD1; l += 1; opt = (gnrc_rpl_opt_t *) (((uint8_t *) opt) + 1); continue; case (GNRC_RPL_OPT_PADN): DEBUG("RPL: PADN option parsed\n"); + *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PADN; break; case (GNRC_RPL_OPT_DODAG_CONF): DEBUG("RPL: DODAG CONF DIO option parsed\n"); + *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_DODAG_CONF; + dodag->dodag_conf_requested = true; gnrc_rpl_opt_dodag_conf_t *dc = (gnrc_rpl_opt_dodag_conf_t *) opt; gnrc_rpl_of_t *of = gnrc_rpl_get_of_for_ocp(byteorder_ntohs(dc->ocp)); if (of != NULL) { @@ -370,6 +381,8 @@ bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt, case (GNRC_RPL_OPT_PREFIX_INFO): DEBUG("RPL: Prefix Information DIO option parsed\n"); + *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PREFIX_INFO; + dodag->prefix_info_requested = true; gnrc_rpl_opt_prefix_info_t *pi = (gnrc_rpl_opt_prefix_info_t *) opt; ipv6_addr_t all_RPL_nodes = GNRC_RPL_ALL_NODES_ADDR; if_id = gnrc_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes); @@ -385,6 +398,7 @@ bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt, case (GNRC_RPL_OPT_TARGET): DEBUG("RPL: RPL TARGET DAO option parsed\n"); + *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_TARGET; if_id = gnrc_ipv6_netif_find_by_prefix(NULL, &dodag->dodag_id); if (if_id == KERNEL_PID_UNDEF) { DEBUG("RPL: no interface found for the configured DODAG id\n"); @@ -405,6 +419,7 @@ bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt, case (GNRC_RPL_OPT_TRANSIT): DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n"); + *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_TRANSIT; gnrc_rpl_opt_transit_t *transit = (gnrc_rpl_opt_transit_t *) opt; if (first_target == NULL) { DEBUG("RPL: Encountered a RPL TRANSIT DAO option without \ @@ -475,9 +490,6 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, ipv6_addr_t *src, uint16_t len) } if (gnrc_rpl_dodag_add(inst, &dio->dodag_id, &dodag)) { - DEBUG("RPL: Joined DODAG (%s).\n", - ipv6_addr_to_str(addr_str, &dio->dodag_id, sizeof(addr_str))); - gnrc_rpl_parent_t *parent = NULL; if (!gnrc_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) { @@ -490,18 +502,29 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, ipv6_addr_t *src, uint16_t len) parent->rank = byteorder_ntohs(dio->rank); - if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, dodag, (gnrc_rpl_opt_t *)(dio + 1), len, NULL)) { + uint32_t included_opts = 0; + if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, dodag, (gnrc_rpl_opt_t *)(dio + 1), len, NULL, + &included_opts)) { DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n"); gnrc_rpl_dodag_remove(dodag); return; } + if (!(included_opts & (((uint32_t) 1) << GNRC_RPL_OPT_DODAG_CONF))) { + DEBUG("RPL: DIO without DODAG_CONF option - remove DODAG and request new DIO\n"); + gnrc_rpl_dodag_remove(dodag); + gnrc_rpl_send_DIS(NULL, src); + return; + } + gnrc_rpl_delay_dao(dodag); trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_INTERVAL, GNRC_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), dodag->dio_interval_doubl, dodag->dio_redun); gnrc_rpl_parent_update(dodag, parent); + DEBUG("RPL: Joined DODAG (%s).\n", + ipv6_addr_to_str(addr_str, &dio->dodag_id, sizeof(addr_str))); return; } else if (dodag == NULL) { @@ -581,8 +604,9 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, ipv6_addr_t *src, uint16_t len) parent->dtsn = dio->dtsn; dodag->grounded = dio->g_mop_prf >> GNRC_RPL_GROUNDED_SHIFT; dodag->prf = dio->g_mop_prf & GNRC_RPL_PRF_MASK; - if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, dodag, - (gnrc_rpl_opt_t *)(dio + 1), len, NULL)) { + uint32_t included_opts = 0; + if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, dodag, (gnrc_rpl_opt_t *)(dio + 1), len, NULL, + &included_opts)) { DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n"); gnrc_rpl_dodag_remove(dodag); return; @@ -800,7 +824,8 @@ void gnrc_rpl_recv_DAO(gnrc_rpl_dao_t *dao, ipv6_addr_t *src, uint16_t len) } } - if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DAO, dodag, opts, len, src)) { + uint32_t included_opts = 0; + if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DAO, dodag, opts, len, src, &included_opts)) { DEBUG("RPL: Error encountered during DAO option parsing - ignore DAO\n"); return; }