
15 changed files with 2427 additions and 14 deletions
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2013 INRIA. |
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com> |
||||
* |
||||
* 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_ng_rpl |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief DODAG-related functions for RPL |
||||
* |
||||
* Header file, which defines all public known DODAG-related functions for RPL. |
||||
* |
||||
* @author Eric Engel <eric.engel@fu-berlin.de> |
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com> |
||||
*/ |
||||
|
||||
#ifndef NG_RPL_DODAG_H_ |
||||
#define NG_RPL_DODAG_H_ |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#include "net/ng_ipv6.h" |
||||
#include "trickle.h" |
||||
#include "net/ng_rpl.h" |
||||
#include "net/ng_rpl/structs.h" |
||||
|
||||
/**
|
||||
* @brief Number of RPL instances |
||||
*/ |
||||
#ifndef NG_RPL_INSTANCES_NUMOF |
||||
#define NG_RPL_INSTANCES_NUMOF (2) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Number of RPL dodags |
||||
*/ |
||||
#ifndef NG_RPL_DODAGS_NUMOF |
||||
#define NG_RPL_DODAGS_NUMOF (4) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Number of RPL parents |
||||
*/ |
||||
#ifndef NG_RPL_PARENTS_NUMOF |
||||
#define NG_RPL_PARENTS_NUMOF (6) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief RPL instance table |
||||
*/ |
||||
extern ng_rpl_instance_t ng_rpl_instances[NG_RPL_INSTANCES_NUMOF]; |
||||
|
||||
/**
|
||||
* @brief RPL DODAG table |
||||
*/ |
||||
extern ng_rpl_dodag_t ng_rpl_dodags[NG_RPL_DODAGS_NUMOF]; |
||||
|
||||
/**
|
||||
* @brief RPL parent table |
||||
*/ |
||||
extern ng_rpl_parent_t ng_rpl_parents[NG_RPL_PARENTS_NUMOF]; |
||||
|
||||
/**
|
||||
* @brief Add a new RPL instance with the id @p instance_id. |
||||
* |
||||
* @param[in] instance_id The instance id of the new RPL instance. |
||||
* @param[out] inst Pointer to an existing or new instance. Otherwise NULL. |
||||
* |
||||
* @return true, if instance could be created. |
||||
* @return false, if instance could not be created or exists already. |
||||
*/ |
||||
bool ng_rpl_instance_add(uint8_t instance_id, ng_rpl_instance_t **inst); |
||||
|
||||
/**
|
||||
* @brief Remove a RPL instance with the id @p instance_id. |
||||
* |
||||
* @param[in] instance_id The instance id of the RPL instance to remove. |
||||
* |
||||
* @return true, on success. |
||||
* @return false, otherwise. |
||||
*/ |
||||
bool ng_rpl_instance_remove_by_id(uint8_t instance_id); |
||||
|
||||
/**
|
||||
* @brief Remove a RPL instance with the pointer @p inst. |
||||
* |
||||
* @param[in] inst Pointer to the the RPL instance to remove. |
||||
* |
||||
* @return true, on success. |
||||
* @return false, otherwise. |
||||
*/ |
||||
bool ng_rpl_instance_remove(ng_rpl_instance_t *inst); |
||||
|
||||
/**
|
||||
* @brief Get the RPL instance with the id @p instance_id. |
||||
* |
||||
* @param[in] instance_id The instance id of the RPL instance to get. |
||||
* |
||||
* @return Pointer to the RPL instance, on success. |
||||
* @return NULL, otherwise. |
||||
*/ |
||||
ng_rpl_instance_t *ng_rpl_instance_get(uint8_t instance_id); |
||||
|
||||
/**
|
||||
* @brief Add a new RPL DODAG with the id @p dodag_id to the instance @p instance. |
||||
* |
||||
* @param[in] instance Pointer to the instance to add the DODAG to |
||||
* @param[in] dodag_id The DODAG-ID of the new DODAG |
||||
* @param[out] dodag Pointer to an existing or new DODAG. Otherwise NULL. |
||||
* |
||||
* @return true, if DODAG could be created. |
||||
* @return false, if DODAG could not be created or exists already. |
||||
*/ |
||||
bool ng_rpl_dodag_add(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id, ng_rpl_dodag_t **dodag); |
||||
|
||||
/**
|
||||
* @brief Remove the RPL DODAG @p dodag. |
||||
* |
||||
* @param[in] dodag Pointer to the dodag. |
||||
* |
||||
* @return true, on success. |
||||
* @return false, otherwise. |
||||
*/ |
||||
bool ng_rpl_dodag_remove(ng_rpl_dodag_t *dodag); |
||||
|
||||
/**
|
||||
* @brief Remove all parents from the @p dodag. |
||||
* |
||||
* @param[in] dodag Pointer to the dodag. |
||||
*/ |
||||
void ng_rpl_dodag_remove_all_parents(ng_rpl_dodag_t *dodag); |
||||
|
||||
/**
|
||||
* @brief Get the RPL DODAG with the id @p dodag_id to the instance @p instance. |
||||
* |
||||
* @param[in] instance Pointer to the instance of the RPL DODAG |
||||
* @param[in] dodag_id The DODAG-ID of the RPL DODAG |
||||
* |
||||
* @return Pointer to the existing RPL DODAG, on success. |
||||
* @return NULL, otherwise. |
||||
*/ |
||||
ng_rpl_dodag_t *ng_rpl_dodag_get(ng_rpl_instance_t *instance, ipv6_addr_t *dodag_id); |
||||
|
||||
/**
|
||||
* @brief Add a new parent with the IPv6 address @p addr to the @p dodag. |
||||
* |
||||
* @param[in] dodag Pointer to the DODAG |
||||
* @param[in] addr IPV6 address of the parent |
||||
* @param[out] parent Pointer to an existing or new parent. Otherwise NULL. |
||||
* |
||||
* @return true. if parent could be created. |
||||
* @return false, if parent could not be created or exists already. |
||||
*/ |
||||
bool ng_rpl_parent_add_by_addr(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr, ng_rpl_parent_t **parent); |
||||
|
||||
/**
|
||||
* @brief Remove the @p parent from its DODAG. |
||||
* |
||||
* @param[in] parent Pointer to the parent. |
||||
* |
||||
* @return true, on success. |
||||
* @return false, otherwise. |
||||
*/ |
||||
bool ng_rpl_parent_remove(ng_rpl_parent_t *parent); |
||||
|
||||
/**
|
||||
* @brief Get a parent with the IPv6 addr @p addr of the DODAG @p dodag. |
||||
* |
||||
* @param[in] dodag Pointer to the DODAG |
||||
* @param[in] addr IPv6 address of the parent |
||||
* |
||||
* @return Pointer to the existing parent, on success. |
||||
* @return NULL, otherwise. |
||||
*/ |
||||
ng_rpl_parent_t *ng_rpl_parent_get(ng_rpl_dodag_t *dodag, ipv6_addr_t *addr); |
||||
|
||||
/**
|
||||
* @brief Update a @p parent of the @p dodag. |
||||
* |
||||
* @param[in] dodag Pointer to the DODAG |
||||
* @param[in] parent Pointer to the parent |
||||
*/ |
||||
void ng_rpl_parent_update(ng_rpl_dodag_t *dodag, ng_rpl_parent_t *parent); |
||||
|
||||
/**
|
||||
* @brief Find the parent with the lowest rank and update the DODAG's preferred parent |
||||
* |
||||
* @param[in] dodag Pointer to the DODAG |
||||
* |
||||
* @return Pointer to the preferred parent, on success. |
||||
* @return NULL, otherwise. |
||||
*/ |
||||
ng_rpl_parent_t *ng_rpl_find_preferred_parent(ng_rpl_dodag_t *dodag); |
||||
|
||||
/**
|
||||
* @brief Start a local repair. |
||||
* |
||||
* @param[in] dodag Pointer to the DODAG |
||||
*/ |
||||
void ng_rpl_local_repair(ng_rpl_dodag_t *dodag); |
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NG_RPL_DODAG_H_ */ |
||||
/**
|
||||
* @} |
||||
*/ |
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin |
||||
* |
||||
* 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_ng_rpl |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief RPL Objective functions manager header |
||||
* |
||||
* @author Fabian Brandt <fabianbr@zedat.fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef RPL_OFM_H |
||||
#define RPL_OFM_H |
||||
|
||||
#include "structs.h" |
||||
#include "net/ng_ipv6.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Initialization of Manager and of-functions. |
||||
*/ |
||||
void ng_rpl_of_manager_init(void); |
||||
|
||||
/**
|
||||
* @brief Returns objective function with a given cope point |
||||
* @param[in] ocp Objective code point of objective function |
||||
* @return Pointer of corresponding objective function implementation |
||||
*/ |
||||
ng_rpl_of_t *ng_rpl_get_of_for_ocp(uint16_t ocp); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* RPL_OFM_H */ |
||||
/** @} */ |
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (C) 2013 INRIA. |
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com> |
||||
* |
||||
* 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_ng_rpl |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief RPL data structs |
||||
* |
||||
* Header file, which defines all structs used by RPL. |
||||
* |
||||
* @author Eric Engel <eric.engel@fu-berlin.de> |
||||
* @author Cenk Gündoğan <cnkgndgn@gmail.com> |
||||
*/ |
||||
|
||||
#ifndef NG_RPL_STRUCTS_H_ |
||||
#define NG_RPL_STRUCTS_H_ |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#include "net/ng_ipv6.h" |
||||
#include "trickle.h" |
||||
|
||||
/**
|
||||
* @brief RPL-Option Generic Format |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.1"> |
||||
* RPL Control Message Option Generic Format |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t type; /**< Option Type */ |
||||
uint8_t length; /**< Option Length, does not include the first two byte */ |
||||
} ng_rpl_opt_t; |
||||
|
||||
/**
|
||||
* @brief DIO Base Object |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.3.1"> |
||||
* Format of the DIO Base Object |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t instance_id; /**< id of the instance */ |
||||
uint8_t version_number; /**< version number of the DODAG */ |
||||
network_uint16_t rank; /**< rank of the parent emitting the DIO */ |
||||
uint8_t g_mop_prf; /**< grounded, MOP, preferred flags */ |
||||
uint8_t dtsn; /**< Destination Advertisement Trigger Sequence Number */ |
||||
uint8_t flags; /**< unused */ |
||||
uint8_t reserved; /**< reserved */ |
||||
ipv6_addr_t dodag_id; /**< id of the dodag */ |
||||
} ng_rpl_dio_t; |
||||
|
||||
/**
|
||||
* @brief DODAG Configuration Option |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.6"> |
||||
* DODAG Configuration |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t type; /**< Option Type: 0x04 */ |
||||
uint8_t length; /**< length of option, not including first two bytes */ |
||||
uint8_t flags_a_pcs; /**< flags */ |
||||
uint8_t dio_int_doubl; /**< trickle Imax parameter */ |
||||
uint8_t dio_int_min; /**< trickle Imin parameter */ |
||||
uint8_t dio_redun; /**< trickle k parameter */ |
||||
network_uint16_t max_rank_inc; /**< allowable increase in rank */ |
||||
network_uint16_t min_hop_rank_inc; /**< DAGRank(rank) = floor(rank/MinHopRankIncrease) */ |
||||
network_uint16_t ocp; /**< Objective Code Point */ |
||||
uint8_t reserved; /**< reserved */ |
||||
uint8_t default_lifetime; /**< lifetime of RPL routes (lifetime * lifetime_unit) */ |
||||
network_uint16_t lifetime_unit; /**< unit in seconds */ |
||||
} ng_rpl_opt_dodag_conf_t; |
||||
|
||||
/**
|
||||
* @brief DODAG Information Solicitation |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.2"> |
||||
* DODAG Information Solicitation |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t flags; /**< unused */ |
||||
uint8_t reserved; /**< reserved */ |
||||
} ng_rpl_dis_t; |
||||
|
||||
/**
|
||||
* @brief Destination Advertisement Object |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.4"> |
||||
* Destination Advertisement Object |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t instance_id; /**< id of the instance */ |
||||
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 */ |
||||
} ng_rpl_dao_t; |
||||
|
||||
/**
|
||||
* @brief Destination Advertisement Object Acknowledgement |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.5"> |
||||
* Destination Advertisement Object Acknowledgement |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t instance_id; /**< id of the instance */ |
||||
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 */ |
||||
} ng_rpl_dao_ack_t; |
||||
|
||||
/**
|
||||
* @brief Target Option |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.7"> |
||||
* RPL Target |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t type; /**< option type */ |
||||
uint8_t length; /**< option length without the first two bytes */ |
||||
uint8_t flags; /**< unused */ |
||||
uint8_t prefix_length; /**< number of valid leading bits in the IPv6 prefix */ |
||||
ipv6_addr_t target; /**< IPv6 prefix, address or multicast group */ |
||||
} ng_rpl_opt_target_t; |
||||
|
||||
/**
|
||||
* @brief Transit Option |
||||
* @see <a href="https://tools.ietf.org/html/rfc6550#section-6.7.8"> |
||||
* Transit Information |
||||
* </a> |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
uint8_t type; /**< option type */ |
||||
uint8_t length; /**< option length without the first two bytes */ |
||||
uint8_t e_flags; /**< external flag indicates external routes */ |
||||
uint8_t path_control; /**< limits the number of DAO parents */ |
||||
uint8_t path_sequence; /**< increased value for route updates */ |
||||
uint8_t path_lifetime; /**< lifetime of routes */ |
||||
} ng_rpl_opt_transit_t; |
||||
|
||||
typedef struct ng_rpl_dodag ng_rpl_dodag_t; |
||||
typedef struct ng_rpl_parent ng_rpl_parent_t; |
||||
|
||||
/**
|
||||
* @brief Parent representation |
||||
*/ |
||||
struct ng_rpl_parent { |
||||
ng_rpl_parent_t *next; /**< pointer to the next parent */ |
||||
uint8_t state; /**< 0 for unsued, 1 for used */ |
||||
ipv6_addr_t addr; /**< link-local IPv6 address of this parent */ |
||||
uint16_t rank; /**< rank of the parent */ |
||||
uint8_t dtsn; /**< last seen dtsn of this parent */ |
||||
ng_rpl_dodag_t *dodag; /**< DODAG the parent belongs to */ |
||||
timex_t lifetime; /**< lifetime of this parent */ |
||||
double link_metric; /**< metric of the link */ |
||||
uint8_t link_metric_type; /**< type of the metric */ |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Objective function representation |
||||
*/ |
||||
typedef struct { |
||||
uint16_t ocp; /**< objective code point */ |
||||
uint16_t (*calc_rank)(ng_rpl_parent_t *parent, uint16_t base_rank); /**< calculate the rank */ |
||||
ng_rpl_parent_t *(*which_parent)(ng_rpl_parent_t *, ng_rpl_parent_t *); /**< compare for parents */ |
||||
ng_rpl_dodag_t *(*which_dodag)(ng_rpl_dodag_t *, ng_rpl_dodag_t *); /**< compare for dodags */ |
||||
void (*reset)(ng_rpl_dodag_t *); /**< resets the OF */ |
||||
void (*parent_state_callback)(ng_rpl_parent_t *, int, int); /**< retrieves the state of a parent*/ |
||||
void (*init)(void); /**< OF specific init function */ |
||||
void (*process_dio)(void); /**< DIO processing callback (acc. to OF0 spec, chpt 5) */ |
||||
} ng_rpl_of_t; |
||||
|
||||
|
||||
/**
|
||||
* @brief Instance representation |
||||
*/ |
||||
typedef struct { |
||||
uint8_t id; /**< id of the instance */ |
||||
uint8_t state; /**< 0 for unused, 1 for used */ |
||||
ng_rpl_dodag_t *dodags; /**< pointer to the DODAG list of this instance */ |
||||
uint8_t mop; /**< configured Mode of Operation */ |
||||
ng_rpl_of_t *of; /**< configured Objective Function */ |
||||
uint16_t min_hop_rank_inc; /**< minimum hop rank increase */ |
||||
uint16_t max_rank_inc; /**< max increase in the rank */ |
||||
} ng_rpl_instance_t; |
||||
|
||||
/**
|
||||
* @brief DODAG representation |
||||
*/ |
||||
struct ng_rpl_dodag { |
||||
ng_rpl_instance_t *instance; /**< id of the instance */ |
||||
ng_rpl_dodag_t *next; /**< pointer to the next dodag */ |
||||
ng_rpl_parent_t *parents; /**< pointer to the parents list of this DODAG */ |
||||
ipv6_addr_t dodag_id; /**< id of the DODAG */ |
||||
uint8_t state; /**< 0 for unused, 1 for used */ |
||||
uint8_t dtsn; /**< DAO Trigger Sequence Number */ |
||||
uint8_t prf; /**< preferred flag */ |
||||
uint8_t dio_interval_doubl; /**< trickle Imax parameter */ |
||||
uint8_t dio_min; /**< trickle Imin parameter */ |
||||
uint8_t dio_redun; /**< trickle k parameter */ |
||||
uint8_t default_lifetime; /**< lifetime of routes (lifetime * unit) */ |
||||
uint16_t lifetime_unit; /**< unit in seconds of the lifetime */ |
||||
uint8_t version; /**< version of this DODAG */ |
||||
uint8_t grounded; /**< grounded flag */ |
||||
uint16_t my_rank; /**< rank/position in the DODAG */ |
||||
uint8_t node_status; /**< leaf, normal, or root node */ |
||||
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 */ |
||||
timex_t dao_time; /**< time to schedule the next DAO */ |
||||
vtimer_t dao_timer; /**< timer to schedule the next DAO */ |
||||
timex_t cleanup_time; /**< time to schedula a DODAG cleanup */ |
||||
vtimer_t cleanup_timer; /**< timer to schedula a DODAG cleanup */ |
||||
trickle_t trickle; /**< trickle representation */ |
||||
}; |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NG_RPL_STRUCTS_H_ */ |
||||
/**
|
||||
* @} |
||||
*/ |
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com> |
||||
* |
||||
* 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 <cnkgndgn@gmail.com> |
||||
*/ |
||||
#include "net/ng_rpl.h" |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
#if ENABLE_DEBUG && defined(MODULE_IPV6_ADDR) |
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN]; |
||||
#endif |
||||
|
||||
static char _stack[NG_RPL_STACK_SIZE]; |
||||
kernel_pid_t ng_rpl_pid = KERNEL_PID_UNDEF; |
||||
static timex_t _lt_time; |
||||
static vtimer_t _lt_timer; |
||||
static msg_t _msg_q[NG_RPL_MSG_QUEUE_SIZE]; |
||||
static ng_netreg_entry_t _me_reg; |
||||
|
||||
ng_rpl_instance_t ng_rpl_instances[NG_RPL_INSTANCES_NUMOF]; |
||||
ng_rpl_dodag_t ng_rpl_dodags[NG_RPL_DODAGS_NUMOF]; |
||||
ng_rpl_parent_t ng_rpl_parents[NG_RPL_PARENTS_NUMOF]; |
||||
|
||||
static void _update_lifetime(void); |
||||
static void _dao_handle_send(ng_rpl_dodag_t *dodag); |
||||
static void _receive(ng_pktsnip_t *pkt); |
||||
static void *_event_loop(void *args); |
||||
static ng_rpl_dodag_t *_root_dodag_init(uint8_t instance_id, ipv6_addr_t *dodag_id, uint8_t mop); |
||||
|
||||
kernel_pid_t ng_rpl_init(kernel_pid_t if_pid) |
||||
{ |
||||
/* check if RPL was initialized before */ |
||||
if (ng_rpl_pid == KERNEL_PID_UNDEF) { |
||||
/* start the event loop */ |
||||
ng_rpl_pid = thread_create(_stack, sizeof(_stack), NG_RPL_PRIO, CREATE_STACKTEST, |
||||
_event_loop, NULL, "RPL"); |
||||
|
||||
if (ng_rpl_pid == KERNEL_PID_UNDEF) { |
||||
DEBUG("RPL: could not start the event loop\n"); |
||||
return KERNEL_PID_UNDEF; |
||||
} |
||||
|
||||
_me_reg.demux_ctx = NG_ICMPV6_RPL_CTRL; |
||||
_me_reg.pid = ng_rpl_pid; |
||||
/* register interest in all ICMPv6 packets */ |
||||
ng_netreg_register(NG_NETTYPE_ICMPV6, &_me_reg); |
||||
|
||||
ng_rpl_of_manager_init(); |
||||
_lt_time = timex_set(NG_RPL_LIFETIME_UPDATE_STEP, 0); |
||||
vtimer_set_msg(&_lt_timer, _lt_time, ng_rpl_pid, NG_RPL_MSG_TYPE_LIFETIME_UPDATE, NULL); |
||||
} |
||||
|
||||
/* register all_RPL_nodes multicast address */ |
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES; |
||||
ng_ipv6_netif_add_addr(if_pid, &all_RPL_nodes, IPV6_ADDR_BIT_LEN, 0); |
||||
|
||||
ng_rpl_send_DIS(NULL, &all_RPL_nodes); |
||||
return ng_rpl_pid; |
||||
} |
||||
|
||||
ng_rpl_dodag_t *ng_rpl_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id) |
||||
{ |
||||
ng_rpl_dodag_t *dodag = _root_dodag_init(instance_id, dodag_id, NG_RPL_DEFAULT_MOP); |
||||
|
||||
if (!dodag) { |
||||
return NULL; |
||||
} |
||||
|
||||
dodag->dtsn = 1; |
||||
dodag->prf = 0; |
||||
dodag->dio_interval_doubl = NG_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS; |
||||
dodag->dio_min = NG_RPL_DEFAULT_DIO_INTERVAL_MIN; |
||||
dodag->dio_redun = NG_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT; |
||||
dodag->default_lifetime = NG_RPL_DEFAULT_LIFETIME; |
||||
dodag->lifetime_unit = NG_RPL_LIFETIME_UNIT; |
||||
dodag->version = NG_RPL_COUNTER_INIT; |
||||
dodag->grounded = NG_RPL_GROUNDED; |
||||
dodag->node_status = NG_RPL_ROOT_NODE; |
||||
dodag->my_rank = NG_RPL_ROOT_RANK; |
||||
|
||||
trickle_start(ng_rpl_pid, &dodag->trickle, NG_RPL_MSG_TYPE_TRICKLE_INTERVAL, |
||||
NG_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), |
||||
dodag->dio_interval_doubl, dodag->dio_redun); |
||||
|
||||
return dodag; |
||||
} |
||||
|
||||
static ng_rpl_dodag_t *_root_dodag_init(uint8_t instance_id, ipv6_addr_t *dodag_id, uint8_t mop) |
||||
{ |
||||
if (ng_rpl_pid == KERNEL_PID_UNDEF) { |
||||
DEBUG("RPL: RPL thread not started\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
ipv6_addr_t *configured_addr; |
||||
ng_rpl_instance_t *inst = NULL; |
||||
ng_rpl_dodag_t *dodag = NULL; |
||||
|
||||
if (instance_id == 0) { |
||||
DEBUG("RPL: instance id (%d) must be a positive number greater than zero\n", instance_id); |
||||
return NULL; |
||||
} |
||||
|
||||
if (ng_ipv6_netif_find_by_addr(&configured_addr, dodag_id) == KERNEL_PID_UNDEF) { |
||||
DEBUG("RPL: no IPv6 address configured to match the given dodag id: %s\n", |
||||
ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str))); |
||||
return NULL; |
||||
} |
||||
|
||||
if (ng_rpl_instance_add(instance_id, &inst)) { |
||||
inst->of = (ng_rpl_of_t *) ng_rpl_get_of_for_ocp(NG_RPL_DEFAULT_OCP); |
||||
inst->mop = mop; |
||||
inst->min_hop_rank_inc = NG_RPL_DEFAULT_MIN_HOP_RANK_INCREASE; |
||||
inst->max_rank_inc = NG_RPL_DEFAULT_MAX_RANK_INCREASE; |
||||
} |
||||
else if (inst == NULL) { |
||||
DEBUG("RPL: could not allocate memory for a new instance with id %d", instance_id); |
||||
return NULL; |
||||
} |
||||
else if (inst->mop != mop) { |
||||
DEBUG("RPL: instance (%d) exists with another MOP", instance_id); |
||||
return NULL; |
||||
} |
||||
|
||||
if (!ng_rpl_dodag_add(inst, dodag_id, &dodag)) { |
||||
DEBUG("RPL: DODAG with id %s exists or no memory left for a new DODAG", |
||||
ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str))); |
||||
return NULL; |
||||
} |
||||
|
||||
return dodag; |
||||
} |
||||
|
||||
static void _receive(ng_pktsnip_t *icmpv6) |
||||
{ |
||||
ng_pktsnip_t *ipv6 = NULL; |
||||
ipv6_hdr_t *ipv6_hdr = NULL; |
||||
ng_icmpv6_hdr_t *icmpv6_hdr = NULL; |
||||
|
||||
LL_SEARCH_SCALAR(icmpv6, ipv6, type, NG_NETTYPE_IPV6); |
||||
ipv6_hdr = (ipv6_hdr_t *)ipv6->data; |
||||
|
||||
icmpv6_hdr = (ng_icmpv6_hdr_t *)icmpv6->data; |
||||
switch (icmpv6_hdr->code) { |
||||
case NG_RPL_ICMPV6_CODE_DIS: |
||||
DEBUG("RPL: DIS received\n"); |
||||
ng_rpl_recv_DIS((ng_rpl_dis_t *)(icmpv6_hdr + 1), &ipv6_hdr->src, &ipv6_hdr->dst, |
||||
byteorder_ntohs(ipv6_hdr->len)); |
||||
break; |
||||
case NG_RPL_ICMPV6_CODE_DIO: |
||||
DEBUG("RPL: DIO received\n"); |
||||
ng_rpl_recv_DIO((ng_rpl_dio_t *)(icmpv6_hdr + 1), &ipv6_hdr->src, |
||||
byteorder_ntohs(ipv6_hdr->len)); |
||||
break; |
||||
case NG_RPL_ICMPV6_CODE_DAO: |
||||
DEBUG("RPL: DAO received\n"); |
||||
ng_rpl_recv_DAO((ng_rpl_dao_t *)(icmpv6_hdr + 1), &ipv6_hdr->src, |
||||
byteorder_ntohs(ipv6_hdr->len)); |
||||
break; |
||||
case NG_RPL_ICMPV6_CODE_DAO_ACK: |
||||
DEBUG("RPL: DAO-ACK received\n"); |
||||
ng_rpl_recv_DAO_ACK((ng_rpl_dao_ack_t *)(icmpv6_hdr + 1)); |
||||
break; |
||||
default: |
||||
DEBUG("RPL: Unknown ICMPV6 code received\n"); |
||||
break; |
||||
} |
||||
|
||||
ng_pktbuf_release(icmpv6); |
||||
} |
||||
|
||||
static void *_event_loop(void *args) |
||||
{ |
||||
msg_t msg, reply; |
||||
|
||||
(void)args; |
||||
msg_init_queue(_msg_q, NG_RPL_MSG_QUEUE_SIZE); |
||||
|
||||
/* preinitialize ACK */ |
||||
reply.type = NG_NETAPI_MSG_TYPE_ACK; |
||||
|
||||
trickle_t *trickle; |
||||
ng_rpl_dodag_t *dodag; |
||||
/* start event loop */ |
||||
while (1) { |
||||
DEBUG("RPL: waiting for incoming message.\n"); |
||||
msg_receive(&msg); |
||||
|
||||
switch (msg.type) { |
||||
case NG_RPL_MSG_TYPE_LIFETIME_UPDATE: |
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_LIFETIME_UPDATE received\n"); |
||||
_update_lifetime(); |
||||
break; |
||||
case NG_RPL_MSG_TYPE_TRICKLE_INTERVAL: |
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_TRICKLE_INTERVAL received\n"); |
||||
trickle = (trickle_t *) msg.content.ptr; |
||||
if (trickle && (trickle->callback.func != NULL)) { |
||||
trickle_interval(trickle); |
||||
} |
||||
break; |
||||
case NG_RPL_MSG_TYPE_TRICKLE_CALLBACK: |
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_TRICKLE_CALLBACK received\n"); |
||||
trickle = (trickle_t *) msg.content.ptr; |
||||
if (trickle && (trickle->callback.func != NULL)) { |
||||
trickle_callback(trickle); |
||||
} |
||||
break; |
||||
case NG_RPL_MSG_TYPE_DAO_HANDLE: |
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_DAO_HANDLE received\n"); |
||||
dodag = (ng_rpl_dodag_t *) msg.content.ptr; |
||||
if (dodag && (dodag->state != 0)) { |
||||
_dao_handle_send(dodag); |
||||
} |
||||
break; |
||||
case NG_RPL_MSG_TYPE_CLEANUP_HANDLE: |
||||
DEBUG("RPL: NG_RPL_MSG_TYPE_CLEANUP received\n"); |
||||
dodag = (ng_rpl_dodag_t *) msg.content.ptr; |
||||
if (dodag && (dodag->state != 0) && (dodag->parents == NULL)) { |
||||
/* no parents - delete this DODAG */ |
||||
ng_rpl_dodag_remove(dodag); |
||||
} |
||||
break; |
||||
case NG_NETAPI_MSG_TYPE_RCV: |
||||
DEBUG("RPL: NG_NETAPI_MSG_TYPE_RCV received\n"); |
||||
_receive((ng_pktsnip_t *)msg.content.ptr); |
||||
break; |
||||
case NG_NETAPI_MSG_TYPE_SND: |
||||
case NG_NETAPI_MSG_TYPE_GET: |
||||
case NG_NETAPI_MSG_TYPE_SET: |
||||
DEBUG("RPL: reply to unsupported recv/get/set\n"); |
||||
reply.content.value = -ENOTSUP; |
||||
msg_reply(&msg, &reply); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
void _update_lifetime(void) |
||||
{ |
||||
timex_t now; |
||||
vtimer_now(&now); |
||||
ng_rpl_parent_t *parent; |
||||
for (uint8_t i = 0; i < NG_RPL_PARENTS_NUMOF; ++i) { |
||||
parent = &ng_rpl_parents[i]; |
||||
if (parent->state != 0) { |
||||
if ((signed)(parent->lifetime.seconds - now.seconds) <= NG_RPL_LIFETIME_UPDATE_STEP) { |
||||
ng_rpl_dodag_t *dodag = parent->dodag; |
||||
ng_rpl_parent_remove(parent); |
||||
ng_rpl_parent_update(dodag, NULL); |
||||
continue; |
||||
} |
||||
else if (((signed)(parent->lifetime.seconds - now.seconds) <= |
||||
NG_RPL_LIFETIME_UPDATE_STEP * 2)) { |
||||
ng_rpl_send_DIS(parent->dodag, &parent->addr); |
||||
} |
||||
} |
||||
} |
||||
vtimer_remove(&_lt_timer); |
||||
vtimer_set_msg(&_lt_timer, _lt_time, ng_rpl_pid, NG_RPL_MSG_TYPE_LIFETIME_UPDATE, NULL); |
||||
} |
||||
|
||||
void ng_rpl_delay_dao(ng_rpl_dodag_t *dodag) |
||||
{ |
||||
dodag->dao_time = timex_set(NG_RPL_DEFAULT_DAO_DELAY, 0); |
||||
dodag->dao_counter = 0; |
||||
dodag->dao_ack_received = false; |
||||
vtimer_remove(&dodag->dao_timer); |
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time, ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag); |
||||
} |
||||
|
||||
void ng_rpl_long_delay_dao(ng_rpl_dodag_t *dodag) |
||||
{ |
||||
dodag->dao_time = timex_set(NG_RPL_REGULAR_DAO_INTERVAL, 0); |
||||
dodag->dao_counter = 0; |
||||
dodag->dao_ack_received = false; |
||||
vtimer_remove(&dodag->dao_timer); |
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time, ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag); |
||||
} |
||||
|
||||
void _dao_handle_send(ng_rpl_dodag_t *dodag) |
||||
{ |
||||
if ((dodag->dao_ack_received == false) && (dodag->dao_counter < NG_RPL_DAO_SEND_RETRIES)) { |
||||
dodag->dao_counter++; |
||||
ng_rpl_send_DAO(dodag, NULL, dodag->default_lifetime); |
||||
dodag->dao_time = timex_set(NG_RPL_DEFAULT_WAIT_FOR_DAO_ACK, 0); |
||||
vtimer_remove(&dodag->dao_timer); |
||||
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time, |
||||
ng_rpl_pid, NG_RPL_MSG_TYPE_DAO_HANDLE, dodag); |
||||
} |
||||
else if (dodag->dao_ack_received == false) { |
||||
ng_rpl_long_delay_dao(dodag); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
@ -0,0 +1,619 @@
|
||||
/*
|
||||
* Copyright (C) 2013 - 2014 INRIA. |
||||
* Copyright (C) 2015 Cenk Gündoğan <cnkgndgn@gmail.com> |
||||
* |
||||
* 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 <cnkgndgn@gmail.com> |
||||
*/ |
||||
|
||||
#include "net/ng_rpl.h" |
||||
#include "inet_ntop.h" |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
#if ENABLE_DEBUG && defined(MODULE_IPV6_ADDR) |
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN]; |
||||
#endif |
||||
|
||||
#define NG_RPL_GROUNDED_SHIFT (7) |
||||
#define NG_RPL_MOP_SHIFT (3) |
||||
#define NG_RPL_OPT_DODAG_CONF_LEN (14) |
||||
#define NG_RPL_SHIFTED_MOP_MASK (0x7) |
||||
#define NG_RPL_PRF_MASK (0x7) |
||||
|
||||
void _ng_rpl_send(ng_pktsnip_t *pkt, ipv6_addr_t *src, ipv6_addr_t *dst, |
||||
ipv6_addr_t *dodag_id) |
||||
{ |
||||
ng_pktsnip_t *hdr; |
||||
ipv6_addr_t all_RPL_nodes = NG_IPV6_ADDR_ALL_RPL_NODES, ll_addr; |
||||
kernel_pid_t iface = ng_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes); |
||||
if (iface == KERNEL_PID_UNDEF) { |
||||
DEBUG("RPL: no suitable interface found for this destination address\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
|
||||
if (src == NULL) { |
||||
ipv6_addr_t *tmp = NULL; |
||||
if (dodag_id != NULL) { |
||||
tmp = ng_ipv6_netif_match_prefix(iface, dodag_id); |
||||
} |
||||
else if (dodag_id == NULL) { |
||||
tmp = ng_ipv6_netif_find_best_src_addr(iface, &all_RPL_nodes); |
||||
} |
||||
|
||||
if (tmp == NULL) { |
||||
DEBUG("RPL: no suitable src address found\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
|
||||
memcpy(&ll_addr, tmp, sizeof(ll_addr)); |
||||
ipv6_addr_set_link_local_prefix(&ll_addr); |
||||
src = &ll_addr; |
||||
} |
||||
|
||||
if (dst == NULL) { |
||||
dst = &all_RPL_nodes; |
||||
} |
||||
|
||||
hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)src, sizeof(ipv6_addr_t), (uint8_t *)dst, |
||||
sizeof(ipv6_addr_t)); |
||||
|
||||
if (hdr == NULL) { |
||||
DEBUG("RPL: Send - no space left in packet buffer\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
|
||||
if (!ng_netapi_dispatch_send(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL,hdr)) { |
||||
DEBUG("RPL: cannot send packet: no subscribers found.\n"); |
||||
ng_pktbuf_release(hdr); |
||||
} |
||||
|
||||
} |
||||
|
||||
void ng_rpl_send_DIO(ng_rpl_dodag_t *dodag, ipv6_addr_t *destination) |
||||
{ |
||||
if (dodag == NULL) { |
||||
DEBUG("RPL: Error - trying to send DIO without being part of a dodag.\n"); |
||||
return; |
||||
} |
||||
|
||||
ng_pktsnip_t *pkt; |
||||
ng_icmpv6_hdr_t *icmp; |
||||
ng_rpl_dio_t *dio; |
||||
uint8_t *pos; |
||||
int size = sizeof(ng_icmpv6_hdr_t) + sizeof(ng_rpl_dio_t); |
||||
|
||||
if ((dodag->dodag_conf_counter % 3) == 0) { |
||||
size += sizeof(ng_rpl_opt_dodag_conf_t); |
||||
} |
||||
|
||||
if ((pkt = ng_icmpv6_build(NULL, NG_ICMPV6_RPL_CTRL, NG_RPL_ICMPV6_CODE_DIO, size)) == NULL) { |
||||
DEBUG("RPL: Send DIO - no space left in packet buffer\n"); |
||||
return; |
||||
} |
||||
|
||||
icmp = (ng_icmpv6_hdr_t *)pkt->data; |
||||
dio = (ng_rpl_dio_t *)(icmp + 1); |
||||
pos = (uint8_t *) dio; |
||||
dio->instance_id = dodag->instance->id; |
||||
dio->version_number = dodag->version |