Skip to content

Commit

Permalink
rpl: omit dodag id in DAO(-ACK) for global instances
Browse files Browse the repository at this point in the history
  • Loading branch information
cgundogan committed Aug 20, 2015
1 parent d438984 commit 0894343
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 35 deletions.
13 changes: 13 additions & 0 deletions sys/include/net/gnrc/rpl.h
Expand Up @@ -312,6 +312,19 @@ static inline bool GNRC_RPL_COUNTER_GREATER_THAN(uint8_t A, uint8_t B)
*/
#define GNRC_RPL_LIFETIME_UPDATE_STEP (2)

/**
* @name Global / Local instance id masks
* @see <a href="https://tools.ietf.org/html/rfc6550#section-5.1">
* RFC 6550, section 5.1, RPL Instance ID
* </a>
* @{
*/
#define NG_RPL_INSTANCE_ID_MSB (1 << 7)
#define NG_RPL_GLOBAL_INSTANCE_MASK (0x7F)
#define NG_RPL_LOCAL_INSTANCE_MASK (0x3F)
#define NG_RPL_INSTANCE_D_FLAG_MASK (1 << 6)
/** @} */

/**
* @brief PID of the RPL thread.
*/
Expand Down
2 changes: 0 additions & 2 deletions sys/include/net/gnrc/rpl/structs.h
Expand Up @@ -101,7 +101,6 @@ typedef struct __attribute__((packed)) {
uint8_t k_d_flags; /**< K and D flags */
uint8_t reserved; /**< reserved */
uint8_t dao_sequence; /**< sequence of the DAO, needs to be used for DAO-ACK */
ipv6_addr_t dodag_id; /**< id of the DODAG */
} gnrc_rpl_dao_t;

/**
Expand All @@ -115,7 +114,6 @@ typedef struct __attribute__((packed)) {
uint8_t d_reserved; /**< if set, indicates that the DODAG id should be included */
uint8_t dao_sequence; /**< sequence must be equal to the sequence from the DAO object */
uint8_t status; /**< indicates completion */
ipv6_addr_t dodag_id; /**< id of the DODAG */
} gnrc_rpl_dao_ack_t;

/**
Expand Down
109 changes: 76 additions & 33 deletions sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c
Expand Up @@ -32,13 +32,16 @@
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#endif

#define GNRC_RPL_GROUNDED_SHIFT (7)
#define GNRC_RPL_MOP_SHIFT (3)
#define GNRC_RPL_OPT_DODAG_CONF_LEN (14)
#define GNRC_RPL_OPT_PREFIX_INFO_LEN (30)
#define GNRC_RPL_SHIFTED_MOP_MASK (0x7)
#define GNRC_RPL_PRF_MASK (0x7)
#define GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT (1 << 6)
#define GNRC_RPL_GROUNDED_SHIFT (7)
#define GNRC_RPL_MOP_SHIFT (3)
#define GNRC_RPL_OPT_DODAG_CONF_LEN (14)
#define GNRC_RPL_OPT_PREFIX_INFO_LEN (30)
#define GNRC_RPL_SHIFTED_MOP_MASK (0x7)
#define GNRC_RPL_PRF_MASK (0x7)
#define GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT (1 << 6)
#define GNRC_RPL_DAO_D_BIT (1 << 6)
#define GNRC_RPL_DAO_K_BIT (1 << 7)
#define GNRC_RPL_DAO_ACK_D_BIT (1 << 7)

void _gnrc_rpl_send(gnrc_pktsnip_t *pkt, ipv6_addr_t *src, ipv6_addr_t *dst,
ipv6_addr_t *dodag_id)
Expand Down Expand Up @@ -226,6 +229,7 @@ bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt,
if ((opt->type != GNRC_RPL_OPT_PAD1) && (len < opt->length + sizeof(gnrc_rpl_opt_t) + l)) {
/* return false to delete the dodag,
* because former options may also contain errors */
DEBUG("RPL: Wrong option length encountered\n");
return false;
}

