2013-06-22 05:11:53 +02:00
|
|
|
/**
|
2013-08-08 13:39:00 +02:00
|
|
|
* RPL dodag implementation
|
2013-06-22 05:11:53 +02:00
|
|
|
*
|
|
|
|
* Copyright (C) 2013 INRIA.
|
|
|
|
*
|
|
|
|
* This file subject to the terms and conditions of the GNU Lesser General
|
|
|
|
* Public License. See the file LICENSE in the top level directory for more
|
|
|
|
* details.
|
|
|
|
*
|
2013-08-08 13:39:00 +02:00
|
|
|
* @ingroup rpl
|
2013-06-22 05:11:53 +02:00
|
|
|
* @{
|
|
|
|
* @file rpl_dodag.c
|
2013-08-08 13:39:00 +02:00
|
|
|
* @brief RPL dodag functions
|
2013-06-22 05:11:53 +02:00
|
|
|
* @author Eric Engel <eric.engel@fu-berlin.de>
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2012-01-19 17:35:50 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "rpl_dodag.h"
|
2012-02-14 22:22:01 +01:00
|
|
|
#include "trickle.h"
|
2012-02-26 19:30:48 +01:00
|
|
|
#include "rpl.h"
|
2012-01-19 17:35:50 +01:00
|
|
|
|
|
|
|
rpl_instance_t instances[RPL_MAX_INSTANCES];
|
|
|
|
rpl_dodag_t dodags[RPL_MAX_DODAGS];
|
|
|
|
rpl_parent_t parents[RPL_MAX_PARENTS];
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_instance_t *rpl_new_instance(uint8_t instanceid)
|
|
|
|
{
|
|
|
|
rpl_instance_t *inst;
|
|
|
|
rpl_instance_t *end ;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (inst = &instances[0], end = inst + RPL_MAX_INSTANCES; inst < end; inst++) {
|
|
|
|
if (inst->used == 0) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memset(inst, 0, sizeof(*inst));
|
|
|
|
inst->used = 1;
|
|
|
|
inst->id = instanceid;
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_instance_t *rpl_get_instance(uint8_t instanceid)
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < RPL_MAX_INSTANCES; i++) {
|
|
|
|
if (instances[i].used && (instances[i].id == instanceid)) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return &instances[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_instance_t *rpl_get_my_instance()
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < RPL_MAX_INSTANCES; i++) {
|
|
|
|
if (instances[i].joined) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return &instances[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
2012-01-31 19:36:26 +01:00
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_dodag_t *rpl_new_dodag(uint8_t instanceid, ipv6_addr_t *dodagid)
|
|
|
|
{
|
|
|
|
rpl_instance_t *inst;
|
|
|
|
inst = rpl_get_instance(instanceid);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (inst == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
printf("Error - No instance found for id %d. This should not happen\n",
|
|
|
|
instanceid);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl_dodag_t *dodag;
|
|
|
|
rpl_dodag_t *end;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (dodag = &dodags[0], end = dodag + RPL_MAX_DODAGS; dodag < end; dodag++) {
|
|
|
|
if (dodag->used == 0) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memset(dodag, 0, sizeof(*dodag));
|
|
|
|
dodag->instance = inst;
|
|
|
|
dodag->my_rank = INFINITE_RANK;
|
|
|
|
dodag->used = 1;
|
|
|
|
memcpy(&dodag->dodag_id, dodagid, sizeof(*dodagid));
|
|
|
|
return dodag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-01-19 17:35:50 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_dodag_t *rpl_get_dodag(ipv6_addr_t *id)
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < RPL_MAX_DODAGS; i++) {
|
|
|
|
if (dodags[i].used && (rpl_equal_id(&dodags[i].dodag_id, id))) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return &dodags[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_dodag_t *rpl_get_my_dodag()
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < RPL_MAX_DODAGS; i++) {
|
|
|
|
if (dodags[i].joined) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return &dodags[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_del_dodag(rpl_dodag_t *dodag)
|
|
|
|
{
|
|
|
|
memset(dodag, 0, sizeof(*dodag));
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_leave_dodag(rpl_dodag_t *dodag)
|
|
|
|
{
|
|
|
|
dodag->joined = 0;
|
|
|
|
dodag->my_preferred_parent = NULL;
|
|
|
|
rpl_delete_all_parents();
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
bool rpl_equal_id(ipv6_addr_t *id1, ipv6_addr_t *id2)
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
for (uint8_t i = 0; i < 4; i++) {
|
|
|
|
if (id1->uint32[i] != id2->uint32[i]) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2012-02-22 00:50:40 +01:00
|
|
|
|
2012-01-19 17:35:50 +01:00
|
|
|
}
|
2012-01-26 20:26:55 +01:00
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_parent_t *rpl_new_parent(rpl_dodag_t *dodag, ipv6_addr_t *address, uint16_t rank)
|
|
|
|
{
|
|
|
|
rpl_parent_t *parent;
|
|
|
|
rpl_parent_t *end;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (parent = &parents[0], end = parents + RPL_MAX_PARENTS; parent < end; parent++) {
|
|
|
|
if (parent->used == 0) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memset(parent, 0, sizeof(*parent));
|
|
|
|
parent->used = 1;
|
|
|
|
parent->addr = *address;
|
|
|
|
parent->rank = rank;
|
|
|
|
parent->dodag = dodag;
|
|
|
|
/* dtsn is set at the end of recv_dio function */
|
|
|
|
parent->dtsn = 0;
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl_delete_worst_parent();
|
|
|
|
return rpl_new_parent(dodag, address, rank);
|
2012-01-26 20:26:55 +01:00
|
|
|
}
|
2012-01-31 19:36:26 +01:00
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_parent_t *rpl_find_parent(ipv6_addr_t *address)
|
|
|
|
{
|
|
|
|
rpl_parent_t *parent;
|
|
|
|
rpl_parent_t *end;
|
2012-01-31 19:36:26 +01:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (parent = &parents[0], end = parents + RPL_MAX_PARENTS; parent < end; parent++) {
|
|
|
|
if ((parent->used) && (rpl_equal_id(address, &parent->addr))) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-01-31 19:36:26 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_delete_parent(rpl_parent_t *parent)
|
|
|
|
{
|
|
|
|
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if ((my_dodag != NULL) && rpl_equal_id(&my_dodag->my_preferred_parent->addr,
|
2013-08-08 13:39:00 +02:00
|
|
|
&parent->addr)) {
|
2013-06-22 05:11:53 +02:00
|
|
|
my_dodag->my_preferred_parent = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(parent, 0, sizeof(*parent));
|
2012-02-22 00:50:40 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_delete_worst_parent(void)
|
|
|
|
{
|
|
|
|
uint8_t worst = 0xFF;
|
|
|
|
uint16_t max_rank = 0x0000;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < RPL_MAX_PARENTS; i++) {
|
|
|
|
if (parents[i].rank > max_rank) {
|
2013-06-22 05:11:53 +02:00
|
|
|
worst = i;
|
|
|
|
max_rank = parents[i].rank;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (worst == 0xFF) {
|
2013-06-22 05:11:53 +02:00
|
|
|
/* Fehler, keine parents -> sollte nicht passieren */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl_delete_parent(&parents[worst]);
|
2012-02-14 22:22:01 +01:00
|
|
|
|
2012-02-22 00:50:40 +01:00
|
|
|
}
|
2012-02-16 23:23:15 +01:00
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_delete_all_parents(void)
|
|
|
|
{
|
|
|
|
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
|
|
|
my_dodag->my_preferred_parent = NULL;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < RPL_MAX_PARENTS; i++) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memset(&parents[i], 0, sizeof(parents[i]));
|
|
|
|
}
|
2012-02-16 23:23:15 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_parent_t *rpl_find_preferred_parent(void)
|
|
|
|
{
|
|
|
|
rpl_parent_t *best = NULL;
|
|
|
|
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (uint8_t i = 0; i < RPL_MAX_PARENTS; i++) {
|
|
|
|
if (parents[i].used) {
|
|
|
|
if ((parents[i].rank == INFINITE_RANK) || (parents[i].lifetime <= 1)) {
|
2013-06-22 05:11:53 +02:00
|
|
|
puts("bad parent");
|
|
|
|
continue;
|
|
|
|
}
|
2013-06-24 22:37:35 +02:00
|
|
|
else if (best == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
puts("parent");
|
|
|
|
best = &parents[i];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
best = my_dodag->of->which_parent(best, &parents[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (best == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!rpl_equal_id(&my_dodag->my_preferred_parent->addr, &best->addr)) {
|
|
|
|
if (my_dodag->mop != NO_DOWNWARD_ROUTES) {
|
2013-06-22 05:11:53 +02:00
|
|
|
/* send DAO with ZERO_LIFETIME to old parent */
|
|
|
|
send_DAO(&my_dodag->my_preferred_parent->addr, 0, false, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
my_dodag->my_preferred_parent = best;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (my_dodag->mop != NO_DOWNWARD_ROUTES) {
|
2013-06-22 05:11:53 +02:00
|
|
|
delay_dao();
|
|
|
|
}
|
|
|
|
|
|
|
|
reset_trickletimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
return best;
|
2012-02-26 19:30:48 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_parent_update(rpl_parent_t *parent)
|
|
|
|
{
|
|
|
|
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
|
|
|
uint16_t old_rank = my_dodag->my_rank;
|
|
|
|
|
|
|
|
/* update Parent lifetime */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (parent != NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
parent->lifetime = my_dodag->default_lifetime * my_dodag->lifetime_unit;
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (rpl_find_preferred_parent() == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_local_repair();
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (rpl_calc_rank(old_rank, my_dodag->minhoprankincrease) !=
|
2013-08-08 13:39:00 +02:00
|
|
|
rpl_calc_rank(my_dodag->my_rank, my_dodag->minhoprankincrease)) {
|
2013-06-24 22:37:35 +02:00
|
|
|
if (my_dodag->my_rank < my_dodag->min_rank) {
|
2013-06-22 05:11:53 +02:00
|
|
|
my_dodag->min_rank = my_dodag->my_rank;
|
|
|
|
}
|
|
|
|
|
|
|
|
reset_trickletimer();
|
|
|
|
}
|
2012-02-26 19:30:48 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_join_dodag(rpl_dodag_t *dodag, ipv6_addr_t *parent, uint16_t parent_rank)
|
|
|
|
{
|
|
|
|
rpl_dodag_t *my_dodag;
|
|
|
|
rpl_parent_t *preferred_parent;
|
|
|
|
my_dodag = rpl_new_dodag(dodag->instance->id, &dodag->dodag_id);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (my_dodag == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
preferred_parent = rpl_new_parent(my_dodag, parent, parent_rank);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (preferred_parent == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
rpl_del_dodag(my_dodag);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_dodag->instance->joined = 1;
|
|
|
|
my_dodag->of = dodag->of;
|
|
|
|
my_dodag->mop = dodag->mop;
|
|
|
|
my_dodag->dtsn = dodag->dtsn;
|
|
|
|
my_dodag->prf = dodag->prf;
|
|
|
|
my_dodag->dio_interval_doubling = dodag->dio_interval_doubling;
|
|
|
|
my_dodag->dio_min = dodag->dio_min;
|
|
|
|
my_dodag->dio_redundancy = dodag->dio_redundancy;
|
|
|
|
my_dodag->maxrankincrease = dodag->maxrankincrease;
|
|
|
|
my_dodag->minhoprankincrease = dodag->minhoprankincrease;
|
|
|
|
my_dodag->default_lifetime = dodag->default_lifetime;
|
|
|
|
my_dodag->lifetime_unit = dodag->lifetime_unit;
|
|
|
|
my_dodag->version = dodag->version;
|
|
|
|
my_dodag->grounded = dodag->grounded;
|
|
|
|
my_dodag->joined = 1;
|
|
|
|
my_dodag->my_preferred_parent = preferred_parent;
|
2013-06-28 17:53:21 +02:00
|
|
|
my_dodag->node_status = (uint8_t) NORMAL_NODE;
|
2013-06-22 05:11:53 +02:00
|
|
|
my_dodag->my_rank = dodag->of->calc_rank(preferred_parent, dodag->my_rank);
|
|
|
|
my_dodag->dao_seq = RPL_COUNTER_INIT;
|
|
|
|
my_dodag->min_rank = my_dodag->my_rank;
|
|
|
|
|
|
|
|
start_trickle(my_dodag->dio_min, my_dodag->dio_interval_doubling, my_dodag->dio_redundancy);
|
|
|
|
delay_dao();
|
2012-01-31 19:36:26 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_global_repair(rpl_dodag_t *dodag, ipv6_addr_t *p_addr, uint16_t rank)
|
|
|
|
{
|
|
|
|
puts("[INFO] Global repair started");
|
|
|
|
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (my_dodag == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
printf("[Error] - no global repair possible, if not part of a DODAG\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl_delete_all_parents();
|
|
|
|
my_dodag->version = dodag->version;
|
|
|
|
my_dodag->dtsn++;
|
|
|
|
my_dodag->my_preferred_parent = rpl_new_parent(my_dodag, p_addr, rank);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (my_dodag->my_preferred_parent == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
printf("[Error] no more parent after global repair\n");
|
|
|
|
my_dodag->my_rank = INFINITE_RANK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Calc new Rank */
|
|
|
|
my_dodag->my_rank = my_dodag->of->calc_rank(my_dodag->my_preferred_parent,
|
2013-08-08 13:39:00 +02:00
|
|
|
my_dodag->my_rank);
|
2013-06-22 05:11:53 +02:00
|
|
|
my_dodag->min_rank = my_dodag->my_rank;
|
|
|
|
reset_trickletimer();
|
|
|
|
delay_dao();
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Migrated to DODAG Version %d. My new Rank: %d\n", my_dodag->version,
|
|
|
|
my_dodag->my_rank);
|
2012-02-26 19:30:48 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void rpl_local_repair(void)
|
|
|
|
{
|
|
|
|
puts("[INFO] Local Repair started");
|
|
|
|
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (my_dodag == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
printf("[Error] - no local repair possible, if not part of a DODAG\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_dodag->my_rank = INFINITE_RANK;
|
|
|
|
my_dodag->dtsn++;
|
|
|
|
rpl_delete_all_parents();
|
|
|
|
reset_trickletimer();
|
2012-02-26 19:30:48 +01:00
|
|
|
|
2012-01-31 19:36:26 +01:00
|
|
|
}
|
2012-02-14 22:22:01 +01:00
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
ipv6_addr_t *rpl_get_my_preferred_parent()
|
|
|
|
{
|
|
|
|
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (my_dodag == NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &my_dodag->my_preferred_parent->addr;
|
2012-02-14 22:22:01 +01:00
|
|
|
}
|
2012-02-26 19:30:48 +01:00
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
uint16_t rpl_calc_rank(uint16_t abs_rank, uint16_t minhoprankincrease)
|
|
|
|
{
|
|
|
|
return abs_rank / minhoprankincrease;
|
2012-02-26 19:30:48 +01:00
|
|
|
}
|