mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
242 lines
7.1 KiB
C
242 lines
7.1 KiB
C
/*
|
|
* Copyright (C) 2014 Freie Universität Berlin
|
|
* Copyright (C) 2014 Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
|
|
*
|
|
* 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 aodvv2
|
|
* @{
|
|
*
|
|
* @file utils.c
|
|
* @brief client- and RREQ-table, ipv6 address representation converters
|
|
*
|
|
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
|
|
*/
|
|
|
|
#include "utils.h"
|
|
|
|
#include "aodv_debug.h"
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
#include "debug.h"
|
|
|
|
/* Some aodvv2 utilities (mostly tables) */
|
|
static mutex_t clientt_mutex;
|
|
static mutex_t rreqt_mutex;
|
|
|
|
/* helper functions */
|
|
static struct aodvv2_rreq_entry *_get_comparable_rreq(struct aodvv2_packet_data *packet_data);
|
|
static void _add_rreq(struct aodvv2_packet_data *packet_data);
|
|
static void _reset_entry_if_stale(uint8_t i);
|
|
|
|
static struct netaddr client_table[AODVV2_MAX_CLIENTS];
|
|
static struct aodvv2_rreq_entry rreq_table[AODVV2_RREQ_BUF];
|
|
|
|
#if ENABLE_DEBUG
|
|
static struct netaddr_str nbuf;
|
|
#endif
|
|
static timex_t null_time, now, _max_idletime;
|
|
|
|
|
|
void clienttable_init(void)
|
|
{
|
|
mutex_lock(&clientt_mutex);
|
|
memset(&client_table, 0, sizeof(client_table));
|
|
mutex_unlock(&clientt_mutex);
|
|
|
|
AODV_DEBUG("client table initialized.\n");
|
|
}
|
|
|
|
void clienttable_add_client(struct netaddr *addr)
|
|
{
|
|
if (clienttable_is_client(addr)){
|
|
return;
|
|
}
|
|
|
|
/*find free spot in client table and place client address there */
|
|
mutex_lock(&clientt_mutex);
|
|
for (unsigned i = 0; i < AODVV2_MAX_CLIENTS; i++) {
|
|
if ((client_table[i]._type == AF_UNSPEC) &&
|
|
(client_table[i]._prefix_len == 0)) {
|
|
client_table[i] = *addr;
|
|
AODV_DEBUG("clienttable: added client %s\n",
|
|
netaddr_to_string(&nbuf, addr));
|
|
mutex_unlock(&clientt_mutex);
|
|
return;
|
|
}
|
|
}
|
|
AODV_DEBUG("Error: Client could not be added: Client table is full.\n");
|
|
mutex_unlock(&clientt_mutex);
|
|
}
|
|
|
|
bool clienttable_is_client(struct netaddr *addr)
|
|
{
|
|
mutex_lock(&clientt_mutex);
|
|
for (unsigned i = 0; i < AODVV2_MAX_CLIENTS; i++) {
|
|
if (!netaddr_cmp(&client_table[i], addr)) {
|
|
mutex_unlock(&clientt_mutex);
|
|
return true;
|
|
}
|
|
}
|
|
mutex_unlock(&clientt_mutex);
|
|
return false;
|
|
}
|
|
|
|
void clienttable_delete_client(struct netaddr *addr)
|
|
{
|
|
if (!clienttable_is_client(addr)) {
|
|
return;
|
|
}
|
|
|
|
mutex_lock(&clientt_mutex);
|
|
for (unsigned i = 0; i < AODVV2_MAX_CLIENTS; i++) {
|
|
if (!netaddr_cmp(&client_table[i], addr)) {
|
|
memset(&client_table[i], 0, sizeof(client_table[i]));
|
|
mutex_unlock(&clientt_mutex);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void rreqtable_init(void)
|
|
{
|
|
mutex_lock(&rreqt_mutex);
|
|
null_time = timex_set(0, 0);
|
|
_max_idletime = timex_set(AODVV2_MAX_IDLETIME, 0);
|
|
|
|
memset(&rreq_table, 0, sizeof(rreq_table));
|
|
mutex_unlock(&rreqt_mutex);
|
|
AODV_DEBUG("RREQ table initialized.\n");
|
|
}
|
|
|
|
bool rreqtable_is_redundant(struct aodvv2_packet_data *packet_data)
|
|
{
|
|
struct aodvv2_rreq_entry *comparable_rreq;
|
|
timex_t now;
|
|
bool result = false;
|
|
|
|
mutex_lock(&rreqt_mutex);
|
|
comparable_rreq = _get_comparable_rreq(packet_data);
|
|
|
|
/* if there is no comparable rreq stored, add one and return false */
|
|
if (comparable_rreq == NULL) {
|
|
_add_rreq(packet_data);
|
|
}
|
|
else {
|
|
int seqnum_comparison = seqnum_cmp(packet_data->origNode.seqnum, comparable_rreq->seqnum);
|
|
|
|
/*
|
|
* If two RREQs have the same
|
|
* metric type and OrigNode and Targnode addresses, the information from
|
|
* the one with the older Sequence Number is not needed in the table
|
|
*/
|
|
if (seqnum_comparison == -1) {
|
|
result = true;
|
|
}
|
|
|
|
if (seqnum_comparison == 1) {
|
|
/* Update RREQ table entry with new seqnum and metric value */
|
|
comparable_rreq->seqnum = packet_data->origNode.seqnum;
|
|
comparable_rreq->metric = packet_data->origNode.metric;
|
|
}
|
|
|
|
/*
|
|
* in case they have the same Sequence Number, the one with the greater
|
|
* Metric value is not needed
|
|
*/
|
|
if (seqnum_comparison == 0) {
|
|
if (comparable_rreq->metric <= packet_data->origNode.metric) {
|
|
result = true;
|
|
}
|
|
/* Update RREQ table entry with new metric value */
|
|
comparable_rreq->metric = packet_data->origNode.metric;
|
|
}
|
|
|
|
/* Since we've changed RREQ info, update the timestamp */
|
|
vtimer_now(&now);
|
|
comparable_rreq->timestamp = now;
|
|
}
|
|
|
|
mutex_unlock(&rreqt_mutex);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* retrieve pointer to a comparable (according to Section 6.7.)
|
|
* RREQ table entry if it exists and NULL otherwise.
|
|
* Two AODVv2 RREQ messages are comparable if:
|
|
* - they have the same metric type
|
|
* - they have the same OrigNode and TargNode addresses
|
|
*/
|
|
static struct aodvv2_rreq_entry *_get_comparable_rreq(struct aodvv2_packet_data *packet_data)
|
|
{
|
|
for (unsigned i = 0; i < AODVV2_RREQ_BUF; i++) {
|
|
_reset_entry_if_stale(i);
|
|
|
|
if (!netaddr_cmp(&rreq_table[i].origNode, &packet_data->origNode.addr)
|
|
&& !netaddr_cmp(&rreq_table[i].targNode, &packet_data->targNode.addr)
|
|
&& rreq_table[i].metricType == packet_data->metricType) {
|
|
return &rreq_table[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void _add_rreq(struct aodvv2_packet_data *packet_data)
|
|
{
|
|
if (_get_comparable_rreq(packet_data)) {
|
|
return;
|
|
}
|
|
/*find empty rreq and fill it with packet_data */
|
|
|
|
for (unsigned i = 0; i < AODVV2_RREQ_BUF; i++) {
|
|
if (!rreq_table[i].timestamp.seconds &&
|
|
!rreq_table[i].timestamp.microseconds) {
|
|
rreq_table[i].origNode = packet_data->origNode.addr;
|
|
rreq_table[i].targNode = packet_data->targNode.addr;
|
|
rreq_table[i].metricType = packet_data->metricType;
|
|
rreq_table[i].metric = packet_data->origNode.metric;
|
|
rreq_table[i].seqnum = packet_data->origNode.seqnum;
|
|
rreq_table[i].timestamp = packet_data->timestamp;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if entry at index i is stale and clear the struct it fills if it is
|
|
*/
|
|
static void _reset_entry_if_stale(uint8_t i)
|
|
{
|
|
vtimer_now(&now);
|
|
|
|
if (timex_cmp(rreq_table[i].timestamp, null_time) == 0) {
|
|
return;
|
|
}
|
|
timex_t expiration_time = timex_add(rreq_table[i].timestamp, _max_idletime);
|
|
if (timex_cmp(expiration_time, now) < 0) {
|
|
/* timestamp+expiration time is in the past: this entry is stale */
|
|
DEBUG("\treset rreq table entry %s\n",
|
|
netaddr_to_string(&nbuf, &rreq_table[i].origNode));
|
|
memset(&rreq_table[i], 0, sizeof(rreq_table[i]));
|
|
}
|
|
}
|
|
|
|
void ipv6_addr_t_to_netaddr(ipv6_addr_t *src, struct netaddr *dst)
|
|
{
|
|
dst->_type = AF_INET6;
|
|
dst->_prefix_len = AODVV2_RIOT_PREFIXLEN;
|
|
memcpy(dst->_addr, src, sizeof(dst->_addr));
|
|
}
|
|
|
|
void netaddr_to_ipv6_addr_t(struct netaddr *src, ipv6_addr_t *dst)
|
|
{
|
|
memcpy(dst, src->_addr, sizeof(uint8_t) * NETADDR_MAX_LENGTH);
|
|
}
|