Expand Down Expand Up @@ -380,6 +384,7 @@ 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)) {
DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n");
gnrc_rpl_dodag_remove(dodag);
return;
}
Expand Down Expand Up @@ -451,6 +456,7 @@ 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)) {
DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n");
gnrc_rpl_dodag_remove(dodag);
return;
}
Expand Down Expand Up @@ -526,25 +532,40 @@ void gnrc_rpl_send_DAO(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_
int size = sizeof(icmpv6_hdr_t) + sizeof(gnrc_rpl_dao_t) +
(sizeof(gnrc_rpl_opt_target_t) * (dst_size + 1)) + sizeof(gnrc_rpl_opt_transit_t);

bool local_instance = (dodag->instance->id & NG_RPL_INSTANCE_ID_MSB) ? true : false;

if (local_instance) {
size += sizeof(ipv6_addr_t);
}

if ((pkt = gnrc_icmpv6_build(NULL, ICMPV6_RPL_CTRL, GNRC_RPL_ICMPV6_CODE_DAO, size)) == NULL) {
DEBUG("RPL: Send DAO - no space left in packet buffer\n");
return;
}

icmp = (icmpv6_hdr_t *)pkt->data;
dao = (gnrc_rpl_dao_t *)(icmp + 1);
target = (gnrc_rpl_opt_target_t *) (dao + 1);

dao->instance_id = dodag->instance->id;
/* set the D flag to indicate that a DODAG id is present */
/* set the K flag to indicate that a ACKs are required */
dao->k_d_flags = ((1 << 6) | (1 << 7));
if (local_instance) {
/* set the D flag to indicate that a DODAG id is present */
dao->k_d_flags = GNRC_RPL_DAO_D_BIT;
memcpy((dao + 1), &dodag->dodag_id, sizeof(ipv6_addr_t));
target = (gnrc_rpl_opt_target_t *)(((uint8_t *) target) + sizeof(ipv6_addr_t));
}
else {
dao->k_d_flags = 0;
}

/* set the K flag to indicate that ACKs are required */
dao->k_d_flags |= GNRC_RPL_DAO_K_BIT;
dao->dao_sequence = dodag->dao_seq;
dao->dodag_id = dodag->dodag_id;
dao->reserved = 0;

/* add own address */
target = (gnrc_rpl_opt_target_t *) (dao + 1);
_dao_fill_target(target, me);

/* add children */
for (size_t i = 0; i < dst_size; ++i) {
target = (target + 1);
Expand Down Expand Up @@ -576,6 +597,11 @@ void gnrc_rpl_send_DAO_ACK(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination, ui
icmpv6_hdr_t *icmp;
gnrc_rpl_dao_ack_t *dao_ack;
int size = sizeof(icmpv6_hdr_t) + sizeof(gnrc_rpl_dao_ack_t);
bool local_instance = (dodag->instance->id & NG_RPL_INSTANCE_ID_MSB) ? true : false;

if (local_instance) {
size += sizeof(ipv6_addr_t);
}

if ((pkt = gnrc_icmpv6_build(NULL, ICMPV6_RPL_CTRL, GNRC_RPL_ICMPV6_CODE_DAO_ACK, size)) == NULL) {
DEBUG("RPL: Send DAOACK - no space left in packet buffer\n");
Expand All @@ -586,11 +612,17 @@ void gnrc_rpl_send_DAO_ACK(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination, ui
dao_ack = (gnrc_rpl_dao_ack_t *)(icmp + 1);

dao_ack->instance_id = dodag->instance->id;
/* set the D flag to indicate that a DODAG id is present */
dao_ack->d_reserved = (1 << 7);
if (local_instance) {
/* set the D flag to indicate that a DODAG id is present */
dao_ack->d_reserved = GNRC_RPL_DAO_ACK_D_BIT;
memcpy((dao_ack + 1), &dodag->dodag_id, sizeof(ipv6_addr_t));
}
else {
dao_ack->d_reserved = 0;
}

dao_ack->dao_sequence = seq;
dao_ack->status = 0;
dao_ack->dodag_id = dodag->dodag_id;

_gnrc_rpl_send(pkt, NULL, destination, &dodag->dodag_id);
}
Expand All @@ -599,31 +631,40 @@ void gnrc_rpl_recv_DAO(gnrc_rpl_dao_t *dao, ipv6_addr_t *src, uint16_t len)
{
gnrc_rpl_instance_t *inst = NULL;
gnrc_rpl_dodag_t *dodag = NULL;
gnrc_rpl_opt_t *opts = (gnrc_rpl_opt_t *) (dao + 1);

if ((inst = gnrc_rpl_instance_get(dao->instance_id)) == NULL) {
DEBUG("RPL: DAO with unknown instance id (%d) received\n", dao->instance_id);
return;
}

len -= (sizeof(gnrc_rpl_dao_t) + sizeof(icmpv6_hdr_t));

/* check if the D flag is set before accessing the DODAG id */
if (!(dao->k_d_flags & (1 << 6))) {
DEBUG("RPL: DAO with D flag unset - global instances not supported\n");
return;
if ((dao->k_d_flags & GNRC_RPL_DAO_D_BIT)) {
if ((dodag = gnrc_rpl_dodag_get(inst, (ipv6_addr_t *)(dao + 1))) == NULL) {
DEBUG("RPL: DAO with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
(ipv6_addr_t *)(dao + 1), sizeof(addr_str)));
return;
}
opts = (gnrc_rpl_opt_t *)(((uint8_t *) opts) + sizeof(ipv6_addr_t));
len -= sizeof(ipv6_addr_t);
}

if ((dodag = gnrc_rpl_dodag_get(inst, &dao->dodag_id)) == NULL) {
DEBUG("RPL: DAO with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
&dao->dodag_id, sizeof(addr_str)));
return;
else {
if ((dodag = gnrc_rpl_dodag_get(inst, NULL)) == NULL) {
DEBUG("RPL: DAO for instance (%d) without DODAGs\n", dao->instance_id);
return;
}
}

len -= (sizeof(gnrc_rpl_dao_t) + sizeof(icmpv6_hdr_t));
if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DAO, dodag, (gnrc_rpl_opt_t *) (dao + 1), len, src)) {
if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DAO, dodag, opts, len, src)) {
DEBUG("RPL: Error encountered during DAO option parsing - remove DODAG\n");
gnrc_rpl_dodag_remove(dodag);
return;
}

/* send a DAO-ACK if K flag is set */
if (dao->k_d_flags & (1 << 7)) {
if (dao->k_d_flags & GNRC_RPL_DAO_K_BIT) {
gnrc_rpl_send_DAO_ACK(dodag, src, dao->dao_sequence);
}

Expand All @@ -640,14 +681,16 @@ void gnrc_rpl_recv_DAO_ACK(gnrc_rpl_dao_ack_t *dao_ack)
}

/* check if the D flag is set before accessing the DODAG id */
if (!(dao_ack->d_reserved & (1 << 7))) {
DEBUG("RPL: DAO-ACK with D flag unset - global instances not supported\n");
return;
if ((dao_ack->d_reserved & GNRC_RPL_DAO_ACK_D_BIT)) {
if ((dodag = gnrc_rpl_dodag_get(inst, (ipv6_addr_t *)(dao_ack + 1))) == NULL) {
DEBUG("RPL: DAO-ACK with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
(ipv6_addr_t *)(dao_ack + 1), sizeof(addr_str)));
return;
}
}

if ((dodag = gnrc_rpl_dodag_get(inst, &dao_ack->dodag_id)) == NULL) {
DEBUG("RPL: DAO-ACK with unknown DODAG id (%s)\n", ipv6_addr_to_str(addr_str,
&dao_ack->dodag_id, sizeof(addr_str)));
/* D flag not set - global instance id */
else if ((dodag = gnrc_rpl_dodag_get(inst, NULL)) == NULL) {
DEBUG("RPL: DAO-ACK for instance (%d) without DODAGs\n", dao_ack->instance_id);
return;
}

Expand Down
10 changes: 10 additions & 0 deletions sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c
Expand Up @@ -199,6 +199,16 @@ gnrc_rpl_dodag_t *gnrc_rpl_dodag_get(gnrc_rpl_instance_t *instance, ipv6_addr_t
return NULL;
}

/* check if global instance id */
if ((dodag_id == NULL) && ((instance->id & NG_RPL_INSTANCE_ID_MSB) == 0)) {
#if defined(DEVELHELP) && defined(ENABLE_DEBUG)
if ((instance->dodags != NULL) && (instance->dodags->next != NULL)) {
DEBUG("RPL: More than one DODAG available for the global instance (%d)", instance->id);
}
#endif
return instance->dodags;
}

gnrc_rpl_dodag_t *dodag = NULL;
LL_FOREACH(instance->dodags, dodag) {
if (ipv6_addr_equal(&dodag->dodag_id, dodag_id)) {
Expand Down

0 comments on commit 0894343

Please sign in to comment.