
18 changed files with 3252 additions and 0 deletions
@ -0,0 +1,732 @@
|
||||
/*
|
||||
* 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 nhdp |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Interface Information Base implementation for NHDP |
||||
* |
||||
* @author Fabian Nack <nack@inf.fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include "mutex.h" |
||||
#include "timex.h" |
||||
#include "vtimer.h" |
||||
#include "utlist.h" |
||||
#include "kernel_types.h" |
||||
|
||||
#include "rfc5444/rfc5444_iana.h" |
||||
#include "rfc5444/rfc5444_writer.h" |
||||
|
||||
#include "iib_table.h" |
||||
#include "nhdp_address.h" |
||||
#include "nhdp_writer.h" |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
/* Internal variables */ |
||||
static mutex_t mtx_iib_access = MUTEX_INIT; |
||||
static iib_base_entry_t *iib_base_entry_head = NULL; |
||||
|
||||
/* Internal function prototypes */ |
||||
static void rem_link_set_entry(iib_base_entry_t *base_entry, iib_link_set_entry_t *ls_entry); |
||||
static void cleanup_link_sets(nhdp_addr_entry_t *rem_list); |
||||
static iib_link_set_entry_t *add_default_link_set_entry(iib_base_entry_t *base_entry, timex_t *now, |
||||
uint64_t val_time); |
||||
static void reset_link_set_entry(iib_link_set_entry_t *ls_entry, timex_t *now, uint64_t val_time); |
||||
static iib_link_set_entry_t *update_link_set(iib_base_entry_t *base_entry, nib_entry_t *nb_elt, |
||||
nhdp_addr_entry_t *send_list, timex_t *now, |
||||
uint64_t val_time, uint8_t sym, uint8_t lost); |
||||
static void release_link_tuple_addresses(iib_link_set_entry_t *ls_entry); |
||||
|
||||
static int update_two_hop_set(iib_base_entry_t *base_entry, iib_link_set_entry_t *ls_entry, |
||||
nhdp_addr_entry_t *th_sym_list, nhdp_addr_entry_t *th_rem_list, |
||||
timex_t *now, uint64_t val_time); |
||||
static uint8_t rem_exst_th_entries(iib_base_entry_t *base_entry, iib_two_hop_set_entry_t *ts_elt, |
||||
nhdp_addr_entry_t *th_sym_list); |
||||
static uint8_t rem_non_sym_th_entries(iib_base_entry_t *base_entry, |
||||
iib_two_hop_set_entry_t *ts_elt, |
||||
nhdp_addr_entry_t *th_rem_list); |
||||
static int add_two_hop_entry(iib_base_entry_t *base_entry, iib_link_set_entry_t *ls_entry, |
||||
nhdp_addr_t *th_addr, timex_t *now, uint64_t val_time); |
||||
static void rem_two_hop_entry(iib_base_entry_t *base_entry, iib_two_hop_set_entry_t *th_entry); |
||||
|
||||
static void wr_update_ls_status(iib_base_entry_t *base_entry, |
||||
iib_link_set_entry_t *ls_elt, timex_t *now); |
||||
static void update_nb_tuple_symmetry(iib_base_entry_t *base_entry, |
||||
iib_link_set_entry_t *ls_entry, timex_t *now); |
||||
static void rem_not_heard_nb_tuple(iib_link_set_entry_t *ls_entry, timex_t *now); |
||||
|
||||
static inline timex_t get_max_timex(timex_t time_one, timex_t time_two); |
||||
static iib_link_tuple_status_t get_tuple_status(iib_link_set_entry_t *ls_entry, timex_t *now); |
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Interface Information Base API * |
||||
*---------------------------------------------------------------------------*/ |
||||
|
||||
int iib_register_if(kernel_pid_t pid) |
||||
{ |
||||
iib_base_entry_t *new_entry = (iib_base_entry_t *) malloc(sizeof(iib_base_entry_t)); |
||||
|
||||
if (!new_entry) { |
||||
/* Insufficient memory */ |
||||
return -1; |
||||
} |
||||
|
||||
new_entry->if_pid = pid; |
||||
new_entry->link_set_head = NULL; |
||||
new_entry->two_hop_set_head = NULL; |
||||
LL_PREPEND(iib_base_entry_head, new_entry); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, nhdp_addr_entry_t *send_list, |
||||
nhdp_addr_entry_t *th_sym_list, nhdp_addr_entry_t *th_rem_list, |
||||
nhdp_addr_entry_t *rem_list, uint64_t validity_time, uint8_t is_sym_nb, |
||||
uint8_t is_lost) |
||||
{ |
||||
iib_base_entry_t *base_elt; |
||||
timex_t now; |
||||
|
||||
mutex_lock(&mtx_iib_access); |
||||
|
||||
/* Remove link tuple addresses that are included in the Removed Addr List */ |
||||
cleanup_link_sets(rem_list); |
||||
|
||||
LL_FOREACH(iib_base_entry_head, base_elt) { |
||||
/* Find the link set and two hop set for the interface */ |
||||
if (base_elt->if_pid == if_pid) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (base_elt) { |
||||
vtimer_now(&now); |
||||
|
||||
/* Create a new link tuple for the neighbor that originated the hello */ |
||||
iib_link_set_entry_t *ls_entry = update_link_set(base_elt, nb_elt, send_list, |
||||
&now, validity_time, is_sym_nb, is_lost); |
||||
|
||||
/* Create new two hop tuples for signaled symmetric neighbors */ |
||||
if (ls_entry) { |
||||
update_two_hop_set(base_elt, ls_entry, th_sym_list, th_rem_list, &now, validity_time); |
||||
} |
||||
} |
||||
|
||||
mutex_unlock(&mtx_iib_access); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void iib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr) |
||||
{ |
||||
iib_base_entry_t *base_elt; |
||||
iib_link_set_entry_t *ls_elt; |
||||
nhdp_addr_entry_t *addr_elt; |
||||
timex_t now; |
||||
|
||||
mutex_lock(&mtx_iib_access); |
||||
|
||||
vtimer_now(&now); |
||||
|
||||
/* Before adding addresses first update the status of all link tuples */ |
||||
iib_update_lt_status(&now); |
||||
|
||||
/* Add all addresses of Link Tuples of the given interface's Link Set to the current HELLO */ |
||||
LL_FOREACH(iib_base_entry_head, base_elt) { |
||||
if (base_elt->if_pid == if_pid) { |
||||
LL_FOREACH(base_elt->link_set_head, ls_elt) { |
||||
if (ls_elt->last_status != IIB_LT_STATUS_PENDING) { |
||||
/* Exclude addresses from tuples with L_STATUS = PENDING */ |
||||
LL_FOREACH(ls_elt->address_list_head, addr_elt) { |
||||
if (!NHDP_ADDR_TMP_IN_ANY(addr_elt->address)) { |
||||
/* Add address to the writers next packet */ |
||||
switch (ls_elt->last_status) { |
||||
case IIB_LT_STATUS_SYM: |
||||
nhdp_writer_add_addr(wr, addr_elt->address, |
||||
RFC5444_ADDRTLV_LINK_STATUS, |
||||
RFC5444_LINKSTATUS_SYMMETRIC); |
||||
addr_elt->address->in_tmp_table = NHDP_ADDR_TMP_SYM; |
||||
break; |
||||
|
||||
case IIB_LT_STATUS_HEARD: |
||||
nhdp_writer_add_addr(wr, addr_elt->address, |
||||
RFC5444_ADDRTLV_LINK_STATUS, |
||||
RFC5444_LINKSTATUS_HEARD); |
||||
addr_elt->address->in_tmp_table = NHDP_ADDR_TMP_ANY; |
||||
break; |
||||
|
||||
case IIB_LT_STATUS_UNKNOWN: |
||||
/* Fall through */ |
||||
|
||||
case IIB_LT_STATUS_LOST: |
||||
nhdp_writer_add_addr(wr, addr_elt->address, |
||||
RFC5444_ADDRTLV_LINK_STATUS, |
||||
RFC5444_LINKSTATUS_LOST); |
||||
addr_elt->address->in_tmp_table = NHDP_ADDR_TMP_ANY; |
||||
break; |
||||
|
||||
case IIB_LT_STATUS_PENDING: |
||||
/* Pending link tuples are not included */ |
||||
break; |
||||
|
||||
default: |
||||
/* Should not happen */ |
||||
DEBUGF("[WARNING] Unknown link tuple status\n"); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
/* IF's link set found */ |
||||
break; |
||||
} |
||||
} |
||||
|
||||
mutex_unlock(&mtx_iib_access); |
||||
} |
||||
|
||||
void iib_update_lt_status(timex_t *now) |
||||
{ |
||||
iib_base_entry_t *base_elt; |
||||
iib_link_set_entry_t *ls_elt, *ls_tmp; |
||||
|
||||
LL_FOREACH(iib_base_entry_head, base_elt) { |
||||
LL_FOREACH_SAFE(base_elt->link_set_head, ls_elt, ls_tmp) { |
||||
wr_update_ls_status(base_elt, ls_elt, now); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void iib_propagate_nb_entry_change(nib_entry_t *old_entry, nib_entry_t *new_entry) |
||||
{ |
||||
iib_base_entry_t *base_elt; |
||||
iib_link_set_entry_t *ls_elt; |
||||
LL_FOREACH(iib_base_entry_head, base_elt) { |
||||
LL_FOREACH(base_elt->link_set_head, ls_elt) { |
||||
if (ls_elt->nb_elt == old_entry) { |
||||
ls_elt->nb_elt = new_entry; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/*------------------------------------------------------------------------------------*/ |
||||
/* Internal functions */ |
||||
/*------------------------------------------------------------------------------------*/ |
||||
|
||||
/**
|
||||
* Remove addresses included in the Removed Address List from all existing Link Tuples |
||||
*/ |
||||
static void cleanup_link_sets(nhdp_addr_entry_t *rem_list) |
||||
{ |
||||
/* Check whether the Removed Address List is not empty */ |
||||
if (!rem_list) { |
||||
return; |
||||
} |
||||
|
||||
/* Loop through all link sets */ |
||||
iib_base_entry_t *base_elt; |
||||
LL_FOREACH(iib_base_entry_head, base_elt) { |
||||
/* Loop through all link tuples of the link set */ |
||||
iib_link_set_entry_t *ls_elt, *ls_tmp; |
||||
LL_FOREACH_SAFE(base_elt->link_set_head, ls_elt, ls_tmp) { |
||||
/* Loop through all addresses of the link tuples */ |
||||
nhdp_addr_entry_t *lt_elt; |
||||
LL_FOREACH(ls_elt->address_list_head, lt_elt) { |
||||
/* Loop through all addresses of the Removed Addr List */ |
||||
nhdp_addr_entry_t *rem_elt; |
||||
LL_FOREACH(rem_list, rem_elt) { |
||||
/* Remove link tuple address if included in the Removed Addr List */ |
||||
if (lt_elt->address == rem_elt->address) { |
||||
/* Addresses are equal (same NHDP address db entry) */ |
||||
LL_DELETE(ls_elt->address_list_head, lt_elt); |
||||
nhdp_free_addr_entry(lt_elt); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Remove link tuples with empty address list */ |
||||
if (!ls_elt->address_list_head) { |
||||
if (ls_elt->last_status == IIB_LT_STATUS_SYM) { |
||||
/* Remove all two hop entries for the corresponding link tuple */ |
||||
iib_two_hop_set_entry_t *th_elt, *th_tmp; |
||||
LL_FOREACH_SAFE(base_elt->two_hop_set_head, th_elt, th_tmp) { |
||||
if (th_elt->ls_elt == ls_elt) { |
||||
rem_two_hop_entry(base_elt, th_elt); |
||||
} |
||||
} |
||||
} |
||||
|
||||
rem_link_set_entry(base_elt, ls_elt); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Update the Link Set for the receiving interface during HELLO message processing |
||||
*/ |
||||
static iib_link_set_entry_t *update_link_set(iib_base_entry_t *base_entry, nib_entry_t *nb_elt, |
||||
nhdp_addr_entry_t *send_list, timex_t *now, |
||||
uint64_t val_time, uint8_t sym, uint8_t lost) |
||||
{ |
||||
iib_link_set_entry_t *ls_elt, *ls_tmp; |
||||
iib_link_set_entry_t *matching_lt = NULL; |
||||
nhdp_addr_entry_t *lt_elt, *send_elt; |
||||
timex_t v_time, l_hold; |
||||
uint8_t matches = 0; |
||||
|
||||
/* Loop through every link tuple of the interface to update the link set */ |
||||
LL_FOREACH_SAFE(base_entry->link_set_head, ls_elt, ls_tmp) { |
||||
/* Loop through all addresses of the link tuple */ |
||||
LL_FOREACH(ls_elt->address_list_head, lt_elt) { |
||||
/* Loop through all addresses of the Sending Addr List */ |
||||
LL_FOREACH(send_list, send_elt) { |
||||
/* If link tuple address matches a sending addr we found a fitting tuple */ |
||||
if (lt_elt->address == send_elt->address) { |
||||
/* Addresses are equal (same NHDP address db entry) */ |
||||
matches++; |
||||
|
||||
if (matches > 1) { |
||||
/* Multiple matching link tuples, delete the previous one */ |
||||
if (matching_lt->last_status == IIB_LT_STATUS_SYM) { |
||||
update_nb_tuple_symmetry(base_entry, matching_lt, now); |
||||
} |
||||
|
||||
rem_link_set_entry(base_entry, matching_lt); |
||||
} |
||||
|
||||
matching_lt = ls_elt; |
||||
break; |
||||
} |
||||
|
||||
if (matching_lt == ls_elt) { |
||||
/* This link tuple is already detected as matching */ |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (matches > 1) { |
||||
/* Multiple matching link tuples, reset the last one for reuse */ |
||||
if (matching_lt->last_status == IIB_LT_STATUS_SYM) { |
||||
update_nb_tuple_symmetry(base_entry, matching_lt, now); |
||||
} |
||||
|
||||
reset_link_set_entry(matching_lt, now, val_time); |
||||
} |
||||
else if (matches == 1) { |
||||
/* A single matching link tuple, only release the address list */ |
||||
release_link_tuple_addresses(matching_lt); |
||||
} |
||||
else { |
||||
/* No single matching link tuple existant, create a new one */ |
||||
matching_lt = add_default_link_set_entry(base_entry, now, val_time); |
||||
|
||||
if (!matching_lt) { |
||||
/* Insufficient memory */ |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
v_time = timex_from_uint64(val_time * MS_IN_USEC); |
||||
l_hold = timex_from_uint64(((uint64_t)NHDP_L_HOLD_TIME_MS) * MS_IN_USEC); |
||||
|
||||
/* Set Sending Address List as this tuples address list */ |
||||
matching_lt->address_list_head = nhdp_generate_new_addr_list(send_list); |
||||
|
||||
if (!matching_lt->address_list_head) { |
||||
/* Insufficient memory */ |
||||
rem_link_set_entry(base_entry, matching_lt); |
||||
return NULL; |
||||
} |
||||
|
||||
matching_lt->nb_elt = nb_elt; |
||||
|
||||
/* Set values dependent on link status */ |
||||
if (sym) { |
||||
if (matching_lt->last_status != IIB_LT_STATUS_SYM) { |
||||
/* Set corresponding neighbor tuple to symmetric (Section 13.1 of RFC 6130) */ |
||||
if (matching_lt->nb_elt) { |
||||
nib_set_nb_entry_sym(matching_lt->nb_elt); |
||||
} |
||||
} |
||||
|
||||
matching_lt->sym_time = timex_add(*now, v_time); |
||||
matching_lt->last_status = IIB_LT_STATUS_SYM; |
||||
} |
||||
else if (lost) { |
||||
matching_lt->sym_time.microseconds = 0; |
||||
matching_lt->sym_time.seconds = 0; |
||||
|
||||
if (matching_lt->last_status == IIB_LT_STATUS_SYM) { |
||||
update_nb_tuple_symmetry(base_entry, matching_lt, now); |
||||
} |
||||
|
||||
if (get_tuple_status(matching_lt, now) == IIB_LT_STATUS_HEARD) { |
||||
matching_lt->last_status = IIB_LT_STATUS_HEARD; |
||||
matching_lt->exp_time = timex_add(*now, l_hold); |
||||
} |
||||
else { |
||||
matching_lt->last_status = IIB_LT_STATUS_UNKNOWN; |
||||
} |
||||
} |
||||
|
||||
/* Set time values */ |
||||
matching_lt->heard_time = get_max_timex(timex_add(*now, v_time), matching_lt->sym_time); |
||||
|
||||
if (matching_lt->pending) { |
||||
/* L_status is PENDING */ |
||||
matching_lt->exp_time = get_max_timex(matching_lt->exp_time, matching_lt->heard_time); |
||||
} |
||||
else if (!matching_lt->lost) { |
||||
if ((timex_cmp(matching_lt->sym_time, *now) == 1) |
||||
|| (timex_cmp(matching_lt->heard_time, *now) == 1)) { |
||||
/* L_status is HEARD or SYMMETRIC */ |
||||
matching_lt->exp_time = get_max_timex(matching_lt->exp_time, |
||||
timex_add(matching_lt->heard_time, l_hold)); |
||||
} |
||||
} |
||||
|
||||
return matching_lt; |
||||
} |
||||
|
||||
/**
|
||||
* Update the status of a link tuple and process necessary changes and execute |
||||
* necessary changes in the 2-Hop Set and in the Neighbor Information Base |
||||
* Implements logic of Section 13 of RFC 6130 |
||||
*/ |
||||
static void wr_update_ls_status(iib_base_entry_t *base_entry, |
||||
iib_link_set_entry_t *ls_elt, timex_t *now) |
||||
{ |
||||
if (timex_cmp(ls_elt->exp_time, *now) != 1) { |
||||
/* Entry expired and has to be removed */ |
||||
if (ls_elt->last_status == IIB_LT_STATUS_SYM) { |
||||
update_nb_tuple_symmetry(base_entry, ls_elt, now); |
||||
} |
||||
|
||||
rem_not_heard_nb_tuple(ls_elt, now); |
||||
rem_link_set_entry(base_entry, ls_elt); |
||||
} |
||||
else if ((ls_elt->last_status == IIB_LT_STATUS_SYM) |
||||
&& (timex_cmp(ls_elt->sym_time, *now) != 1)) { |
||||
/* Status changed from SYMMETRIC to HEARD */ |
||||
update_nb_tuple_symmetry(base_entry, ls_elt, now); |
||||
ls_elt->last_status = IIB_LT_STATUS_HEARD; |
||||
|
||||
if (timex_cmp(ls_elt->heard_time, *now) != 1) { |
||||
/* New status is LOST (equals IIB_LT_STATUS_UNKNOWN) */ |
||||
rem_not_heard_nb_tuple(ls_elt, now); |
||||
ls_elt->nb_elt = NULL; |
||||
ls_elt->last_status = IIB_LT_STATUS_UNKNOWN; |
||||
} |
||||
} |
||||
else if ((ls_elt->last_status == IIB_LT_STATUS_HEARD) |
||||
&& (timex_cmp(ls_elt->heard_time, *now) != 1)) { |
||||
/* Status changed from HEARD to LOST (equals IIB_LT_STATUS_UNKNOWN) */ |
||||
rem_not_heard_nb_tuple(ls_elt, now); |
||||
ls_elt->nb_elt = NULL; |
||||
ls_elt->last_status = IIB_LT_STATUS_UNKNOWN; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Add a new Link Tuple with default values to the given Link Set |
||||
*/ |
||||
static iib_link_set_entry_t *add_default_link_set_entry(iib_base_entry_t *base_entry, timex_t *now, |
||||
uint64_t val_time) |
||||
{ |
||||
iib_link_set_entry_t *new_entry; |
||||
timex_t v_time = timex_from_uint64(val_time * MS_IN_USEC); |
||||
|
||||
new_entry = (iib_link_set_entry_t *) malloc(sizeof(iib_link_set_entry_t)); |
||||
|
||||
if (!new_entry) { |
||||
/* Insufficient memory */ |
||||
return NULL; |
||||
} |
||||
|
||||
new_entry->address_list_head = NULL; |
||||
new_entry->heard_time.microseconds = 0; |
||||
new_entry->heard_time.seconds = 0; |
||||
new_entry->sym_time.microseconds = 0; |
||||
new_entry->sym_time.seconds = 0; |
||||
new_entry->pending = NHDP_INITIAL_PENDING; |
||||
new_entry->lost = 0; |
||||
new_entry->exp_time = timex_add(*now, v_time); |
||||
new_entry->last_status = IIB_LT_STATUS_UNKNOWN; |
||||
new_entry->nb_elt = NULL; |
||||
LL_PREPEND(base_entry->link_set_head, new_entry); |
||||
|
||||
return new_entry; |
||||
} |
||||
|
||||
/**
|
||||
* Reset a given Link Tuple for reusage |
||||
*/ |
||||
static void reset_link_set_entry(iib_link_set_entry_t *ls_entry, timex_t *now, uint64_t val_time) |
||||
{ |
||||
timex_t v_time = timex_from_uint64(val_time * MS_IN_USEC); |
||||
|
||||
release_link_tuple_addresses(ls_entry); |
||||
ls_entry->sym_time.microseconds = 0; |
||||
ls_entry->sym_time.seconds = 0; |
||||
ls_entry->heard_time.microseconds = 0; |
||||
ls_entry->heard_time.seconds = 0; |
||||
ls_entry->pending = NHDP_INITIAL_PENDING; |
||||
ls_entry->lost = 0; |
||||
ls_entry->exp_time = timex_add(*now, v_time); |
||||
ls_entry->nb_elt = NULL; |
||||
ls_entry->last_status = IIB_LT_STATUS_UNKNOWN; |
||||
} |
||||
|
||||
/**
|
||||
* Remove a given Link Tuple |
||||
*/ |
||||
static void rem_link_set_entry(iib_base_entry_t *base_entry, iib_link_set_entry_t *ls_entry) |
||||
{ |
||||
LL_DELETE(base_entry->link_set_head, ls_entry); |
||||
release_link_tuple_addresses(ls_entry); |
||||
free(ls_entry); |
||||
} |
||||
|
||||
/**
|
||||
* Free all address entries of a link tuple |
||||
*/ |
||||
static void release_link_tuple_addresses(iib_link_set_entry_t *ls_entry) |
||||
{ |
||||
nhdp_free_addr_list(ls_entry->address_list_head); |
||||
ls_entry->address_list_head = NULL; |
||||
} |
||||
|
||||
/**
|
||||
* Update the 2-Hop Set during HELLO message processing |
||||
*/ |
||||
static int update_two_hop_set(iib_base_entry_t *base_entry, iib_link_set_entry_t *ls_entry, |
||||
nhdp_addr_entry_t *th_sym_list, nhdp_addr_entry_t *th_rem_list, |
||||
timex_t *now, uint64_t val_time) |
||||
{ |
||||
/* Check whether a corresponding link tuple was created */ |
||||
if (ls_entry == NULL) { |
||||
return -1; |
||||
} |
||||
|
||||
/* If the link to the neighbor is still symmetric */ |
||||
if (get_tuple_status(ls_entry, now) == IIB_LT_STATUS_SYM) { |
||||
iib_two_hop_set_entry_t *ths_elt, *ths_tmp; |
||||
nhdp_addr_entry_t *sym_elt; |
||||
|
||||
/* Loop through all the two hop tuples of the two hop set */ |
||||
LL_FOREACH_SAFE(base_entry->two_hop_set_head, ths_elt, ths_tmp) { |
||||
if (timex_cmp(ths_elt->exp_time, *now) != 1) { |
||||
/* Entry is expired, remove it */ |
||||
rem_two_hop_entry(base_entry, ths_elt); |
||||
} |
||||
else if (ths_elt->ls_elt == ls_entry) { |
||||
if (!rem_non_sym_th_entries(base_entry, ths_elt, th_rem_list)) { |
||||
rem_exst_th_entries(base_entry, ths_elt, th_sym_list); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Add a new entry for every signaled symmetric neighbor address */ |
||||
LL_FOREACH(th_sym_list, sym_elt) { |
||||
if (add_two_hop_entry(base_entry, ls_entry, sym_elt->address, now, val_time)) { |
||||
/* No more memory available, return error */ |
||||
return -1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* Remove an existing 2-Hop Tuple if its address was signalled as lost in the received HELLO |
||||
*/ |
||||
static uint8_t rem_non_sym_th_entries(iib_base_entry_t *base_entry, |
||||
iib_two_hop_set_entry_t *ts_elt, |
||||
nhdp_addr_entry_t *th_rem_list) |
||||
{ |
||||
nhdp_addr_entry_t *rem_elt; |
||||
|
||||
/* Remove the given two hop entry if it was signaled as lost */ |
||||
LL_FOREACH(th_rem_list, rem_elt) { |
||||
if (ts_elt->th_nb_addr == rem_elt->address) { |
||||
/* Addresses are equal (same NHDP address db entry) */ |
||||
rem_two_hop_entry(base_entry, ts_elt); |
||||
return 1; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* Remove an existing 2-Hop Tuple if it is present in the 2-Hop symmetric address |
||||
* list of the received HELLO |
||||
*/ |
||||
static uint8_t rem_exst_th_entries(iib_base_entry_t *base_entry, |
||||
iib_two_hop_set_entry_t *ts_elt, nhdp_addr_entry_t *th_sym_list) |
||||
{ |
||||
nhdp_addr_entry_t *sym_elt; |
||||
|
||||
/* Remove the given two hop entry if it was signaled as symmetric (new one is added) */ |
||||
LL_FOREACH(th_sym_list, sym_elt) { |
||||
if (ts_elt->th_nb_addr == sym_elt->address) { |
||||
/* Addresses are equal (same NHDP address db entry) */ |
||||
rem_two_hop_entry(base_entry, ts_elt); |
||||
return 1; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* Add a 2-Hop Tuple for a given address |
||||
*/ |
||||
static int add_two_hop_entry(iib_base_entry_t *base_entry, iib_link_set_entry_t *ls_entry, |
||||
nhdp_addr_t *th_addr, timex_t *now, uint64_t val_time) |
||||
{ |
||||
iib_two_hop_set_entry_t *new_entry; |
||||
timex_t v_time = timex_from_uint64(val_time * MS_IN_USEC); |
||||
|
||||
new_entry = (iib_two_hop_set_entry_t *) malloc(sizeof(iib_two_hop_set_entry_t)); |
||||
|
||||
if (!new_entry) { |
||||
/* Insufficient memory */ |
||||
return -1; |
||||
} |
||||
|
||||
/* Increment usage counter of address in central NHDP address storage */ |
||||
th_addr->usg_count++; |
||||
new_entry->th_nb_addr = th_addr; |
||||
new_entry->ls_elt = ls_entry; |
||||
new_entry->exp_time = timex_add(*now, v_time); |
||||
LL_PREPEND(base_entry->two_hop_set_head, new_entry); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* Remove a given 2-Hop Tuple |
||||
*/ |
||||
static void rem_two_hop_entry(iib_base_entry_t *base_entry, iib_two_hop_set_entry_t *th_entry) |
||||
{ |
||||
LL_DELETE(base_entry->two_hop_set_head, th_entry); |
||||
nhdp_decrement_addr_usage(th_entry->th_nb_addr); |
||||
free(th_entry); |
||||
} |
||||
|
||||
/**
|
||||
* Remove all corresponding two hop entries for a given link tuple that lost symmetry status. |
||||
* Additionally reset the neighbor tuple's symmmetry flag (for the neighbor tuple this link |
||||
* tuple is represented in), if no more corresponding symmetric link tuples are left. |
||||
* Implements section 13.2 of RFC 6130 |
||||
*/ |
||||
static void update_nb_tuple_symmetry(iib_base_entry_t *base_entry, |
||||
iib_link_set_entry_t *ls_entry, timex_t *now) |
||||
{ |
||||
iib_two_hop_set_entry_t *th_elt, *th_tmp; |
||||
|
||||
/* First remove all two hop entries for the corresponding link tuple */ |
||||
LL_FOREACH_SAFE(base_entry->two_hop_set_head, th_elt, th_tmp) { |
||||
if (th_elt->ls_elt == ls_entry) { |
||||
rem_two_hop_entry(base_entry, th_elt); |
||||
} |
||||
} |
||||
|
||||
/* Afterwards check the neighbor tuple containing the link tuple's addresses */ |
||||
if ((ls_entry->nb_elt != NULL) && (ls_entry->nb_elt->symmetric == 1)) { |
||||
iib_base_entry_t *base_tmp; |
||||
LL_FOREACH(iib_base_entry_head, base_tmp) { |
||||
iib_link_set_entry_t *ls_tmp; |
||||
LL_FOREACH(base_tmp->link_set_head, ls_tmp) { |
||||
if ((ls_entry->nb_elt == ls_tmp->nb_elt) && (ls_entry != ls_tmp)) { |
||||
if (timex_cmp(ls_tmp->sym_time, *now) == 1) { |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* No remaining symmetric link tuple for the neighbor tuple */ |
||||
nib_reset_nb_entry_sym(ls_entry->nb_elt, now); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Remove a neighbor tuple if no more corresponding heard link tuples are left |
||||
* Implements section 13.3 of RFC 6130 |
||||
*/ |
||||
static void rem_not_heard_nb_tuple(iib_link_set_entry_t *ls_entry, timex_t *now) |
||||
{ |
||||
/* Check whether the corresponding neighbor tuple still exists */ |
||||
if (ls_entry->nb_elt) { |
||||
iib_base_entry_t *base_tmp; |
||||
LL_FOREACH(iib_base_entry_head, base_tmp) { |
||||
iib_link_set_entry_t *ls_tmp; |
||||
LL_FOREACH(base_tmp->link_set_head, ls_tmp) { |
||||
if ((ls_entry->nb_elt == ls_tmp->nb_elt) && (ls_entry != ls_tmp)) { |
||||
if (timex_cmp(ls_tmp->heard_time, *now) == 1) { |
||||
return; |
||||
} |
||||
|
||||
ls_tmp->nb_elt = NULL; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* No remaining heard link tuple for the neighbor tuple */ |
||||
nib_rem_nb_entry(ls_entry->nb_elt); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Get the L_STATUS value of a given link tuple |
||||
*/ |
||||
static iib_link_tuple_status_t get_tuple_status(iib_link_set_entry_t *ls_entry, timex_t *now) |
||||
{ |
||||
if (ls_entry->pending) { |
||||
return IIB_LT_STATUS_PENDING; |
||||
} |
||||
else if (ls_entry->lost) { |
||||
return IIB_LT_STATUS_LOST; |
||||
} |
||||
else if (timex_cmp(ls_entry->sym_time, *now) == 1) { |
||||
return IIB_LT_STATUS_SYM; |
||||
} |
||||
else if (timex_cmp(ls_entry->heard_time, *now) == 1) { |
||||
return IIB_LT_STATUS_HEARD; |
||||
} |
||||
|
||||
return IIB_LT_STATUS_UNKNOWN; |
||||
} |
||||
|
||||
/**
|
||||
* Get the later one of two timex representation |
||||
*/ |
||||
static inline timex_t get_max_timex(timex_t time_one, timex_t time_two) |
||||
{ |
||||
if (timex_cmp(time_one, time_two) != -1) { |
||||
return time_one; |
||||
} |
||||
|
||||
return time_two; |
||||
} |
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 nhdp |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Interface Information Base interface for NHDP |
||||
* |
||||
* @author Fabian Nack <nack@inf.fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef IIB_TABLE_H_ |
||||
#define IIB_TABLE_H_ |
||||
|
||||
#include "timex.h" |
||||
#include "kernel_types.h" |
||||
|
||||
#include "nib_table.h" |
||||
#include "nhdp_address.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Possible L_STATUS values of a link tuple |
||||
*/ |
||||
typedef enum iib_link_tuple_status_t { |
||||
IIB_LT_STATUS_PENDING, |
||||
IIB_LT_STATUS_LOST, |
||||
IIB_LT_STATUS_HEARD, |
||||
IIB_LT_STATUS_SYM, |
||||
IIB_LT_STATUS_UNKNOWN |
||||
} iib_link_tuple_status_t; |
||||
|
||||
/**
|
||||
* @brief Link Set entry (link tuple) |
||||
*/ |
||||
typedef struct iib_link_set_entry_t { |
||||
nhdp_addr_entry_t *address_list_head; /**< Pointer to head of this tuple's addresses */ |
||||
timex_t heard_time; /**< Time at which entry leaves heard status */ |
||||
timex_t sym_time; /**< Time at which entry leaves symmetry status */ |
||||
uint8_t pending; /**< Flag whether link is pending */ |
||||
uint8_t lost; /**< Flag whether link is lost */ |
||||
timex_t exp_time; /**< Time at which entry expires */ |
||||
nib_entry_t *nb_elt; /**< Pointer to corresponding nb tuple */ |
||||
enum iib_link_tuple_status_t last_status; /**< Last processed status of link tuple */ |
||||
struct iib_link_set_entry_t *next; /**< Pointer to next list entry */ |
||||
} iib_link_set_entry_t; |
||||
|
||||
/**
|
||||
* @brief 2-Hop Set entry (2-Hop tuple) |
||||
*/ |
||||
typedef struct iib_two_hop_set_entry_t { |
||||
struct iib_link_set_entry_t *ls_elt; /**< Pointer to corresponding link tuple */ |
||||
nhdp_addr_t *th_nb_addr; /**< Address of symmetric 2-hop neighbor */ |
||||
timex_t exp_time; /**< Time at which entry expires */ |
||||
struct iib_two_hop_set_entry_t *next; /**< Pointer to next list entry */ |
||||
} iib_two_hop_set_entry_t; |
||||
|
||||
/**
|
||||
* @brief Link set for a registered interface |
||||
*/ |
||||
typedef struct iib_base_entry_t { |
||||
kernel_pid_t if_pid; /**< PID of the interface */ |
||||
struct iib_link_set_entry_t *link_set_head; /**< Pointer to this if's link tuples */ |
||||
struct iib_two_hop_set_entry_t *two_hop_set_head; /**< Pointer to this if's 2-hop tuples */ |
||||
struct iib_base_entry_t *next; /**< Pointer to next list entry */ |
||||
} iib_base_entry_t; |
||||
|
||||
/**
|
||||
* @brief Register a new interface in the IIB |
||||
* |
||||
* This function creates a new empty Link Set and a new empty 2-Hop Set for the |
||||
* given interface. |
||||
* |
||||
* @param[in] pid PID of the interface |
||||
* |
||||
* @return 0 on success |
||||
* @return -1 on error |
||||
*/ |
||||
int iib_register_if(kernel_pid_t pid); |
||||
|
||||
/**
|
||||
* @brief Process a received HELLO message in the IIB |
||||
* |
||||
* @note |
||||
* Must not be called from outside the NHDP reader's message processing. |
||||
* |
||||
* @param[in] if_pid PID of the interface the message was received on |
||||
* @param[in] nb_elt Pointer to the Neighbor Tuple for the message originator |
||||
* @param[in] send_list Pointer to the Sending Address List from the received HELLO |
||||
* @param[in] th_sym_list Pointer to the Addr List of the originator's symmetric 2-Hop neighbors |
||||
* @param[in] th_rem_list Pointer to the Addr List of the originator's lost 2-Hop neighbors |
||||
* @param[in] rem_list Pointer to the Removed Address List |
||||
* @param[in] validity_time Validity time in milliseconds for the originator's information |
||||
* @param[in] is_sym_nb Flag whether the link to the originator is symmetric |
||||
* @param[in] is_lost Flag whether the originator marked this link as lost |
||||
* |
||||
* @return 0 on success |
||||
*/ |
||||
int iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, nhdp_addr_entry_t *send_list, |
||||
nhdp_addr_entry_t *th_sym_list, nhdp_addr_entry_t *th_rem_list, |
||||
nhdp_addr_entry_t *rem_list, uint64_t validity_time, uint8_t is_sym_nb, |
||||
uint8_t is_lost); |
||||
|
||||
/**
|
||||
* @brief Add addresses to the currently constructed HELLO message |
||||
* |
||||
* @note |
||||
* Must not be called from outside the NHDP writer's message creation process. |
||||
* |
||||
* @param[in] if_pid PID of the interface the message is constructed for |
||||
* @param[in] wr The NHDP writer used for message construction |
||||
*/ |
||||
void iib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr); |
||||
|
||||
/**
|
||||
* @brief Update L_STATUS of all existing Link Tuples |
||||
* |
||||
* @note |
||||
* If a status change appears the steps described in section 13 of RFC 6130 are executed. |
||||
* |
||||
* @param[in] now Pointer to current time timex representation |
||||
*/ |
||||
void iib_update_lt_status(timex_t *now); |
||||
|
||||
/**
|
||||
* @brief Exchange the corresponding Neighbor Tuple of existing Link Tuples |
||||
* |
||||
* This function exchanges the corresponding Neighbor Tuple of every Link Tuple that |
||||
* was assigned to old_entry. Primarily used on Neighbor Tuple deletion of old_entry. |
||||
* |
||||
* @param[in] old_entry Pointer to the old corresponding Neighbor Tuple |
||||
* @param[in] new_entry Pointer to the new corresponding Neighbor Tuple |
||||
*/ |
||||
void iib_propagate_nb_entry_change(nib_entry_t *old_entry, nib_entry_t *new_entry); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* IIB_TABLE_H_ */ |
||||
/** @} */ |
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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 nhdp |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Local Information Base implementation for NHDP |
||||
* |
||||
* @author Fabian Nack <nack@inf.fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include "mutex.h" |
||||
#include "utlist.h" |
||||
#include "kernel_types.h" |
||||
|
||||
#include "rfc5444/rfc5444_iana.h" |
||||
#include "rfc5444/rfc5444_writer.h" |
||||
|
||||
#include "lib_table.h" |
||||
#include "nhdp_address.h" |
||||
#include "nhdp_writer.h" |
||||
|
||||
/* Internal variables */ |
||||
static mutex_t mtx_lib_access = MUTEX_INIT; |
||||
static lib_entry_t *lib_entry_head = NULL; |
||||
|
||||
/* Internal function prototypes */ |
||||
static int create_if_entry(kernel_pid_t if_pid, nhdp_addr_t *addr); |
||||
static int add_address_to_if(lib_entry_t *if_entry, nhdp_addr_t *addr); |
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Local Information Base API * |
||||
*---------------------------------------------------------------------------*/ |
||||
|
||||
int lib_add_if_addr(kernel_pid_t if_pid, nhdp_addr_t *addr) |
||||
{ |
||||
lib_entry_t *lib_elt; |
||||
nhdp_addr_entry_t *addr_elt; |
||||
int result = -1; |
||||
|
||||
mutex_lock(&mtx_lib_access); |
||||
|
||||
/* Check whether the given interface is already registered */ |
||||
LL_FOREACH(lib_entry_head, lib_elt) { |
||||
if (lib_elt->if_pid == if_pid) { |
||||
LL_FOREACH(lib_entry_head->if_addr_list_head, addr_elt) { |
||||
if (addr_elt->address == addr) { |
||||
/* Address already known for the interface */ |
||||
result = 0; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (result) { |
||||
/* Existing interface entry, but new address */ |
||||
result = add_address_to_if(lib_elt, addr); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (result) { |
||||
/* New interface, create a lib entry */ |
||||
result = create_if_entry(if_pid, addr); |
||||
} |
||||
|
||||
mutex_unlock(&mtx_lib_access); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
void lib_rem_if(kernel_pid_t if_pid) |
||||
{ |
||||
lib_entry_t *lib_elt, *lib_tmp; |
||||
|
||||
mutex_lock(&mtx_lib_access); |
||||
|
||||
LL_FOREACH_SAFE(lib_entry_head, lib_elt, lib_tmp) { |
||||
if (lib_elt->if_pid == if_pid) { |
||||
nhdp_free_addr_list(lib_elt->if_addr_list_head); |
||||
LL_DELETE(lib_entry_head, lib_elt); |
||||
free(lib_elt); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
mutex_unlock(&mtx_lib_access); |
||||
} |
||||
|
||||
void lib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr) |
||||
{ |
||||
lib_entry_t *lib_elt; |
||||
nhdp_addr_entry_t *add_tmp; |
||||
|
||||
mutex_lock(&mtx_lib_access); |
||||
|
||||
/* First fill the list for LOCAL_IF = THIS_IF */ |
||||
LL_FOREACH(lib_entry_head, lib_elt) { |
||||
if (lib_elt->if_pid == if_pid) { |
||||
LL_FOREACH(lib_elt->if_addr_list_head, add_tmp) { |
||||
nhdp_writer_add_addr(wr, add_tmp->address, |
||||
RFC5444_ADDRTLV_LOCAL_IF, RFC5444_LOCALIF_THIS_IF); |
||||
add_tmp->address->in_tmp_table = NHDP_ADDR_TMP_ANY; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Second fill the list for LOCAL_IF = OTHER_IF */ |
||||
LL_FOREACH(lib_entry_head, lib_elt) { |
||||
if (lib_elt->if_pid != if_pid) { |
||||
LL_FOREACH(lib_elt->if_addr_list_head, add_tmp) { |
||||
/* Check if this address is not already included in a list */ |
||||
if (!NHDP_ADDR_TMP_IN_ANY(add_tmp->address)) { |
||||
/* Address can be added */ |
||||
nhdp_writer_add_addr(wr, add_tmp->address, |
||||
RFC5444_ADDRTLV_LOCAL_IF, RFC5444_LOCALIF_OTHER_IF); |
||||
add_tmp->address->in_tmp_table = NHDP_ADDR_TMP_ANY; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
mutex_unlock(&mtx_lib_access); |
||||
} |
||||
|
||||
uint8_t lib_is_reg_addr(kernel_pid_t if_pid, nhdp_addr_t *addr) |
||||
{ |
||||
lib_entry_t *lib_elt; |
||||
nhdp_addr_entry_t *addr_elt; |
||||
|
||||
LL_FOREACH(lib_entry_head, lib_elt) { |
||||
LL_FOREACH(lib_elt->if_addr_list_head, addr_elt) { |
||||
if (addr_elt->address == addr) { |
||||
if (lib_elt->if_pid == if_pid) { |
||||
/* Given address is assigned to the given IF */ |
||||
return 1; |
||||
} |
||||
|
||||
/* Given address is assigned to any other IF */ |
||||
return 2; |
||||
} |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/*------------------------------------------------------------------------------------*/ |
||||
/* Internal functions */ |
||||
/*------------------------------------------------------------------------------------*/ |
||||
|
||||
/**
|
||||
* Create an entry for a newly registered interface |
||||
*/ |
||||
static int create_if_entry(kernel_pid_t if_pid, nhdp_addr_t *addr) |
||||
{ |
||||
lib_entry_t *new_entry; |
||||
|
||||
new_entry = (lib_entry_t *) malloc(sizeof(lib_entry_t)); |
||||
|
||||
if (!new_entry) { |
||||
/* Insufficient memory */ |
||||
return -1; |
||||
} |
||||
|
||||
new_entry->if_addr_list_head = NULL; |
||||
new_entry->if_pid = if_pid; |
||||
|
||||
if (add_address_to_if(new_entry, addr)) { |
||||
/* Insufficient memory */ |
||||
free(new_entry); |
||||
return -1; |
||||
} |
||||
|
||||
LL_PREPEND(lib_entry_head, new_entry); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* Add another address to an interface entry |
||||
*/ |
||||
static int add_address_to_if(lib_entry_t *if_entry, nhdp_addr_t *addr) |
||||
{ |
||||
nhdp_addr_entry_t *new_entry = (nhdp_addr_entry_t *) malloc(sizeof(nhdp_addr_entry_t)); |
||||
|
||||
if (!new_entry) { |
||||
/* Insufficient memory */ |
||||
return -1; |
||||
} |
||||
|
||||
/* Increment usage counter of address in central NHDP address storage */ |
||||
addr->usg_count++; |
||||
new_entry->address = addr; |
||||
LL_PREPEND(if_entry->if_addr_list_head, new_entry); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 nhdp |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Local Information Base interface for NHDP |
||||
* |
||||
* @author Fabian Nack <nack@inf.fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef LIB_TABLE_H_ |
||||
#define LIB_TABLE_H_ |
||||
|
||||
#include "kernel_types.h" |
||||
|
||||
#include "rfc5444/rfc5444_writer.h" |
||||
|
||||
#include "nhdp_address.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Local Interface Set entry (local interface tuple) |
||||
*/ |
||||
typedef struct lib_entry_t { |
||||
kernel_pid_t if_pid; /**< PID of the interface's handling thread */ |
||||
nhdp_addr_entry_t *if_addr_list_head; /**< Pointer to head of this interface's addr list */ |
||||
struct lib_entry_t *next; /**< Pointer to next list entry */ |
||||
} lib_entry_t; |
||||
|
||||
/**
|
||||
* @brief Add an interface to the Local Information Base |
||||
* |
||||
* This function can also be used to add an additional address to an existing LIB tuple. |
||||
* |
||||
* @param[in] if_pid PID of the interface |
||||
* @param[in] addr The (additional) NHDP address to register for the interface |
||||
* |
||||
* @return 0 on success |
||||
* @return -1 on error |
||||
*/ |
||||
int lib_add_if_addr(kernel_pid_t if_pid, nhdp_addr_t *addr); |
||||
|
||||
/**
|
||||
* @brief Remove a given interface's Local Information Base entry |
||||
* |
||||
* @param[in] if_pid PID of the interface that should be removed |
||||
*/ |
||||
void lib_rem_if(kernel_pid_t if_pid); |
||||
|
||||
/**
|
||||
* @brief Add addresses to the currently constructed HELLO message |
||||
* |
||||
* @note |
||||
* Must not be called from outside the NHDP writer's message creation process. |
||||
* |
||||
* @param[in] if_pid PID of the interface the message is constructed for |
||||
* @param[in] wr The NHDP writer used for message construction |
||||
*/ |
||||
void lib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr); |
||||
|
||||
/**
|
||||
* @brief Check whether a given NHDP address is used as a local address |
||||
* |
||||
* @param[in] if_pid PID of the interface to check for |
||||
* @param[in] addr Pointer to the NHDP address that has to be checked |
||||
* |
||||
* @return 1 if the given address is assigned to the given interface |
||||
* @return 2 if the given address is assigned to any other local interface |
||||
* @return 0 otherwise |
||||
*/ |
||||
uint8_t lib_is_reg_addr(kernel_pid_t if_pid, nhdp_addr_t *addr); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* LIB_TABLE_H_ */ |
||||
/** @} */ |
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* 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 nhdp |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Implementation of NHDP's core functionality |
||||
* |
||||
* @author Fabian Nack <nack@inf.fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include "msg.h" |
||||
#include "netapi.h" |
||||
#include "thread.h" |
||||
#include "utlist.h" |
||||
#include "mutex.h" |
||||
|
||||
#include "rfc5444/rfc5444_writer.h" |
||||
|
||||
#include "lib_table.h" |
||||
#include "iib_table.h" |
||||
#include "nib_table.h" |
||||
#include "nhdp.h" |
||||
#include "nhdp_address.h" |
||||
#include "nhdp_writer.h" |
||||
#include "nhdp_reader.h" |
||||
|
||||
char nhdp_stack[NHDP_STACK_SIZE]; |
||||
char nhdp_rcv_stack[NHDP_STACK_SIZE]; |
||||
|
||||
/* Internal variables */ |
||||
static kernel_pid_t nhdp_pid = KERNEL_PID_UNDEF; |
||||
static kernel_pid_t nhdp_rcv_pid = KERNEL_PID_UNDEF; |
||||
static kernel_pid_t helper_pid = KERNEL_PID_UNDEF; |
||||
static nhdp_if_entry_t *nhdp_if_entry_head = NULL; |
||||
static mutex_t send_rcv_mutex = MUTEX_INIT; |
||||
static sockaddr6_t sa_bcast; |
||||
static int sock_rcv; |
||||
|
||||
/* Internal function prototypes */ |
||||
static void *_nhdp_runner(void *arg __attribute__((unused))); |
||||
static void *_nhdp_receiver(void *arg __attribute__((unused))); |
||||
static void write_packet(struct rfc5444_writer *wr __attribute__((unused)), |
||||
struct rfc5444_writer_target *iface __attribute__((unused)), |
||||
void *buffer, size_t length); |
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* NHDP Core API * |
||||
*---------------------------------------------------------------------------*/ |
||||
|
||||
void nhdp_init(void) |
||||
{ |
||||
if (nhdp_pid != KERNEL_PID_UNDEF) { |
||||
/* do not initialize twice */ |
||||
return; |
||||
} |
||||
|
||||
/* Initialize reader and writer */ |
||||
nhdp_writer_init(); |
||||
nhdp_reader_init(); |
||||
} |
||||
|
||||
kernel_pid_t nhdp_start(void) |
||||
{ |
||||
if (nhdp_pid == KERNEL_PID_UNDEF) { |
||||
/* Init destination address for NHDP's packets */ |
||||
sa_bcast.sin6_family = AF_INET6; |
||||
sa_bcast.sin6_port = HTONS(MANET_PORT); |
||||
ipv6_addr_set_all_nodes_addr(&sa_bcast.sin6_addr); |
||||
|
||||
/* Configure sending/receiving UDP socket */ |
||||
sock_rcv = socket_base_socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
||||
|
||||
/* Start the NHDP thread */ |
||||
nhdp_pid = thread_create(nhdp_stack, sizeof(nhdp_stack), PRIORITY_MAIN - 1, |
||||
CREATE_STACKTEST, _nhdp_runner, NULL, "NHDP"); |
||||
} |
||||
|
||||
return nhdp_pid; |
||||
} |
||||
|
||||
int nhdp_register_if_default(kernel_pid_t if_pid, uint8_t *addr, size_t addr_size, |
||||
uint8_t addr_type, uint16_t max_pl_size) |
||||
{ |
||||
return nhdp_register_if(if_pid, addr, addr_size, addr_type, max_pl_size, |
||||
NHDP_DEFAULT_HELLO_INT_MS, NHDP_DEFAULT_HOLD_TIME_MS); |
||||
} |
||||
|
||||
int nhdp_register_if(kernel_pid_t if_pid, uint8_t *addr, size_t addr_size, uint8_t addr_type, |
||||
uint16_t max_pl_size, uint16_t hello_int_ms, uint16_t val_time_ms) |
||||
{ |
||||
nhdp_if_entry_t *if_entry; |
||||
nhdp_addr_t *nhdp_addr; |
||||
msg_t signal_msg; |
||||
|
||||
if (nhdp_rcv_pid != KERNEL_PID_UNDEF) { |
||||
return -2; |
||||
} |
||||
|
||||
if_entry = (nhdp_if_entry_t *) malloc(sizeof(nhdp_if_entry_t)); |
||||
|
||||
if (!if_entry) { |
||||
/* Insufficient memory */ |
||||
return -1; |
||||
} |
||||
|
||||
/* Create an interface writer targer for the nhdp_writer */ |
||||
if_entry->wr_target = (struct rfc5444_writer_target *) |
||||
calloc(1, sizeof(struct rfc5444_writer_target)); |
||||
|
||||
if (!if_entry->wr_target) { |
||||
/* Insufficient memory */ |
||||
free(if_entry); |
||||
return -1; |
||||
} |
||||
|
||||
uint16_t payload_size = max_pl_size > NHDP_MAX_RFC5444_PACKET_SZ |
||||
? NHDP_MAX_RFC5444_PACKET_SZ : max_pl_size; |
||||
if_entry->wr_target->packet_buffer = (uint8_t *) calloc(payload_size, sizeof(uint8_t)); |
||||
|
||||
if (!if_entry->wr_target->packet_buffer) { |
||||
/* Insufficient memory */ |
||||
free(if_entry->wr_target); |
||||
free(if_entry); |
||||
return -1; |
||||
} |
||||
|
||||
if_entry->wr_target->packet_size = payload_size; |
||||
if_entry->wr_target->sendPacket = write_packet; |
||||
|
||||
/* Get NHDP address entry for the given address */ |
||||
nhdp_addr = nhdp_addr_db_get_address(addr, addr_size, addr_type); |
||||
|
||||
if (!nhdp_addr) { |
||||
/* Insufficient memory */ |
||||
free(if_entry->wr_target->packet_buffer); |
||||
free(if_entry->wr_target); |
||||
free(if_entry); |
||||
return -1; |
||||
} |
||||
|
||||
/* Set Interface's PID */ |
||||
if_entry->if_pid = if_pid; |
||||
/* Set HELLO_INTERVAL and H_HOLD_TIME (validity time) */ |
||||
if_entry->hello_interval.seconds = 0; |
||||
if_entry->hello_interval.microseconds = MS_IN_USEC * hello_int_ms; |
||||
if_entry->validity_time.seconds = 0; |
||||
if_entry->validity_time.microseconds = MS_IN_USEC * val_time_ms; |
||||
timex_normalize(&if_entry->hello_interval); |
||||
timex_normalize(&if_entry->validity_time); |
||||
|
||||
/* Add the interface to the LIB */ |
||||
if (lib_add_if_addr(if_entry->if_pid, nhdp_addr) != 0) { |
||||
free(if_entry->wr_target->packet_buffer); |
||||
free(if_entry->wr_target); |
||||
free(if_entry); |
||||
nhdp_decrement_addr_usage(nhdp_addr); |
||||
return -1; |
||||
} |
||||
|
||||
/* Create new IIB for the interface */ |
||||
if (iib_register_if(if_pid) != 0) { |
||||
/* TODO: Cleanup lib entry */ |
||||
free(if_entry->wr_target->packet_buffer); |
||||
free(if_entry->wr_target); |
||||
free(if_entry); |
||||
nhdp_decrement_addr_usage(nhdp_addr); |
||||
return -1; |
||||
} |
||||
|
||||
/* Everything went well */ |
||||
nhdp_decrement_addr_usage(nhdp_addr); |
||||
nhdp_writer_register_if(if_entry->wr_target); |
||||
LL_PREPEND(nhdp_if_entry_head, if_entry); |
||||
helper_pid = if_pid; |
||||
|
||||
/* Start the receiving thread */ |
||||
nhdp_rcv_pid = thread_create(nhdp_rcv_stack, sizeof(nhdp_rcv_stack), PRIORITY_MAIN - 1, |
||||
CREATE_STACKTEST, _nhdp_receiver, NULL, "nhdp_rcv_thread"); |
||||
|
||||
/* Start sending periodic HELLO */ |
||||
signal_msg.type = MSG_TIMER; |
||||
signal_msg.content.ptr = (char *) if_entry; |
||||
/* TODO: msg_send or msg_try_send? */ |
||||
msg_try_send(&signal_msg, nhdp_pid); |
||||
|
||||
return 0; |
||||
} |
||||