From b5c09bfc41ad046263638f606fb51b0d4aba402c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cenk=20G=C3=BCndo=C4=9Fan?= Date: Sun, 23 Aug 2015 14:25:39 +0200 Subject: [PATCH 1/2] rpl: introducing p2p-rpl --- Makefile.dep | 4 + sys/include/net/gnrc/rpl/p2p.h | 180 ++++++++ sys/include/net/gnrc/rpl/p2p_dodag.h | 74 ++++ sys/include/net/gnrc/rpl/p2p_structs.h | 106 +++++ sys/net/gnrc/Makefile | 3 + sys/net/gnrc/routing/rpl/gnrc_rpl.c | 31 ++ .../routing/rpl/gnrc_rpl_control_messages.c | 54 ++- sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c | 43 +- sys/net/gnrc/routing/rpl/p2p/Makefile | 3 + sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p.c | 386 ++++++++++++++++++ .../gnrc/routing/rpl/p2p/gnrc_rpl_p2p_dodag.c | 63 +++ sys/shell/commands/sc_gnrc_rpl.c | 30 ++ 12 files changed, 972 insertions(+), 5 deletions(-) create mode 100644 sys/include/net/gnrc/rpl/p2p.h create mode 100644 sys/include/net/gnrc/rpl/p2p_dodag.h create mode 100644 sys/include/net/gnrc/rpl/p2p_structs.h create mode 100644 sys/net/gnrc/routing/rpl/p2p/Makefile create mode 100644 sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p.c create mode 100644 sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p_dodag.c diff --git a/Makefile.dep b/Makefile.dep index 6dafb9f0e1..9d00969c13 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -53,6 +53,10 @@ ifneq (,$(filter gnrc_tftp,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter gnrc_rpl_p2p,$(USEMODULE))) + USEMODULE += gnrc_rpl +endif + ifneq (,$(filter gnrc_rpl,$(USEMODULE))) USEMODULE += fib USEMODULE += gnrc_ipv6_router_default diff --git a/sys/include/net/gnrc/rpl/p2p.h b/sys/include/net/gnrc/rpl/p2p.h new file mode 100644 index 0000000000..05d3f588b6 --- /dev/null +++ b/sys/include/net/gnrc/rpl/p2p.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2016 Cenk Gündoğan + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_rpl_p2p Reactive Discovery of P2P Routes in LLNs + * @ingroup net_gnrc_rpl + * @brief Implementation of P2P-RPL + * @see + * RFC 6997 + * + * @{ + * + * @file + * @brief Definititions for P2P-RPL + * + * @author Cenk Gündoğan + */ +#ifndef GNRC_RPL_P2P_H_ +#define GNRC_RPL_P2P_H_ + +#include "net/ipv6/addr.h" +#include "net/gnrc.h" +#include "net/gnrc/rpl/structs.h" +#include "net/gnrc/rpl/p2p_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief P2P-RPL Mode of Operation + */ +#define GNRC_RPL_P2P_MOP (0x04) + +/** + * @brief Default lifetime of the P2P-RPL DODAG, encoded + * @see + * RFC 6997, section 7, P2P Route Discovery Option (P2P-RDO) + * + */ +#define GNRC_RPL_P2P_LIFETIME (0x02) + +/** + * @brief Number of elided prefix octets from the target field and address vector + * @see + * RFC 6997, section 7, P2P Route Discovery Option (P2P-RDO) + * + */ +#define GNRC_RPL_P2P_COMPR (0) + +/** + * @brief Maximum rank in the DODAG during the route discovery + * @see + * RFC 6997, section 7, P2P Route Discovery Option (P2P-RDO) + * + */ +#define GNRC_RPL_P2P_MAX_RANK (0) + +/** + * @name Trickle parameters + * @see + * RFC 6997, section 6.1, Setting a P2P Mode DIO + * + * @{ + */ +#define GNRC_RPL_P2P_DEFAULT_DIO_INTERVAL_MIN (6) +#define GNRC_RPL_P2P_DEFAULT_DIO_REDUNDANCY_CONSTANT (1) +/** @} */ + +/** + * @name Default parent and route entry lifetime + * default lifetime will be multiplied by the lifetime unit to obtain the resulting lifetime + * @{ + */ +#define GNRC_RPL_P2P_DEFAULT_LIFETIME (0xFF) +#define GNRC_RPL_P2P_LIFETIME_UNIT (0xFFFF) +/** @} */ + +/** + * @brief P2P-RPL RDO DIO option type + * @see + * RFC 6997, section 7, P2P Route Discovery Option (P2P-RDO) + * + */ +#define GNRC_RPL_P2P_OPT_RDO (0x0A) + +/** + * @brief DRO ICMPv6 code + * @see + * RFC 6997, section 8, The P2P Discovery Reply Object (P2P-DRO) + * + */ +#define GNRC_RPL_P2P_ICMPV6_CODE_DRO (0x04) + +/** + * @brief DRO-ACK ICMPv6 code + * @see + * RFC 6997, section 10, The P2P Discovery Reply Object Acknowledgement (P2P-DRO-ACK) + * + */ +#define GNRC_RPL_P2P_ICMPV6_CODE_DRO_ACK (0x05) + +/** + * @brief Time in seconds to wait before sending a DRO + */ +#define GNRC_RPL_P2P_DRO_DELAY (4) + +/** + * @brief Message type for handling DRO sending + */ +#define GNRC_RPL_P2P_MSG_TYPE_DRO_HANDLE (0x09A0) + +/** + * @brief Lookup table used to decode/encode the lifetime values + */ +extern const uint8_t gnrc_rpl_p2p_lifetime_lookup[4]; + +/** + * @brief Initialization of a P2P-RPL Instance as root node. + * + * @param[in] instance_id Id of the instance + * @param[in] dodag_id Id of the DODAG + * @param[in] target Target of the P2P-RPL routes discovery + * @param[in] gen_inst_id Flag indicating whether to generate a local isntance id. + * If true, @p instance_id will be ignored + * + * @return Pointer to the new Instance, on success. + * @return NULL, otherwise. + */ +gnrc_rpl_instance_t *gnrc_rpl_p2p_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id, + ipv6_addr_t *target, bool gen_inst_id); + +/** + * @brief Build an RDO + * + * @param[in,out] pkt The RDO will be added to the @p pkt + * @param[in] p2p_ext Pointer to the P2P-RPL DODAG extension + */ +gnrc_pktsnip_t *gnrc_rpl_p2p_rdo_build(gnrc_pktsnip_t *pkt, gnrc_rpl_p2p_ext_t *p2p_ext); + +/** + * @brief Parse an RDO + * + * @param[in] rdo The RDO to parse from. + * @param[in] p2p_ext Pointer to the P2P-RPL DODAG extension + */ +void gnrc_rpl_p2p_rdo_parse(gnrc_rpl_p2p_opt_rdo_t *rdo, gnrc_rpl_p2p_ext_t *p2p_ext); + +/** + * @brief Send a DRO control message + * + * @param[in] pkt The ICMPv6 packet to send. Can be NULL. + * @param[in] p2p_ext Pointer to the P2P-RPL DODAG extension + */ +void gnrc_rpl_p2p_send_DRO(gnrc_pktsnip_t *pkt, gnrc_rpl_p2p_ext_t *p2p_ext); + +/** + * @brief Receive and parse a DRO control message + * + * @param[in] pkt The ICMPv6 packet to parse. + * @param[in] src The source address of the IPv6 packet. + */ +void gnrc_rpl_p2p_recv_DRO(gnrc_pktsnip_t *pkt, ipv6_addr_t *src); + +/** + * @brief Updates the lifetime of the P2P Dodag and the delay of the DRO + */ +void gnrc_rpl_p2p_update(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_RPL_P2P_H_ */ +/** @} */ diff --git a/sys/include/net/gnrc/rpl/p2p_dodag.h b/sys/include/net/gnrc/rpl/p2p_dodag.h new file mode 100644 index 0000000000..466c7b71a9 --- /dev/null +++ b/sys/include/net/gnrc/rpl/p2p_dodag.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 Cenk Gündoğan + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup net_gnrc_rpl_p2p + * @{ + * + * @file + * @brief DODAG-related functions for P2P-RPL + * + * Header file, which defines all public known DODAG-related functions for P2P-RPL. + * + * @author Cenk Gündoğan + */ + +#ifndef GNRC_RPL_P2P_DODAG_H_ +#define GNRC_RPL_P2P_DODAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "net/gnrc/rpl/p2p_structs.h" + +/** + * @brief Number of P2P RPL DODAG extensions + */ +#ifndef GNRC_RPL_P2P_EXTS_NUMOF +#define GNRC_RPL_P2P_EXTS_NUMOF (1) +#endif + +/** + * @brief P2P-RPL DODAG extensions table + */ +extern gnrc_rpl_p2p_ext_t gnrc_rpl_p2p_exts[GNRC_RPL_P2P_EXTS_NUMOF]; + +/** + * @brief Allocate a free P2P-RPL DODAG extension + * + * @return Pointer to a free P2P-RPL DODAG extension + * @return NULL, if no free P2P-RPL DODAG extension is available + */ +gnrc_rpl_p2p_ext_t *gnrc_rpl_p2p_ext_new(gnrc_rpl_dodag_t *dodag); + +/** + * @brief Free the P2P-RPL DODAG extension of @p dodag + * + * @param[in] dodag Pointer to a P2P-RPL DODAG + */ +void gnrc_rpl_p2p_ext_remove(gnrc_rpl_dodag_t *dodag); + +/** + * @brief Get the appropriate P2P-RPL DODAG extension of the @p dodag + * + * @param[in] dodag Pointer to a P2P-RPL DODAG + * + * @return Pointer to a P2P-RPL DODAG extension + * @return NULL, if no P2P-RPL DODAG extension is available for @p dodag + */ +gnrc_rpl_p2p_ext_t *gnrc_rpl_p2p_ext_get(gnrc_rpl_dodag_t *dodag); + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_RPL_P2P_DODAG_H_ */ +/** + * @} + */ diff --git a/sys/include/net/gnrc/rpl/p2p_structs.h b/sys/include/net/gnrc/rpl/p2p_structs.h new file mode 100644 index 0000000000..69602baf45 --- /dev/null +++ b/sys/include/net/gnrc/rpl/p2p_structs.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 Cenk Gündoğan + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup net_gnrc_rpl_p2p + * @{ + * + * @file + * @brief P2P-RPL data structs + * + * Header file, which defines all structs used by P2P-RPL. + * + * @author Cenk Gündoğan + */ + +#ifndef GNRC_RPL_P2P_STRUCTS_H_ +#define GNRC_RPL_P2P_STRUCTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "net/ipv6/addr.h" +#include "net/gnrc/rpl/structs.h" + +/** + * @brief Address vector length in RDO DIO options and maximal hop count for the P2P-DODAG + */ +#define GNRC_RPL_P2P_ADDR_VEC_NUMOF (8) + +/** + * @brief P2P Route Discovery Object (RDO) Option + * @see + * RFC 6997, section 7, P2P Route Discovery Option (P2P-RDO) + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< Option Type: 0x0a */ + uint8_t length; /**< length of option, not including first two bytes */ + uint8_t compr_flags; /**< flags and number of elided prefix octets */ + uint8_t lmn; /**< lifetime, maxrank/nexthop */ + ipv6_addr_t target; /**< target address */ +} gnrc_rpl_p2p_opt_rdo_t; + +/** + * @brief P2P Discovery Reply Object (P2P-DRO) + * @see + * RFC 6997, section 8, P2P Discovery Reply Object (P2P-DRO) + * + */ +typedef struct __attribute__((packed)) { + uint8_t instance_id; /**< id of the instance */ + uint8_t version_number; /**< version number of the DODAG */ + network_uint16_t flags_rev; /**< flags and reserved */ + ipv6_addr_t dodag_id; /**< id of the dodag */ +} gnrc_rpl_p2p_dro_t; + +/** + * @brief P2P Discovery Reply Object Acknowledgement (P2P-DRO-ACK) + * @see + * RFC 6997, section 10, P2P Discovery Reply Object Acknowledgement (P2P-DRO-ACK) + * + */ +typedef struct __attribute__((packed)) { + uint8_t instance_id; /**< id of the instance */ + uint8_t version_number; /**< version number of the DODAG */ + network_uint16_t seq_rev; /**< sequence number and reserved */ + ipv6_addr_t dodag_id; /**< id of the dodag */ +} gnrc_rpl_p2p_dro_ack_t; + +/** + * @brief Extended DODAG information for P2P-RPL + */ +typedef struct { + bool state; /**< state: used / unused */ + gnrc_rpl_dodag_t *dodag;/**< DODAG, which owns this P2P extension */ + uint8_t compr; /**< number of elided prefix octets */ + uint8_t routes_numof; /**< number of requested routes */ + bool hop_by_hop; /**< request hop-by-hop routes or source routes */ + bool stop; /**< stop route discovery */ + bool reply; /**< request P2P-DRO */ + bool dro_ack; /**< request P2P-DRO-ACK */ + uint8_t lifetime_enc; /**< encoded lifetime of the P2P-DODAG */ + int8_t lifetime_sec; /**< lifetime of the P2P-DODAG in seconds */ + uint8_t maxrank; /**< maximum rank the P2P-DODAG should span */ + uint8_t dro_seq; /**< sequence number of the P2P-DRO */ + ipv6_addr_t target; /**< target of the P2P route discovery */ + bool for_me; /**< true if this node is the target */ + uint8_t addr_numof; /**< number of addresses in the address vector */ + int8_t dro_delay; /**< delay DRO after it was requested in seconds */ + ipv6_addr_t addr_vec[GNRC_RPL_P2P_ADDR_VEC_NUMOF]; /**< address vector */ +} gnrc_rpl_p2p_ext_t; + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_RPL_P2P_STRUCTS_H_ */ +/** + * @} + */ diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index e21de28ed5..a4b69955ff 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -85,6 +85,9 @@ endif ifneq (,$(filter gnrc_rpl_srh,$(USEMODULE))) DIRS += routing/rpl/srh endif +ifneq (,$(filter gnrc_rpl_p2p,$(USEMODULE))) + DIRS += routing/rpl/p2p +endif ifneq (,$(filter gnrc_sixlowpan,$(USEMODULE))) DIRS += network_layer/sixlowpan endif diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl.c b/sys/net/gnrc/routing/rpl/gnrc_rpl.c index 6acd978c28..f3420d9e41 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl.c @@ -21,6 +21,10 @@ #include "mutex.h" #include "net/gnrc/rpl.h" +#ifdef MODULE_GNRC_RPL_P2P +#include "net/gnrc/rpl/p2p.h" +#include "net/gnrc/rpl/p2p_dodag.h" +#endif #define ENABLE_DEBUG (0) #include "debug.h" @@ -157,6 +161,24 @@ static void _receive(gnrc_pktsnip_t *icmpv6) gnrc_rpl_recv_DAO_ACK((gnrc_rpl_dao_ack_t *)(icmpv6_hdr + 1), iface, byteorder_ntohs(ipv6_hdr->len)); break; +#ifdef MODULE_GNRC_RPL_P2P + case GNRC_RPL_P2P_ICMPV6_CODE_DRO: + DEBUG("RPL: P2P DRO received\n"); + gnrc_pktsnip_t *icmpv6_snip = gnrc_pktbuf_add(NULL, NULL, icmpv6->size, + GNRC_NETTYPE_ICMPV6); + if (icmpv6_snip == NULL) { + DEBUG("RPL-P2P: cannot copy ICMPv6 packet\n"); + break; + } + + memcpy(icmpv6_snip->data, icmpv6->data, icmpv6->size); + + gnrc_rpl_p2p_recv_DRO(icmpv6_snip, &ipv6_hdr->src); + break; + case GNRC_RPL_P2P_ICMPV6_CODE_DRO_ACK: + DEBUG("RPL: P2P DRO-ACK received\n"); + break; +#endif default: DEBUG("RPL: Unknown ICMPV6 code received\n"); break; @@ -265,6 +287,10 @@ void _update_lifetime(void) } } +#ifdef MODULE_GNRC_RPL_P2P + gnrc_rpl_p2p_update(); +#endif + xtimer_set_msg(&_lt_timer, _lt_time, &_lt_msg, gnrc_rpl_pid); } @@ -284,6 +310,11 @@ void gnrc_rpl_long_delay_dao(gnrc_rpl_dodag_t *dodag) void _dao_handle_send(gnrc_rpl_dodag_t *dodag) { +#ifdef MODULE_GNRC_RPL_P2P + if (dodag->instance->mop == GNRC_RPL_P2P_MOP) { + return; + } +#endif if ((dodag->dao_ack_received == false) && (dodag->dao_counter < GNRC_RPL_DAO_SEND_RETRIES)) { dodag->dao_counter++; gnrc_rpl_send_DAO(dodag->instance, NULL, dodag->default_lifetime); 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 472ad78c1d..e9bf29addd 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_control_messages.c @@ -25,6 +25,12 @@ #include "net/gnrc/rpl.h" +#ifdef MODULE_GNRC_RPL_P2P +#include "net/gnrc/rpl/p2p_structs.h" +#include "net/gnrc/rpl/p2p_dodag.h" +#include "net/gnrc/rpl/p2p.h" +#endif + #define ENABLE_DEBUG (0) #include "debug.h" @@ -161,6 +167,18 @@ void gnrc_rpl_send_DIO(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination) gnrc_pktsnip_t *pkt = NULL, *tmp; gnrc_rpl_dio_t *dio; +#ifdef MODULE_GNRC_RPL_P2P + gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag); + if (dodag->instance->mop == GNRC_RPL_P2P_MOP) { + if (!p2p_ext->for_me) { + if ((pkt = gnrc_rpl_p2p_rdo_build(pkt, p2p_ext)) == NULL) { + return; + } + } + dodag->dio_opts &= ~GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; + } +#endif + #ifndef GNRC_RPL_WITHOUT_PIO if (dodag->dio_opts & GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO) { if ((pkt = _dio_prefix_info_build(pkt, dodag)) == NULL) { @@ -265,6 +283,12 @@ void gnrc_rpl_recv_DIS(gnrc_rpl_dis_t *dis, kernel_pid_t iface, ipv6_addr_t *src 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)); } } @@ -497,6 +521,11 @@ bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt_t *opt first_target = NULL; break; +#ifdef MODULE_GNRC_RPL_P2P + case (GNRC_RPL_P2P_OPT_RDO): + gnrc_rpl_p2p_rdo_parse((gnrc_rpl_p2p_opt_rdo_t *) opt, gnrc_rpl_p2p_ext_get(dodag)); + break; +#endif } l += opt->length + sizeof(gnrc_rpl_opt_t); opt = (gnrc_rpl_opt_t *) (((uint8_t *) (opt + 1)) + opt->length); @@ -635,6 +664,13 @@ void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, kernel_pid_t iface, ipv6_addr_t *src return; } +#ifdef MODULE_GNRC_RPL_P2P + gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag); + if ((dodag->instance->mop == GNRC_RPL_P2P_MOP) && (p2p_ext->lifetime_sec <= 0)) { + return; + } +#endif + if (GNRC_RPL_COUNTER_GREATER_THAN(dio->version_number, dodag->version)) { if (dodag->node_status == GNRC_RPL_ROOT_NODE) { dodag->version = GNRC_RPL_COUNTER_INCREMENT(dio->version_number); @@ -760,6 +796,12 @@ void gnrc_rpl_send_DAO(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination, uint return; } +#ifdef MODULE_GNRC_RPL_P2P + if (dodag->instance->mop == GNRC_RPL_P2P_MOP) { + return; + } +#endif + if (destination == NULL) { if (dodag->parents == NULL) { DEBUG("RPL: dodag has no preferred parent\n"); @@ -781,14 +823,12 @@ void gnrc_rpl_send_DAO(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination, uint return; } - fib_entry_t *fentry = NULL; - ipv6_addr_t *addr = NULL; - mutex_lock(&(gnrc_ipv6_fib_table.mtx_access)); /* add external and RPL FIB entries */ for (size_t i = 0; i < gnrc_ipv6_fib_table.size; ++i) { - fentry = &gnrc_ipv6_fib_table.data.entries[i]; + ipv6_addr_t *addr; + fib_entry_t *fentry = &gnrc_ipv6_fib_table.data.entries[i]; if (fentry->lifetime != 0) { if (!(fentry->next_hop_flags & FIB_FLAG_RPL_ROUTE)) { ptr = &tmp; @@ -1003,6 +1043,12 @@ void gnrc_rpl_recv_DAO(gnrc_rpl_dao_t *dao, kernel_pid_t iface, ipv6_addr_t *src return; } +#ifdef MODULE_GNRC_RPL_P2P + if (dodag->instance->mop == GNRC_RPL_P2P_MOP) { + return; + } +#endif + uint32_t included_opts = 0; if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DAO, inst, opts, len, src, &included_opts)) { DEBUG("RPL: Error encountered during DAO option parsing - ignore DAO\n"); diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c index ec75700950..e864f6c616 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c @@ -24,6 +24,10 @@ #include "utlist.h" #include "net/gnrc/rpl.h" +#ifdef MODULE_GNRC_RPL_P2P +#include "net/gnrc/rpl/p2p.h" +#include "net/gnrc/rpl/p2p_dodag.h" +#endif #define ENABLE_DEBUG (0) #include "debug.h" @@ -46,6 +50,16 @@ static void _rpl_trickle_send_dio(void *args) return; } +#ifdef MODULE_GNRC_RPL_P2P + if (dodag->instance->mop == GNRC_RPL_P2P_MOP) { + gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag); + if (p2p_ext && (p2p_ext->for_me || ((p2p_ext->lifetime_sec <= 0) || p2p_ext->stop))) { + trickle_stop(&dodag->trickle); + return; + } + } +#endif + gnrc_rpl_send_DIO(inst, (ipv6_addr_t *) &ipv6_addr_all_rpl_nodes); DEBUG("trickle callback: Instance (%d) | DODAG: (%s)\n", inst->id, ipv6_addr_to_str(addr_str,&dodag->dodag_id, sizeof(addr_str))); @@ -97,6 +111,9 @@ bool gnrc_rpl_instance_remove_by_id(uint8_t instance_id) bool gnrc_rpl_instance_remove(gnrc_rpl_instance_t *inst) { gnrc_rpl_dodag_t *dodag = &inst->dodag; +#ifdef MODULE_GNRC_RPL_P2P + gnrc_rpl_p2p_ext_remove(dodag); +#endif gnrc_rpl_dodag_remove_all_parents(dodag); trickle_stop(&dodag->trickle); memset(inst, 0, sizeof(gnrc_rpl_instance_t)); @@ -140,6 +157,14 @@ bool gnrc_rpl_dodag_init(gnrc_rpl_instance_t *instance, ipv6_addr_t *dodag_id, k dodag->iface = iface; dodag->netif_addr = netif_addr; +#ifdef MODULE_GNRC_RPL_P2P + if ((instance->mop == GNRC_RPL_P2P_MOP) && (gnrc_rpl_p2p_ext_new(dodag) == NULL)) { + DEBUG("RPL: could not allocate new P2P-RPL DODAG extension. Remove DODAG\n"); + gnrc_rpl_instance_remove(instance); + return false; + } +#endif + return true; } @@ -149,6 +174,7 @@ void gnrc_rpl_dodag_remove_all_parents(gnrc_rpl_dodag_t *dodag) LL_FOREACH_SAFE(dodag->parents, elt, tmp) { gnrc_rpl_parent_remove(elt); } + dodag->my_rank = GNRC_RPL_INFINITE_RANK; } bool gnrc_rpl_parent_add_by_addr(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *addr, @@ -243,6 +269,9 @@ void gnrc_rpl_parent_update(gnrc_rpl_dodag_t *dodag, gnrc_rpl_parent_t *parent) /* update Parent lifetime */ if (parent != NULL) { parent->lifetime = (now / SEC_IN_USEC) + ((dodag->default_lifetime * dodag->lifetime_unit)); +#ifdef MODULE_GNRC_RPL_P2P + if (dodag->instance->mop != GNRC_RPL_P2P_MOP) { +#endif if (parent == dodag->parents) { fib_add_entry(&gnrc_ipv6_fib_table, dodag->iface, @@ -254,6 +283,9 @@ void gnrc_rpl_parent_update(gnrc_rpl_dodag_t *dodag, gnrc_rpl_parent_t *parent) FIB_FLAG_RPL_ROUTE, (dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS); } +#ifdef MODULE_GNRC_RPL_P2P + } +#endif } if (_gnrc_rpl_find_preferred_parent(dodag) == NULL) { @@ -291,11 +323,16 @@ static gnrc_rpl_parent_t *_gnrc_rpl_find_preferred_parent(gnrc_rpl_dodag_t *doda if (new_best != old_best) { LL_DELETE(dodag->parents, new_best); LL_PREPEND(dodag->parents, new_best); - if (dodag->instance->mop != GNRC_RPL_MOP_NO_DOWNWARD_ROUTES) { + /* no-path DAOs only for the storing mode */ + if ((dodag->instance->mop == GNRC_RPL_MOP_STORING_MODE_NO_MC) || + (dodag->instance->mop == GNRC_RPL_MOP_STORING_MODE_MC)) { gnrc_rpl_send_DAO(dodag->instance, &old_best->addr, 0); gnrc_rpl_delay_dao(dodag); } +#ifdef MODULE_GNRC_RPL_P2P + if (dodag->instance->mop != GNRC_RPL_P2P_MOP) { +#endif fib_add_entry(&gnrc_ipv6_fib_table, dodag->iface, (uint8_t *) ipv6_addr_unspecified.u8, @@ -305,6 +342,10 @@ static gnrc_rpl_parent_t *_gnrc_rpl_find_preferred_parent(gnrc_rpl_dodag_t *doda sizeof(ipv6_addr_t), FIB_FLAG_RPL_ROUTE, (dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS); +#ifdef MODULE_GNRC_RPL_P2P + } +#endif + } dodag->my_rank = dodag->instance->of->calc_rank(dodag->parents, 0); diff --git a/sys/net/gnrc/routing/rpl/p2p/Makefile b/sys/net/gnrc/routing/rpl/p2p/Makefile new file mode 100644 index 0000000000..67dc94651f --- /dev/null +++ b/sys/net/gnrc/routing/rpl/p2p/Makefile @@ -0,0 +1,3 @@ +MODULE = gnrc_rpl_p2p + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p.c b/sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p.c new file mode 100644 index 0000000000..9899936bb3 --- /dev/null +++ b/sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p.c @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2016 Cenk Gündoğan + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + * + * @author Cenk Gündoğan + */ + +#include "net/icmpv6.h" +#include "net/gnrc/ipv6.h" +#include "net/gnrc/icmpv6.h" +#include "net/gnrc.h" +#include "net/gnrc/rpl/structs.h" +#include "net/gnrc/rpl/dodag.h" +#include "net/gnrc/rpl/p2p.h" +#include "net/gnrc/rpl/p2p_structs.h" +#include "net/gnrc/rpl/p2p_dodag.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if ENABLE_DEBUG +static char addr_str[IPV6_ADDR_MAX_STR_LEN]; +#endif + +#define GNRC_RPL_P2P_RDO_LEN (18) +#define GNRC_RPL_P2P_RDO_FLAGS_LIFETIME (6) +#define GNRC_RPL_P2P_RDO_FLAGS_HBH (6) +#define GNRC_RPL_P2P_RDO_FLAGS_REPLY (7) +#define GNRC_RPL_P2P_RDO_FLAGS_ADDRNUM (4) +#define GNRC_RPL_P2P_RDO_FLAGS_COMPR (0x0F) +#define GNRC_RPL_P2P_RDO_FLAGS_MAXRANK (0x3F) +#define GNRC_RPL_P2P_RDO_FLAGS_NEXT_HOP (GNRC_RPL_P2P_RDO_FLAGS_MAXRANK) +#define GNRC_RPL_P2P_DRO_FLAGS_SEQ (12) +#define GNRC_RPL_P2P_DRO_FLAGS_ACK (14) +#define GNRC_RPL_P2P_DRO_FLAGS_STOP (15) + +gnrc_rpl_p2p_ext_t gnrc_rpl_p2p_exts[GNRC_RPL_P2P_EXTS_NUMOF]; +const uint8_t gnrc_rpl_p2p_lifetime_lookup[4] = { 1, 4, 16, 64 }; + +void gnrc_rpl_p2p_update(void) +{ + gnrc_rpl_p2p_ext_t *p2p_ext; + for (uint8_t i = 0; i < GNRC_RPL_P2P_EXTS_NUMOF; ++i) { + p2p_ext = &gnrc_rpl_p2p_exts[i]; + if ((p2p_ext->state) && (p2p_ext->lifetime_sec > 0)) { + p2p_ext->lifetime_sec -= GNRC_RPL_LIFETIME_UPDATE_STEP; + if (p2p_ext->lifetime_sec <= 0) { + gnrc_rpl_dodag_remove_all_parents(p2p_ext->dodag); + p2p_ext->dodag->instance->cleanup = GNRC_RPL_CLEANUP_TIME; + continue; + } + p2p_ext->dro_delay -= GNRC_RPL_LIFETIME_UPDATE_STEP; + if (p2p_ext->reply && (p2p_ext->dro_delay < 0) && (p2p_ext->for_me)) { + gnrc_rpl_p2p_send_DRO(NULL, p2p_ext); + } + } + } +} + +gnrc_rpl_instance_t *gnrc_rpl_p2p_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id, + ipv6_addr_t *target, bool gen_inst_id) +{ + if (gen_inst_id) { + instance_id = gnrc_rpl_gen_instance_id(true); + } + + gnrc_rpl_dodag_t *dodag = NULL; + gnrc_rpl_instance_t *instance = gnrc_rpl_root_instance_init(instance_id, dodag_id, + GNRC_RPL_P2P_MOP); + + if (!instance) { + return NULL; + } + + dodag = &instance->dodag; + + instance->max_rank_inc = 0; + dodag->dtsn = 0; + dodag->prf = 0; + dodag->dio_interval_doubl = GNRC_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS; + dodag->dio_min = GNRC_RPL_P2P_DEFAULT_DIO_INTERVAL_MIN; + dodag->dio_redun = GNRC_RPL_P2P_DEFAULT_DIO_REDUNDANCY_CONSTANT; + dodag->default_lifetime = GNRC_RPL_P2P_DEFAULT_LIFETIME; + dodag->lifetime_unit = GNRC_RPL_P2P_LIFETIME_UNIT; + dodag->version = 0; + dodag->grounded = 1; + dodag->node_status = GNRC_RPL_ROOT_NODE; + dodag->my_rank = GNRC_RPL_ROOT_RANK; + dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; + dodag->dio_opts &= ~GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; + + gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag); + p2p_ext->target = *target; + p2p_ext->compr = GNRC_RPL_P2P_COMPR; + p2p_ext->routes_numof = 0; + p2p_ext->hop_by_hop = true; + p2p_ext->reply = true; + p2p_ext->lifetime_enc = GNRC_RPL_P2P_LIFETIME; + p2p_ext->lifetime_sec = gnrc_rpl_p2p_lifetime_lookup[p2p_ext->lifetime_enc]; + p2p_ext->maxrank = GNRC_RPL_P2P_MAX_RANK; + p2p_ext->dro_delay = -1; + + 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); + + return instance; +} + +gnrc_pktsnip_t *gnrc_rpl_p2p_rdo_build(gnrc_pktsnip_t *pkt, gnrc_rpl_p2p_ext_t *p2p_ext) +{ + gnrc_rpl_p2p_opt_rdo_t *rdo; + gnrc_pktsnip_t *opt_snip; + size_t addr_len = (sizeof(ipv6_addr_t) - p2p_ext->compr); + for (uint8_t i = p2p_ext->addr_numof; i > 0; i--) { + if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, addr_len, GNRC_NETTYPE_UNDEF)) == NULL) { + DEBUG("RPL: BUILD RDO - no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + return NULL; + } + memcpy(opt_snip->data, &p2p_ext->addr_vec[i-1], addr_len); + pkt = opt_snip; + } + + if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_p2p_opt_rdo_t), + GNRC_NETTYPE_UNDEF)) == NULL) { + DEBUG("RPL: BUILD RDO - no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + return NULL; + } + rdo = opt_snip->data; + rdo->type = GNRC_RPL_P2P_OPT_RDO; + rdo->length = GNRC_RPL_P2P_RDO_LEN + + p2p_ext->addr_numof * (sizeof(ipv6_addr_t) - p2p_ext->compr); + rdo->compr_flags = (p2p_ext->reply << GNRC_RPL_P2P_RDO_FLAGS_REPLY) | + (p2p_ext->hop_by_hop << GNRC_RPL_P2P_RDO_FLAGS_HBH) + | ((p2p_ext->routes_numof & 0x3) << GNRC_RPL_P2P_RDO_FLAGS_ADDRNUM) + | (p2p_ext->compr & GNRC_RPL_P2P_RDO_FLAGS_COMPR); + rdo->lmn = ((p2p_ext->lifetime_enc & 0x3) << GNRC_RPL_P2P_RDO_FLAGS_LIFETIME) | + (p2p_ext->maxrank & GNRC_RPL_P2P_RDO_FLAGS_MAXRANK); + rdo->target = p2p_ext->target; + return opt_snip; +} + +void gnrc_rpl_p2p_rdo_parse(gnrc_rpl_p2p_opt_rdo_t *rdo, gnrc_rpl_p2p_ext_t *p2p_ext) +{ + DEBUG("RPL: Route Discovery DIO option parsed\n"); + + uint8_t addr_num = (rdo->length - GNRC_RPL_P2P_RDO_LEN) + / (sizeof(ipv6_addr_t) - p2p_ext->compr); + if (addr_num >= GNRC_RPL_P2P_ADDR_VEC_NUMOF) { + DEBUG("RPL: cannot parse RDO - too many hops\n"); + return; + } + + p2p_ext->for_me = (gnrc_ipv6_netif_find_by_addr(NULL, &rdo->target) != KERNEL_PID_UNDEF); + + p2p_ext->reply = (rdo->compr_flags & (1 << GNRC_RPL_P2P_RDO_FLAGS_REPLY)) + >> GNRC_RPL_P2P_RDO_FLAGS_REPLY; + p2p_ext->hop_by_hop = (rdo->compr_flags & (1 << GNRC_RPL_P2P_RDO_FLAGS_HBH)) + >> GNRC_RPL_P2P_RDO_FLAGS_HBH; + p2p_ext->routes_numof = (rdo->compr_flags & (0x3 << GNRC_RPL_P2P_RDO_FLAGS_ADDRNUM)) + >> GNRC_RPL_P2P_RDO_FLAGS_ADDRNUM; + p2p_ext->compr = rdo->compr_flags & GNRC_RPL_P2P_RDO_FLAGS_COMPR; + p2p_ext->lifetime_enc = (rdo->lmn & (0x3 << GNRC_RPL_P2P_RDO_FLAGS_LIFETIME)) + >> GNRC_RPL_P2P_RDO_FLAGS_LIFETIME; + if (p2p_ext->lifetime_sec == INT8_MIN) { + p2p_ext->lifetime_sec = gnrc_rpl_p2p_lifetime_lookup[p2p_ext->lifetime_enc]; + } + p2p_ext->maxrank = rdo->lmn & GNRC_RPL_P2P_RDO_FLAGS_MAXRANK; + p2p_ext->target = rdo->target; + + memset(&p2p_ext->addr_vec, 0, sizeof(ipv6_addr_t) * GNRC_RPL_P2P_ADDR_VEC_NUMOF); + p2p_ext->addr_numof = 0; + uint8_t *tmp = (uint8_t *) (rdo + 1); + uint8_t *addr = NULL; + uint8_t addr_len = sizeof(ipv6_addr_t) - p2p_ext->compr; + uint8_t i = 0; + for (i = 0; i < addr_num; i++) { + addr = ((uint8_t *) &p2p_ext->addr_vec[i]) + p2p_ext->compr; + memcpy(addr, tmp, addr_len); + tmp += addr_len; + p2p_ext->addr_numof++; + } + + if (!p2p_ext->for_me) { + ipv6_addr_t *me = NULL; + if(gnrc_ipv6_netif_find_by_prefix(&me, &p2p_ext->dodag->dodag_id) == KERNEL_PID_UNDEF) { + DEBUG("RPL: no address configured\n"); + return; + } + addr = ((uint8_t *) &p2p_ext->addr_vec[i]) + p2p_ext->compr; + memcpy(addr, ((uint8_t *) me) + p2p_ext->compr, addr_len); + p2p_ext->addr_numof++; + } + else if (p2p_ext->reply) { + p2p_ext->stop = true; + p2p_ext->dro_ack = true; + p2p_ext->dro_delay = GNRC_RPL_P2P_DRO_DELAY; + } +} + +static gnrc_pktsnip_t *_build_initial_DRO(gnrc_rpl_p2p_ext_t *p2p_ext) +{ + gnrc_pktsnip_t *pkt = NULL, *opt_snip = NULL; + gnrc_rpl_p2p_dro_t *dro = NULL; + gnrc_rpl_p2p_opt_rdo_t *rdo = NULL; + size_t addr_len = (sizeof(ipv6_addr_t) - p2p_ext->compr); + uint8_t addr_size = p2p_ext->addr_numof * addr_len; + + for (uint8_t i = p2p_ext->addr_numof; i > 0; i--) { + if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, addr_len, GNRC_NETTYPE_UNDEF)) == NULL) { + DEBUG("RPL-P2P: cannot add addresses to RDO - no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + return NULL; + } + memcpy(opt_snip->data, &p2p_ext->addr_vec[i-1], addr_len); + pkt = opt_snip; + } + + if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_p2p_opt_rdo_t), + GNRC_NETTYPE_UNDEF)) == NULL) { + DEBUG("RPL-P2P: cannot allocate DRO - no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + return NULL; + } + + rdo = opt_snip->data; + rdo->type = GNRC_RPL_P2P_OPT_RDO; + rdo->length = GNRC_RPL_P2P_RDO_LEN + addr_size; + rdo->compr_flags = (p2p_ext->hop_by_hop << GNRC_RPL_P2P_RDO_FLAGS_HBH) | + (p2p_ext->compr & GNRC_RPL_P2P_RDO_FLAGS_COMPR); + /* rdo->length does not include the first two bytes, thus we have to add them manually */ + rdo->lmn = (((rdo->length + 2 - sizeof(*rdo)) / addr_len) & GNRC_RPL_P2P_RDO_FLAGS_NEXT_HOP); + rdo->target = p2p_ext->target; + pkt = opt_snip; + + if ((opt_snip = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_p2p_dro_t), + GNRC_NETTYPE_UNDEF)) == NULL) { + DEBUG("RPL-P2P: cannot allocate RDO - no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + return NULL; + } + dro = opt_snip->data; + dro->instance_id = p2p_ext->dodag->instance->id; + dro->version_number = 0; + dro->flags_rev = byteorder_htons((((p2p_ext->stop << 1) | (p2p_ext->dro_ack << 0)) + << GNRC_RPL_P2P_DRO_FLAGS_ACK) | + ((p2p_ext->dro_seq & 0x3) << GNRC_RPL_P2P_DRO_FLAGS_SEQ)); + dro->dodag_id = p2p_ext->dodag->dodag_id; + pkt = opt_snip; + + if ((opt_snip = gnrc_icmpv6_build(pkt, ICMPV6_RPL_CTRL, GNRC_RPL_P2P_ICMPV6_CODE_DRO, + sizeof(icmpv6_hdr_t))) == NULL) { + DEBUG("RPL-P2P: cannot allocate ICMPv6 - no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + return NULL; + } + + pkt = opt_snip; + + return pkt; +} + +void gnrc_rpl_p2p_send_DRO(gnrc_pktsnip_t *pkt, gnrc_rpl_p2p_ext_t *p2p_ext) +{ + assert(p2p_ext != NULL); + + if (pkt == NULL) { + if ((pkt = _build_initial_DRO(p2p_ext)) == NULL) { + DEBUG("RPL-P2P: BUILD INITIAL DRO - no space left in packet buffer\n"); + return; + } + } + + gnrc_rpl_send(pkt, p2p_ext->dodag->iface, NULL, NULL, &p2p_ext->dodag->dodag_id); + + return; +} + +void gnrc_rpl_p2p_recv_DRO(gnrc_pktsnip_t *pkt, ipv6_addr_t *src) +{ + gnrc_pktsnip_t *icmpv6_snip = gnrc_pktbuf_mark(pkt, sizeof(icmpv6_hdr_t), GNRC_NETTYPE_ICMPV6); + gnrc_pktsnip_t *dro_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_dro_t), + GNRC_NETTYPE_UNDEF); + gnrc_pktsnip_t *rdo_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_opt_rdo_t), + GNRC_NETTYPE_UNDEF); + gnrc_pktsnip_t *addr_snip = pkt; + gnrc_rpl_instance_t *inst; + gnrc_rpl_dodag_t *dodag; + gnrc_rpl_p2p_ext_t *p2p_ext; + gnrc_rpl_p2p_dro_t *dro; + gnrc_rpl_p2p_opt_rdo_t *rdo; + uint8_t *addr_vec; + uint16_t flags; + size_t addr_len; + + if (!rdo_snip || !dro_snip) { + DEBUG("RPL-P2P: Error - No DRO or RDO received\n"); + gnrc_pktbuf_release(pkt); + return; + } + + dro = dro_snip->data; + + if ((inst = gnrc_rpl_instance_get(dro->instance_id)) == NULL) { + DEBUG("RPL-P2P: Error - Instance (%d) does not exist\n", dro->instance_id); + return; + } + + dodag = &inst->dodag; + + if ((p2p_ext = gnrc_rpl_p2p_ext_get(dodag)) == NULL) { + DEBUG("RPL-P2P: Error - No P2P-RPL DODAG extension found\n"); + return; + } + + if (p2p_ext->for_me) { + DEBUG("RPL-P2P: Ignore DRO\n"); + return; + } + + flags = byteorder_ntohs(dro->flags_rev); + p2p_ext->stop = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_STOP)) >> GNRC_RPL_P2P_DRO_FLAGS_STOP; + p2p_ext->dro_ack = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_ACK)) >> GNRC_RPL_P2P_DRO_FLAGS_ACK; + p2p_ext->dro_seq = (flags & (0x3 << GNRC_RPL_P2P_DRO_FLAGS_SEQ)) >> GNRC_RPL_P2P_DRO_FLAGS_SEQ; + + addr_len = sizeof(ipv6_addr_t) - p2p_ext->compr; + ipv6_addr_t addr = p2p_ext->dodag->dodag_id; + ipv6_addr_t *me = NULL; + addr_vec = addr_snip->data; + + rdo = rdo_snip->data; + + if (rdo->lmn > 0) { + rdo->lmn--; + memcpy(&addr.u8[p2p_ext->compr], &addr_vec[addr_len * rdo->lmn], addr_len); + } + + if (gnrc_ipv6_netif_find_by_addr(&me, &addr) == dodag->iface) { + fib_add_entry(&gnrc_ipv6_fib_table, dodag->iface, p2p_ext->target.u8, + sizeof(ipv6_addr_t), FIB_FLAG_NET_PREFIX, src->u8, + sizeof(ipv6_addr_t), FIB_FLAG_RPL_ROUTE, + p2p_ext->dodag->default_lifetime * + p2p_ext->dodag->lifetime_unit * SEC_IN_MS); + + if (p2p_ext->dodag->node_status != GNRC_RPL_ROOT_NODE) { + if ((rdo_snip = gnrc_pktbuf_start_write(rdo_snip)) == NULL) { + DEBUG("RPL-P2P: Error - Cannot allocate new RDO\n"); + return; + } + + addr_snip->next = NULL; + rdo_snip->next = addr_snip; + dro_snip->next = rdo_snip; + + icmpv6_snip = gnrc_icmpv6_build(dro_snip, ICMPV6_RPL_CTRL, GNRC_RPL_P2P_ICMPV6_CODE_DRO, + sizeof(icmpv6_hdr_t)); + if (icmpv6_snip == NULL) { + DEBUG("RPL-P2P: cannot allocate ICMPv6 - no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + return; + } + + gnrc_rpl_send(icmpv6_snip, p2p_ext->dodag->iface, NULL, NULL, &p2p_ext->dodag->dodag_id); + return; + } + } + + gnrc_pktbuf_release(pkt); + + return; +} + +/** + * @} + */ diff --git a/sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p_dodag.c b/sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p_dodag.c new file mode 100644 index 0000000000..3d4b93f9b5 --- /dev/null +++ b/sys/net/gnrc/routing/rpl/p2p/gnrc_rpl_p2p_dodag.c @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2016 Cenk Gündoğan + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + * @author Cenk Gündoğan + */ + +#include +#include "net/gnrc/rpl/structs.h" +#include "net/gnrc/rpl/p2p.h" +#include "net/gnrc/rpl/p2p_dodag.h" +#include "net/gnrc/rpl/p2p_structs.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +gnrc_rpl_p2p_ext_t *gnrc_rpl_p2p_ext_new(gnrc_rpl_dodag_t *dodag) +{ + for (uint8_t i = 0; i < GNRC_RPL_P2P_EXTS_NUMOF; ++i) { + if (!gnrc_rpl_p2p_exts[i].state) { + gnrc_rpl_p2p_exts[i].state = true; + gnrc_rpl_p2p_exts[i].dodag = dodag; + gnrc_rpl_p2p_exts[i].dro_delay = -1; + gnrc_rpl_p2p_exts[i].lifetime_sec = INT8_MIN; + return &gnrc_rpl_p2p_exts[i]; + } + } + + /* no space available to allocate a P2P-RPL DODAG extension */ + DEBUG("RPL-P2P: Could not a new P2P-RPL DODAG extension\n"); + return NULL; +} + +void gnrc_rpl_p2p_ext_remove(gnrc_rpl_dodag_t *dodag) +{ + for (uint8_t i = 0; i < GNRC_RPL_P2P_EXTS_NUMOF; ++i) { + if ((gnrc_rpl_p2p_exts[i].state) && (gnrc_rpl_p2p_exts[i].dodag == dodag)) { + memset(&gnrc_rpl_p2p_exts[i], 0, sizeof(gnrc_rpl_p2p_ext_t)); + return; + } + } +} + +gnrc_rpl_p2p_ext_t *gnrc_rpl_p2p_ext_get(gnrc_rpl_dodag_t *dodag) +{ + for (uint8_t i = 0; i < GNRC_RPL_P2P_EXTS_NUMOF; ++i) { + if ((gnrc_rpl_p2p_exts[i].state) && (gnrc_rpl_p2p_exts[i].dodag == dodag)) { + return &gnrc_rpl_p2p_exts[i]; + } + } + return NULL; +} +/** + * @} + */ diff --git a/sys/shell/commands/sc_gnrc_rpl.c b/sys/shell/commands/sc_gnrc_rpl.c index 33252d500a..c3fce2c68f 100644 --- a/sys/shell/commands/sc_gnrc_rpl.c +++ b/sys/shell/commands/sc_gnrc_rpl.c @@ -63,6 +63,36 @@ int _gnrc_rpl_dodag_root(char *arg1, char *arg2) return 0; } +#ifdef MODULE_GNRC_RPL_P2P +int _gnrc_rpl_find(char *arg1, char *arg2) +{ + uint8_t instance_id = (uint8_t) atoi(arg1); + ipv6_addr_t dodag_id; + ipv6_addr_t target; + + if (ipv6_addr_from_str(&dodag_id, arg1) == NULL) { + puts(" must be a valid IPv6 address"); + return 1; + } + + if (ipv6_addr_from_str(&target, arg2) == NULL) { + puts(" must be a valid IPv6 address"); + return 1; + } + + gnrc_rpl_instance_t *instance = NULL; + if ((instance = gnrc_rpl_p2p_root_init(0, &dodag_id, &target, true)) == NULL) { + char addr_str[IPV6_ADDR_MAX_STR_LEN]; + printf("error: could not add DODAG (%s) to instance (%d)\n", + ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)), instance_id); + return 1; + } + + printf("successfully initiated a P2P-RPL Route Discovery\n"); + return 0; +} +#endif + int _gnrc_rpl_instance_remove(char *arg1) { uint8_t instance_id = (uint8_t) atoi(arg1); From c8c8a183d9273c711ab1cbef3b20e3feddf85d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cenk=20G=C3=BCndo=C4=9Fan?= Date: Mon, 24 Aug 2015 10:27:04 +0200 Subject: [PATCH 2/2] rpl: p2p-rpl shell extension --- sys/shell/commands/sc_gnrc_rpl.c | 43 ++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/sys/shell/commands/sc_gnrc_rpl.c b/sys/shell/commands/sc_gnrc_rpl.c index c3fce2c68f..eb3e339a2f 100644 --- a/sys/shell/commands/sc_gnrc_rpl.c +++ b/sys/shell/commands/sc_gnrc_rpl.c @@ -23,6 +23,11 @@ #include "net/gnrc/rpl/dodag.h" #include "utlist.h" #include "trickle.h" +#ifdef MODULE_GNRC_RPL_P2P +#include "net/gnrc/rpl/p2p.h" +#include "net/gnrc/rpl/p2p_dodag.h" +#include "net/gnrc/rpl/p2p_structs.h" +#endif int _gnrc_rpl_init(char *arg) { @@ -80,8 +85,7 @@ int _gnrc_rpl_find(char *arg1, char *arg2) return 1; } - gnrc_rpl_instance_t *instance = NULL; - if ((instance = gnrc_rpl_p2p_root_init(0, &dodag_id, &target, true)) == NULL) { + if (gnrc_rpl_p2p_root_init(0, &dodag_id, &target, true) == NULL) { char addr_str[IPV6_ADDR_MAX_STR_LEN]; printf("error: could not add DODAG (%s) to instance (%d)\n", ipv6_addr_to_str(addr_str, &dodag_id, sizeof(addr_str)), instance_id); @@ -203,7 +207,22 @@ int _gnrc_rpl_dodag_show(void) } putchar('\t'); } + putchar('\n'); + +#ifdef MODULE_GNRC_RPL_P2P + printf("p2p-rpl table:\t"); + for (int8_t i = 0; i < GNRC_RPL_P2P_EXTS_NUMOF; ++i) { + if (gnrc_rpl_p2p_exts[i].state == 0) { + printf("[ ]"); + } + else { + printf("[X]"); + } + putchar('\t'); + } +#endif + putchar('\n'); gnrc_rpl_dodag_t *dodag = NULL; @@ -241,6 +260,16 @@ int _gnrc_rpl_dodag_show(void) (int) cleanup, (1 << dodag->dio_min), dodag->dio_interval_doubl, dodag->trickle.k, dodag->trickle.c, (uint32_t) (tc & 0xFFFFFFFF), (uint32_t) (ti & 0xFFFFFFFF)); +#ifdef MODULE_GNRC_RPL_P2P + if (dodag->instance->mop == GNRC_RPL_P2P_MOP) { + gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag); + printf("\tP2P-Ext [%s | HBH: %s | R: %s | L: %us]\n", + ipv6_addr_to_str(addr_str, &p2p_ext->target, sizeof(addr_str)), + p2p_ext->hop_by_hop ? "True" : "False", + p2p_ext->reply ? "True" : "False", p2p_ext->lifetime_sec); + } +#endif + gnrc_rpl_parent_t *parent; LL_FOREACH(gnrc_rpl_instances[i].dodag.parents, parent) { printf("\t\tparent [addr: %s | rank: %d | lifetime: %" PRIu32 "s]\n", @@ -347,7 +376,17 @@ int _gnrc_rpl(int argc, char **argv) #endif } } +#ifdef MODULE_GNRC_RPL_P2P + else if (strcmp(argv[1], "find") == 0) { + if (argc == 4) { + return _gnrc_rpl_find(argv[2], argv[3]); + } + } +#endif +#ifdef MODULE_GNRC_RPL_P2P + puts("* find \t\t\t- initiate a P2P-RPL route discovery"); +#endif puts("* help\t\t\t\t\t- show usage"); puts("* init \t\t\t\t- initialize RPL on the given interface"); puts("* leaf \t\t\t- operate as leaf in the instance");