1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2026-01-01 01:41:18 +01:00

gnrc/rpl/control_messages: extract DIO opts parsing

This commit is contained in:
Elena Frank 2025-06-30 17:14:24 +02:00
parent b80176333a
commit ca2f13fa20

View File

@ -25,6 +25,7 @@
#include "xtimer.h"
#endif
#include "bit.h"
#include "net/af.h"
#include "net/icmpv6.h"
#include "net/ipv6/hdr.h"
@ -533,19 +534,19 @@ static bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt
switch (opt->type) {
case (GNRC_RPL_OPT_PAD1):
DEBUG("RPL: PAD1 option parsed\n");
*included_opts |= ((uint32_t)1) << GNRC_RPL_OPT_PAD1;
bit_set32(included_opts, GNRC_RPL_OPT_PAD1);
len_parsed += 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;
bit_set32(included_opts, 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;
bit_set32(included_opts, GNRC_RPL_OPT_DODAG_CONF);
dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF;
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));
@ -570,7 +571,7 @@ static bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_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;
bit_set32(included_opts, GNRC_RPL_OPT_PREFIX_INFO);
if (!IS_ACTIVE(CONFIG_GNRC_RPL_WITHOUT_PIO)) {
dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO;
@ -597,7 +598,7 @@ static bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt
break;
case (GNRC_RPL_OPT_SOLICITED_INFO):
DEBUG("RPL: RPL SOLICITED INFO option parsed\n");
*included_opts |= ((uint32_t)1) << GNRC_RPL_OPT_SOLICITED_INFO;
bit_set32(included_opts, GNRC_RPL_OPT_SOLICITED_INFO);
gnrc_rpl_opt_dis_solicited_t *sol = (gnrc_rpl_opt_dis_solicited_t *)opt;
/* check expected length */
@ -630,7 +631,7 @@ static bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt
break;
case (GNRC_RPL_OPT_TARGET):
DEBUG("RPL: RPL TARGET DAO option parsed\n");
*included_opts |= ((uint32_t)1) << GNRC_RPL_OPT_TARGET;
bit_set32(included_opts, GNRC_RPL_OPT_TARGET);
gnrc_rpl_opt_target_t *target = (gnrc_rpl_opt_target_t *)opt;
if (first_target == NULL) {
@ -649,7 +650,8 @@ static bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt
case (GNRC_RPL_OPT_TRANSIT):
DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n");
*included_opts |= ((uint32_t)1) << GNRC_RPL_OPT_TRANSIT;
bit_set32(included_opts, 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 "
@ -737,6 +739,49 @@ void gnrc_rpl_recv_DIS(gnrc_rpl_dis_t *dis, kernel_pid_t iface, ipv6_addr_t *src
}
}
/**
* @brief Handles the options from a received DIO packet.
*
* @param[in] inst The @p RPL instance that the DIO belongs to.
* @param[in] dio The @p DIO packet.
* @param[in] src The address of the sender.
* @param[in] len The length of the whole DIO packet.
* @param[in] is_new Whether the DIO belongs to an existing or newly created DODAG.
*
* @retval True on success.
* @retval False if parsing of the options failed.
* @retval False if the DODAG is new and the GNRC_RPL_OPT_DODAG_CONF option
* is required but missing.
*/
static bool _handle_DIO_opts(gnrc_rpl_instance_t *inst, gnrc_rpl_dio_t *dio, ipv6_addr_t *src,
uint16_t len, bool is_new)
{
gnrc_rpl_opt_t *opts = (gnrc_rpl_opt_t *)(dio + 1);
uint32_t included_opts = 0;
/* subtract length of ICMPv6 header and DIO base object fields to get length of DIO options */
size_t opt_len = len - sizeof(gnrc_rpl_dio_t) - sizeof(icmpv6_hdr_t);
if (!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, inst, opts, opt_len, src, &included_opts)) {
DEBUG("RPL: Error encountered during DIO option parsing\n");
return false;
}
if (is_new && !bit_check32(&included_opts, GNRC_RPL_OPT_DODAG_CONF)) {
if (!IS_ACTIVE(CONFIG_GNRC_RPL_DODAG_CONF_OPTIONAL_ON_JOIN)) {
DEBUG("RPL: DIO without DODAG_CONF option - request new DIO\n");
gnrc_rpl_send_DIS(NULL, src, NULL, 0);
return false;
}
else {
DEBUG("RPL: DIO without DODAG_CONF option - use default trickle parameters\n");
gnrc_rpl_send_DIS(NULL, src, NULL, 0);
}
}
return true;
}
/**
* @brief Handles a received DIO message for a new DODAG.
*
@ -792,27 +837,11 @@ void _recv_DIO_for_new_dodag(gnrc_rpl_instance_t *inst, gnrc_rpl_dio_t *dio, ker
parent->rank = byteorder_ntohs(dio->rank);
gnrc_rpl_parent_update(dodag, parent);
uint32_t included_opts = 0;
if (!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, inst, (gnrc_rpl_opt_t *)(dio + 1), len,
src, &included_opts)) {
DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n");
if (!_handle_DIO_opts(inst, dio, src, len, true)) {
gnrc_rpl_instance_remove(inst);
return;
}
if (!(included_opts & (((uint32_t)1) << GNRC_RPL_OPT_DODAG_CONF))) {
if (!IS_ACTIVE(CONFIG_GNRC_RPL_DODAG_CONF_OPTIONAL_ON_JOIN)) {
DEBUG("RPL: DIO without DODAG_CONF option - remove DODAG and request new DIO\n");
gnrc_rpl_instance_remove(inst);
gnrc_rpl_send_DIS(NULL, src, NULL, 0);
return;
}
else {
DEBUG("RPL: DIO without DODAG_CONF option - use default trickle parameters\n");
gnrc_rpl_send_DIS(NULL, src, NULL, 0);
}
}
/* if there was no address created manually or by a PIO on the interface,
* leave this DODAG */
if (gnrc_netif_ipv6_addr_match(netif, &dio->dodag_id) < 0) {
@ -919,9 +948,8 @@ static void _recv_DIO_for_existing_dodag(gnrc_rpl_instance_t *inst, gnrc_rpl_dio
parent->dtsn = dio->dtsn;
dodag->grounded = dio->g_mop_prf >> GNRC_RPL_GROUNDED_SHIFT;
dodag->prf = dio->g_mop_prf & GNRC_RPL_PRF_MASK;
uint32_t included_opts = 0;
if (!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, inst, (gnrc_rpl_opt_t *)(dio + 1), len,
src, &included_opts)) {
if (!_handle_DIO_opts(inst, dio, src, len, false)) {
DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n");
gnrc_rpl_instance_remove(inst);
return;
@ -945,8 +973,6 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, kernel_pid_t iface, ipv6_addr_t *src
}
}
len -= (sizeof(gnrc_rpl_dio_t) + sizeof(icmpv6_hdr_t));
if (gnrc_rpl_instance_add(dio->instance_id, &inst)) {
_recv_DIO_for_new_dodag(inst, dio, iface, src, len);
}