diff --git a/sys/include/net/gnrc/rpl.h b/sys/include/net/gnrc/rpl.h index 0b681ebfee23914c9d16b7e32ca4ecdeb30c3413..2659fe82b5dd8fec29a66883aaa15bd19d6e9f6c 100644 --- a/sys/include/net/gnrc/rpl.h +++ b/sys/include/net/gnrc/rpl.h @@ -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. */ diff --git a/sys/include/net/gnrc/rpl/structs.h b/sys/include/net/gnrc/rpl/structs.h index 44f7e92771c83ecc2d5c9828633669d5acec1110..f2d02cbefc24ddc800fe535fa053496deacd22c9 100644 --- a/sys/include/net/gnrc/rpl/structs.h +++ b/sys/include/net/gnrc/rpl/structs.h @@ -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; /** @@ -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; /** 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 22a652470c32bfc1730c00d1979650ff4e777f7a..fbaccde7ece64894acf8c44b97b28587510c0e8a 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c @@ -28,17 +28,20 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#if ENABLE_DEBUG && defined(MODULE_IPV6_ADDR) +#if ENABLE_DEBUG 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) @@ -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; } @@ -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; } @@ -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; } @@ -526,6 +532,12 @@ 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; @@ -533,18 +545,27 @@ void gnrc_rpl_send_DAO(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *destination, uint8_ 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); @@ -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"); @@ -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); } @@ -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); } @@ -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; } diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c index 8ba257a0362121d846b3f8034176ad3f096ee885..03e5fe63ef84b719be6f152102d606fb2b45173f 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c @@ -27,7 +27,7 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#if ENABLE_DEBUG && defined(MODULE_PV6_ADDR) +#if ENABLE_DEBUG static char addr_str[IPV6_ADDR_MAX_STR_LEN]; #endif @@ -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)) {