1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-15 09:33:50 +01:00

sys: net: remove AODVv2

(will be upgraded to gnrc soon)
This commit is contained in:
Kaspar Schleiser 2015-08-05 12:33:22 +02:00
parent 9db612cd53
commit 00a44c9147
25 changed files with 0 additions and 3770 deletions

View File

@ -40,9 +40,6 @@ endif
ifneq (,$(filter routing,$(USEMODULE)))
DIRS += net/routing
endif
ifneq (,$(filter aodvv2,$(USEMODULE)))
DIRS += net/routing/aodvv2
endif
ifneq (,$(filter ieee802154,$(USEMODULE)))
DIRS += net/link_layer/ieee802154
endif

View File

@ -1,52 +0,0 @@
/*
* 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.
*/
/**
* @defgroup aodvv2 AODVv2
* @brief The Ad-hoc On-demand Distance Vector routing protocol, version 2
* @ingroup net
* @{
*
* @file
* @brief Interface for the AODVv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_H_
#define AODVV2_H_
#include "common/netaddr.h"
#include "rfc5444/rfc5444_print.h"
#include "aodvv2/types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize the AODVv2 routing protocol.
*/
void aodv_init(void);
/**
* @brief Set the metric type. If metric_type does not match any known metric
* types, no changes will be made.
*
* @param[in] metric_type type of new metric
*/
void aodv_set_metric_type(aodvv2_metric_t metric_type);
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_H_ */
/** @} */

View File

@ -1,102 +0,0 @@
/*
* 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
* @brief data types for the aodvv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_TYPES_H
#define AODVV2_TYPES_H
#include "common/netaddr.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief AODVv2 metric types. Extend to include alternate metrics.
*/
typedef enum {
HOP_COUNT = 3, /**< see RFC6551*/
} aodvv2_metric_t;
typedef uint16_t aodvv2_seqnum_t;
#define AODVV2_DEFAULT_METRIC_TYPE HOP_COUNT
/**
* @brief AODVv2 message types
*/
enum rfc5444_msg_type
{
RFC5444_MSGTYPE_RREQ = 10,
RFC5444_MSGTYPE_RREP = 11,
RFC5444_MSGTYPE_RERR = 12,
};
/**
* @brief AODVv2 TLV types
*/
enum rfc5444_tlv_type
{
RFC5444_MSGTLV_ORIGSEQNUM,
RFC5444_MSGTLV_TARGSEQNUM,
RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM,
RFC5444_MSGTLV_METRIC,
};
/**
* @brief Data about an OrigNode or TargNode, typically embedded in an
* aodvv2_packet_data struct.
*/
struct node_data
{
struct netaddr addr; /**< IP address of the node */
uint8_t metric; /**< Metric value */
aodvv2_seqnum_t seqnum; /**< Sequence Number */
};
/**
* @brief all data contained in a RREQ or RREP.
*/
struct aodvv2_packet_data
{
uint8_t hoplimit; /**< Hop limit */
struct netaddr sender; /**< IP address of the neighboring router
* which sent the RREQ/RREP*/
aodvv2_metric_t metricType; /**< Metric type */
struct node_data origNode; /**< Data about the originating node */
struct node_data targNode; /**< Data about the originating node */
timex_t timestamp; /**< point at which the packet was (roughly)
* received. Note that this timestamp
* will be set after the packet has been
* successfully parsed. */
};
/**
* @brief Data about an unreachable node to be embedded in a RERR.
*/
struct unreachable_node
{
struct netaddr addr; /**< IP address */
aodvv2_seqnum_t seqnum; /**< Sequence Number */
};
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_TYPES_H */

View File

@ -1 +0,0 @@
include $(RIOTBASE)/Makefile.base

View File

@ -1,478 +0,0 @@
/*
* 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
* @brief aodvv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#include "aodv.h"
#include "aodvv2/aodvv2.h"
#include "aodv_debug.h"
#include "ng_fib.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define UDP_BUFFER_SIZE (128) /** with respect to IEEE 802.15.4's MTU */
#define RCV_MSG_Q_SIZE (32) /* TODO: check if smaller values work, too */
static void _init_addresses(void);
static void _init_sock_snd(void);
static void *_aodv_receiver_thread(void *arg);
static void *_aodv_sender_thread(void *arg);
static void *fib_signal_handler_thread(void *arg);
static void _deep_free_msg_container(struct msg_container *msg_container);
static void _write_packet(struct rfc5444_writer *wr __attribute__ ((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length);
static void print_json_pkt_sent(struct writer_target *wt);
#if AODV_DEBUG
char addr_str[IPV6_MAX_ADDR_STR_LEN];
static struct netaddr_str nbuf;
#endif
#if TEST_SETUP
static struct netaddr_str nbuf_origaddr, nbuf_targaddr, nbuf_nexthop;
#endif
static char aodv_rcv_stack_buf[THREAD_STACKSIZE_MAIN];
static char aodv_snd_stack_buf[THREAD_STACKSIZE_MAIN];
static char aodv_fib_stack_buf[THREAD_STACKSIZE_MAIN];
static aodvv2_metric_t _metric_type;
static int sender_thread;
static int _sock_snd;
static struct autobuf _hexbuf;
static sockaddr6_t sa_wp;
static ipv6_addr_t _v6_addr_local, _v6_addr_mcast, _v6_addr_loopback;
static struct netaddr na_local; /* the same as _v6_addr_local, but to save us
* constant calls to ipv6_addr_t_to_netaddr()... */
static struct writer_target *wt;
static mutex_t rreq_mutex;
static mutex_t rrep_mutex;
static mutex_t rerr_mutex;
struct netaddr na_mcast;
kernel_pid_t aodvv2_if_id;
ipv6_addr_t aodvv2_prefix;
int aodvv2_prefix_len;
void aodv_init(void)
{
AODV_DEBUG("%s()\n", __func__);
/* init this thread's IPC msg queue (TODO: do I need to do this?) */
msg_t msgq[RCV_MSG_Q_SIZE];
msg_init_queue(msgq, sizeof msgq);
/* TODO: set & handle prefix and prefix_len properly (consider AODVV2_RIOT_PREFIXLEN!) */
aodvv2_prefix_len = 0;
/* TODO: set if_id properly (as param of aodv_init) */
aodvv2_if_id = 0;
net_if_set_src_address_mode(aodvv2_if_id, NET_IF_TRANS_ADDR_M_SHORT);
mutex_init(&rreq_mutex);
mutex_init(&rrep_mutex);
mutex_init(&rerr_mutex);
aodv_set_metric_type(AODVV2_DEFAULT_METRIC_TYPE);
_init_addresses();
_init_sock_snd();
/* init ALL the things! \o, */
seqnum_init();
routingtable_init();
clienttable_init();
/* every node is its own client. */
clienttable_add_client(&na_local);
rreqtable_init();
/* init reader and writer */
aodv_packet_reader_init();
aodv_packet_writer_init(_write_packet);
/* start listening & enable sending */
thread_create(aodv_rcv_stack_buf, sizeof(aodv_rcv_stack_buf), THREAD_PRIORITY_MAIN,
CREATE_STACKTEST, _aodv_receiver_thread, NULL, "_aodv_receiver_thread");
AODV_DEBUG("listening on port %d\n", HTONS(MANET_PORT));
sender_thread = thread_create(aodv_snd_stack_buf, sizeof(aodv_snd_stack_buf),
THREAD_PRIORITY_MAIN, CREATE_STACKTEST, _aodv_sender_thread,
NULL, "_aodv_sender_thread");
thread_create(aodv_fib_stack_buf, sizeof(aodv_fib_stack_buf),
THREAD_PRIORITY_MAIN, CREATE_STACKTEST, fib_signal_handler_thread,
NULL, "fib_signal_handler_thread");
}
void aodv_set_metric_type(aodvv2_metric_t metric_type)
{
if (metric_type != AODVV2_DEFAULT_METRIC_TYPE) {
return;
}
_metric_type = metric_type;
}
/*
* @brief handles callbacks from the FIB when it needs a route
*/
void *fib_signal_handler_thread(void *arg)
{
(void) arg;
ipv6_addr_t dest;
struct netaddr na_dest;
fib_register_rp((uint8_t*) &aodvv2_prefix, aodvv2_prefix_len);
while (true) {
msg_t msg;
msg_receive(&msg);
if (msg.type == FIB_MSG_RP_SIGNAL) {
rp_address_msg_t* rp_msg = (rp_address_msg_t*)msg.content.ptr;
if (rp_msg->address_size == sizeof(ipv6_addr_t)) {
/* We currently only support IPv6*/
memcpy(&dest, rp_msg->address, rp_msg->address_size);
/* Reply to the FIB so that it can stop blocking */
msg_reply(&msg, &msg);
/* perform/initiate a rreq for dst here*/
ipv6_addr_t_to_netaddr(&dest, &na_dest);
aodvv2_seqnum_t seqnum = seqnum_get();
seqnum_inc();
/* Build new RREQ */
struct aodvv2_packet_data rreq_data = (struct aodvv2_packet_data) {
.hoplimit = AODVV2_MAX_HOPCOUNT,
.metricType = _metric_type,
.origNode = (struct node_data) {
.addr = na_local,
.metric = 0,
.seqnum = seqnum,
},
.targNode = (struct node_data) {
.addr = na_dest,
},
.timestamp = (timex_t) {0,0} /* this timestamp is never used, it exists
* merely to make the compiler shut up */
};
AODV_DEBUG("\tstarting route discovery towards %s... \n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &dest));
aodv_send_rreq(&rreq_data);
}
else {
/* Reply to the FIB so that it can stop blocking */
msg_reply(&msg, &msg);
}
}
}
return NULL;
}
void aodv_send_rreq(struct aodvv2_packet_data *packet_data)
{
/* Make sure only one thread is dispatching a RREQ at a time */
mutex_lock(&rreq_mutex);
struct aodvv2_packet_data *pd = malloc(sizeof(struct aodvv2_packet_data));
memcpy(pd, packet_data, sizeof(struct aodvv2_packet_data));
struct rreq_rrep_data *rd = malloc(sizeof(struct rreq_rrep_data));
*rd = (struct rreq_rrep_data) {
.next_hop = &na_mcast,
.packet_data = pd,
};
struct msg_container *mc = malloc(sizeof(struct msg_container));
*mc = (struct msg_container) {
.type = RFC5444_MSGTYPE_RREQ,
.data = rd
};
msg_t msg;
msg.content.ptr = (char *) mc;
msg_try_send(&msg, sender_thread);
mutex_unlock(&rreq_mutex);
}
void aodv_send_rrep(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop)
{
/* Make sure only one thread is dispatching a RREP at a time */
mutex_lock(&rrep_mutex);
struct aodvv2_packet_data *pd = malloc(sizeof(struct aodvv2_packet_data));
memcpy(pd, packet_data, sizeof(struct aodvv2_packet_data));
struct netaddr *nh = malloc(sizeof(struct netaddr));
memcpy(nh, next_hop, sizeof(struct netaddr));
struct rreq_rrep_data *rd = malloc(sizeof(struct rreq_rrep_data));
*rd = (struct rreq_rrep_data) {
.next_hop = nh,
.packet_data = pd,
};
struct msg_container *mc = malloc(sizeof(struct msg_container));
*mc = (struct msg_container) {
.type = RFC5444_MSGTYPE_RREP,
.data = rd
};
msg_t msg;
msg.content.ptr = (char *) mc;
msg_try_send(&msg, sender_thread);
mutex_unlock(&rrep_mutex);
}
void aodv_send_rerr(struct unreachable_node unreachable_nodes[], size_t len, struct netaddr *next_hop)
{
/* Make sure only one thread is dispatching a RERR at a time */
mutex_lock(&rerr_mutex);
struct rerr_data *rerrd = malloc(sizeof(struct rerr_data));
*rerrd = (struct rerr_data) {
.unreachable_nodes = unreachable_nodes,
.len = len,
.hoplimit = AODVV2_MAX_HOPCOUNT,
.next_hop = next_hop
};
struct msg_container *mc2 = malloc(sizeof(struct msg_container));
*mc2 = (struct msg_container) {
.type = RFC5444_MSGTYPE_RERR,
.data = rerrd
};
msg_t msg2;
msg2.content.ptr = (char *) mc2;
msg_try_send(&msg2, sender_thread);
mutex_unlock(&rerr_mutex);
}
/*
* init the multicast address all RREQ and RERRS are sent to
* and the local address (source address) of this node
*/
static void _init_addresses(void)
{
/* init multicast address: set to to a link-local all nodes multicast address */
ipv6_addr_set_all_nodes_addr(&_v6_addr_mcast);
AODV_DEBUG("my multicast address is: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_mcast));
/* get best IP for sending */
ipv6_net_if_get_best_src_addr(&_v6_addr_local, &_v6_addr_mcast);
AODV_DEBUG("my src address is: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_local));
/* store src & multicast address as netaddr as well for easy interaction
* with oonf based stuff */
ipv6_addr_t_to_netaddr(&_v6_addr_local, &na_local);
ipv6_addr_t_to_netaddr(&_v6_addr_mcast, &na_mcast);
ipv6_addr_set_loopback_addr(&_v6_addr_loopback);
/* init sockaddr that write_packet will use to send data */
sa_wp.sin6_family = AF_INET6;
sa_wp.sin6_port = HTONS(MANET_PORT);
}
/* init socket communication for sender */
static void _init_sock_snd(void)
{
_sock_snd = socket_base_socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == _sock_snd) {
AODV_DEBUG("Error Creating Socket!\n");
}
}
/* Build RREQs, RREPs and RERRs from the information contained in the thread's
* message queue and send them */
static void *_aodv_sender_thread(void *arg)
{
(void) arg;
msg_t msgq[RCV_MSG_Q_SIZE];
msg_init_queue(msgq, RCV_MSG_Q_SIZE);
while (true) {
msg_t msg;
msg_receive(&msg);
struct msg_container *mc = (struct msg_container *) msg.content.ptr;
if (mc->type == RFC5444_MSGTYPE_RREQ) {
struct rreq_rrep_data *rreq_data = (struct rreq_rrep_data *) mc->data;
aodv_packet_writer_send_rreq(rreq_data->packet_data, rreq_data->next_hop);
}
else if (mc->type == RFC5444_MSGTYPE_RREP) {
struct rreq_rrep_data *rrep_data = (struct rreq_rrep_data *) mc->data;
aodv_packet_writer_send_rrep(rrep_data->packet_data, rrep_data->next_hop);
}
else if (mc->type == RFC5444_MSGTYPE_RERR) {
struct rerr_data *rerr_data = (struct rerr_data *) mc->data;
aodv_packet_writer_send_rerr(rerr_data->unreachable_nodes, rerr_data->len,
rerr_data->hoplimit, rerr_data->next_hop);
}
else {
AODV_DEBUG("ERROR: Couldn't identify Message\n");
}
_deep_free_msg_container(mc);
}
return NULL;
}
/* receive RREQs, RREPs and RERRs and handle them */
static void *_aodv_receiver_thread(void *arg)
{
(void) arg;
uint32_t fromlen;
char buf_rcv[UDP_BUFFER_SIZE];
msg_t msg_q[RCV_MSG_Q_SIZE];
msg_init_queue(msg_q, RCV_MSG_Q_SIZE);
sockaddr6_t sa_rcv = { .sin6_family = AF_INET6,
.sin6_port = HTONS(MANET_PORT)
};
int sock_rcv = socket_base_socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == socket_base_bind(sock_rcv, &sa_rcv, sizeof(sa_rcv))) {
AODV_DEBUG("Error: bind to receive socket failed!\n");
socket_base_close(sock_rcv);
return NULL;
}
while (true) {
int32_t rcv_size = socket_base_recvfrom(sock_rcv, (void *)buf_rcv, UDP_BUFFER_SIZE, 0,
&sa_rcv, &fromlen);
if (rcv_size < 0) {
AODV_DEBUG("ERROR receiving data!\n");
}
struct netaddr _sender;
ipv6_addr_t_to_netaddr(&sa_rcv.sin6_addr, &_sender);
/* We sometimes get passed our own packets. Drop them. */
if (netaddr_cmp(&_sender, &na_local) == 0) {
AODV_DEBUG("received our own packet, dropping it.\n");
}
else {
aodv_packet_reader_handle_packet((void *) buf_rcv, rcv_size, &_sender);
}
}
socket_base_close(sock_rcv);
return NULL;
}
/**
* Handle the output of the RFC5444 packet creation process. This callback is
* called by every writer_send_* function.
*/
static void _write_packet(struct rfc5444_writer *wr __attribute__ ((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length)
{
AODV_DEBUG("%s()\n", __func__);
/* generate hexdump and human readable representation of packet
* and print to console */
abuf_hexdump(&_hexbuf, "\t", buffer, length);
rfc5444_print_direct(&_hexbuf, buffer, length);
/* DEBUG("%s", abuf_getptr(&_hexbuf)); */
abuf_clear(&_hexbuf);
/* fetch the address the packet is supposed to be sent to (i.e. to a
* specific node or the multicast address) from the writer_target struct
* iface* is stored in. This is a bit hacky, but it does the trick. */
wt = container_of(iface, struct writer_target, interface);
print_json_pkt_sent(wt);
netaddr_to_ipv6_addr_t(&wt->target_addr, &sa_wp.sin6_addr);
/* When originating a RREQ, add it to our RREQ table/update its predecessor */
if (wt->type == RFC5444_MSGTYPE_RREQ
&& netaddr_cmp(&wt->packet_data.origNode.addr, &na_local) == 0) {
AODV_DEBUG("originating RREQ with SeqNum %d towards %s via %s; updating RREQ table...\n",
wt->packet_data.origNode.seqnum,
netaddr_to_string(&nbuf, &wt->packet_data.targNode.addr),
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &sa_wp.sin6_addr));
rreqtable_is_redundant(&wt->packet_data);
}
int bytes_sent = socket_base_sendto(_sock_snd, buffer, length,
0, &sa_wp, sizeof sa_wp);
(void) bytes_sent;
AODV_DEBUG("%d bytes sent.\n", bytes_sent);
}
/* Print the json representation of a sent packet to stdout for debugging */
static void print_json_pkt_sent(struct writer_target *wt)
{
#if TEST_SETUP
// note: what if the content at wt has changed until this is printed? memcpy the entire thing?
int msg_type = wt->type;
if (msg_type == RFC5444_MSGTYPE_RREQ) {
printf("{\"log_type\": \"sent_rreq\", \"log_data\": {"
"\"orig_addr\": \"%s\", \"targ_addr\": \"%s\", \"orig_seqnum\": %d, \"metric\": %d}}\n",
netaddr_to_string(&nbuf_origaddr, &wt->packet_data.origNode.addr),
netaddr_to_string(&nbuf_targaddr, &wt->packet_data.targNode.addr),
wt->packet_data.origNode.seqnum, wt->packet_data.origNode.metric);
}
if (msg_type == RFC5444_MSGTYPE_RREP) {
printf("{\"log_type\": \"sent_rrep\", \"log_data\": {"
"\"next_hop\": \"%s\",\"orig_addr\": \"%s\", \"orig_seqnum\": %d,"
" \"targ_addr\": \"%s\"}}\n",
netaddr_to_string(&nbuf_nexthop, &wt->target_addr),
netaddr_to_string(&nbuf_origaddr, &wt->packet_data.origNode.addr),
wt->packet_data.origNode.seqnum,
netaddr_to_string(&nbuf_targaddr, &wt->packet_data.targNode.addr));
}
if (msg_type == RFC5444_MSGTYPE_RERR) {
/* TODO */
}
#else
(void) wt; /* silence compiler */
#endif
}
/* free the matryoshka doll of cobbled-together structs that the sender_thread receives */
static void _deep_free_msg_container(struct msg_container *mc)
{
int type = mc->type;
if ((type == RFC5444_MSGTYPE_RREQ) || (type == RFC5444_MSGTYPE_RREP)) {
struct rreq_rrep_data *rreq_rrep_data = (struct rreq_rrep_data *) mc->data;
free(rreq_rrep_data->packet_data);
if (netaddr_cmp(rreq_rrep_data->next_hop, &na_mcast) != 0) {
free(rreq_rrep_data->next_hop);
}
}
else if (type == RFC5444_MSGTYPE_RERR) {
struct rerr_data *rerr_data = (struct rerr_data *) mc->data;
if (netaddr_cmp(rerr_data->next_hop, &na_mcast) != 0) {
free(rerr_data->next_hop);
}
}
free(mc->data);
free(mc);
}

View File

@ -1,131 +0,0 @@
/*
* 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
* @brief aodvv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODV_H_
#define AODV_H_
#include <sixlowpan/ip.h>
#include "sixlowpan.h"
#include "kernel.h"
#include "udp.h"
#include "socket_base/socket.h"
#include "net_help.h"
#include "net_if.h"
#include "aodvv2/types.h"
#include "constants.h"
#include "seqnum.h"
#include "routingtable.h"
#include "utils.h"
#include "reader.h"
#include "writer.h"
#include "thread.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief This struct contains data which needs to be put into a RREQ or RREP.
* It is used to transport this data in a message to the sender_thread.
* @note Please note that it is for internal use only. To send a RREQ or RREP,
* please use the aodv_send_rreq() and aodv_send_rrep() functions.
*/
struct rreq_rrep_data
{
struct aodvv2_packet_data *packet_data; /**< Data for the RREQ or RREP */
struct netaddr *next_hop; /**< Next hop to which the RREQ
* or RREP should be sent */
};
/**
* @brief This struct contains data which needs to be put into a RERR.
* It is used to transport this data in a message to the sender_thread.
* @note Please note that it is for internal use only. To send a RERR,
* please use the aodv_send_rerr() function.
*/
struct rerr_data
{
struct unreachable_node *unreachable_nodes; /**< All unreachable nodes. Beware,
* this is the start of an array */
size_t len; /**< Length of the unreachable_nodes array */
int hoplimit; /**< hoplimit for the RERR */
struct netaddr *next_hop; /**< Next hop to which the RERR
* should be sent */
};
/**
* @brief This struct holds the data for a RREQ, RREP or RERR (contained
* in a rreq_rrep_data or rerr_data struct) and the next hop the RREQ, RREP
* or RERR should be sent to. It used for message communication with
* the sender_thread.
* @note Please note that it is for internal use only. To send a RERR,
* please use the aodv_send_rerr() function.
*/
struct msg_container
{
int type; /**< Message type (i.e. one of
* rfc5444_msg_type) */
void *data; /**< Pointer to the message data
* (i.e. rreq_rrep_data or rerr_data) */
};
/**
* @brief When set as ipv6_iface_routing_provider, this function is called by
* ipv6_sendto() to determine the next hop towards dest. This function
* is non-blocking.
*
* @param[in] dest destination of the packet
* @return Address of the next hop towards dest if there is any,
* NULL if there is none (yet)
*/
ipv6_addr_t *aodv_get_next_hop(ipv6_addr_t *dest);
/**
* @brief Dispatch a RREQ
*
* @param[in] packet_data Payload of the RREQ
*/
void aodv_send_rreq(struct aodvv2_packet_data *packet_data);
/**
* @brief Dispatch a RREP
*
* @param[in] packet_data Payload of the RREP
* @param[in] next_hop Address of the next hop the RREP should be sent to
*/
void aodv_send_rrep(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop);
/**
* @brief Dispatch a RERR
*
* @param[in] unreachable_nodes All nodes that are marked as unreachable
* by this RERR
* @param[in] len Number of unreachable nodes
* @param[in] next_hop Address of the next hop the RERR should be sent to
*/
void aodv_send_rerr(struct unreachable_node unreachable_nodes[], size_t len,
struct netaddr *next_hop);
#ifdef __cplusplus
}
#endif
#endif /* AODV_H_ */

View File

@ -1,53 +0,0 @@
/*
* 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 aodvv2
* @{
*
* @brief Debug-header for aodvv2 debug messages
*
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODV_DEBUG_H_
#define AODV_DEBUG_H_
#include <stdio.h>
#include "sched.h"
#ifdef __cplusplus
extern "C" {
#endif
#if ENABLE_DEBUG
#define ENABLE_AODV_DEBUG (1)
#endif
/**
* @brief Print aodvv2 specific debug information to std-out with [aodvv2] prefix
*
*/
#if ENABLE_AODV_DEBUG
#include "tcb.h"
#define AODV_DEBUG(...) \
do { \
printf("[aodvv2] "); \
printf(__VA_ARGS__); \
} while (0)
#else
#define AODV_DEBUG(...)
#endif
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_DEBUG_H_*/
/** @} */

View File

@ -1,64 +0,0 @@
/*
* 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
* @brief constants for the aodvv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_CONSTANTS_H_
#define AODVV2_CONSTANTS_H_
#include "aodvv2/types.h"
#include "common/netaddr.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MANET_PORT 269 /** RFC5498 */
enum aodvv2_constants {
AODVV2_MAX_HOPCOUNT = 250, /**< see AODVv2 draft, section 14.2.*/
AODVV2_MAX_ROUTING_ENTRIES = 255, /**< maximum number of entries
* in the routing table */
AODVV2_ACTIVE_INTERVAL = 5, /**< seconds */
AODVV2_MAX_IDLETIME = 250, /**< seconds */
AODVV2_MAX_SEQNUM_LIFETIME = 300, /**< seconds */
AODVV2_MAX_UNREACHABLE_NODES = 15, /**< TODO: choose value (wisely) */
};
/**
* @brief TLV type array indices
*/
enum tlv_index
{
TLV_ORIGSEQNUM,
TLV_TARGSEQNUM,
TLV_UNREACHABLE_NODE_SEQNUM,
TLV_METRIC,
};
/* my multicast address */
extern struct netaddr na_mcast;
/* the interface this protocol operates on */
extern kernel_pid_t aodvv2_if_id;
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_CONSTANTS_H_ */

View File

@ -1,792 +0,0 @@
/*
* 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
* @brief reading and handling of RFC5444 aodvv2 messages
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifdef RIOT
#include "net_help.h"
#endif
#include "reader.h"
#include "aodv_debug.h"
#include "ng_fib.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if ENABLE_DEBUG
/* For PRIu16 etc. */
#include <inttypes.h>
#endif
static enum rfc5444_result _cb_rreq_blocktlv_addresstlvs_okay(
struct rfc5444_reader_tlvblock_context *cont);
static enum rfc5444_result _cb_rreq_blocktlv_messagetlvs_okay(
struct rfc5444_reader_tlvblock_context *cont);
static enum rfc5444_result _cb_rreq_end_callback(
struct rfc5444_reader_tlvblock_context *cont, bool dropped);
static enum rfc5444_result _cb_rrep_blocktlv_addresstlvs_okay(
struct rfc5444_reader_tlvblock_context *cont);
static enum rfc5444_result _cb_rrep_blocktlv_messagetlvs_okay(
struct rfc5444_reader_tlvblock_context *cont);
static enum rfc5444_result _cb_rrep_end_callback(
struct rfc5444_reader_tlvblock_context *cont, bool dropped);
static enum rfc5444_result _cb_rerr_blocktlv_addresstlvs_okay(
struct rfc5444_reader_tlvblock_context *cont);
static enum rfc5444_result _cb_rerr_blocktlv_messagetlvs_okay(
struct rfc5444_reader_tlvblock_context *cont);
static enum rfc5444_result _cb_rerr_end_callback(
struct rfc5444_reader_tlvblock_context *cont, bool dropped);
/* helper functions */
static void print_json_received_rreq(void);
static void print_json_received_rrep(void);
static uint8_t _get_link_cost(aodvv2_metric_t metricType);
static uint8_t _get_max_metric(aodvv2_metric_t metricType);
static uint8_t _get_route_cost(aodvv2_metric_t metricType, uint8_t metric);
/* This is where we store data gathered from packets */
static struct aodvv2_packet_data packet_data;
static struct unreachable_node unreachable_nodes[AODVV2_MAX_UNREACHABLE_NODES];
static int num_unreachable_nodes;
static int aodvv2_validity_t = (AODVV2_ACTIVE_INTERVAL + AODVV2_MAX_IDLETIME) * 1000; /* milliseconds */
static struct rfc5444_reader reader;
#if AODV_DEBUG
static struct netaddr_str nbuf;
#endif
/*
* Message consumer, will be called once for every message of
* type RFC5444_MSGTYPE_RREQ that contains all the mandatory message TLVs
*/
static struct rfc5444_reader_tlvblock_consumer _rreq_consumer =
{
.msg_id = RFC5444_MSGTYPE_RREQ,
.block_callback = _cb_rreq_blocktlv_messagetlvs_okay,
.end_callback = _cb_rreq_end_callback,
};
/*
* Address consumer. Will be called once for every address in a message of
* type RFC5444_MSGTYPE_RREQ.
*/
static struct rfc5444_reader_tlvblock_consumer _rreq_address_consumer =
{
.msg_id = RFC5444_MSGTYPE_RREQ,
.addrblock_consumer = true,
.block_callback = _cb_rreq_blocktlv_addresstlvs_okay,
};
/*
* Message consumer, will be called once for every message of
* type RFC5444_MSGTYPE_RREP that contains all the mandatory message TLVs
*/
static struct rfc5444_reader_tlvblock_consumer _rrep_consumer =
{
.msg_id = RFC5444_MSGTYPE_RREP,
.block_callback = _cb_rrep_blocktlv_messagetlvs_okay,
.end_callback = _cb_rrep_end_callback,
};
/*
* Address consumer. Will be called once for every address in a message of
* type RFC5444_MSGTYPE_RREP.
*/
static struct rfc5444_reader_tlvblock_consumer _rrep_address_consumer =
{
.msg_id = RFC5444_MSGTYPE_RREP,
.addrblock_consumer = true,
.block_callback = _cb_rrep_blocktlv_addresstlvs_okay,
};
/*
* Message consumer, will be called once for every message of
* type RFC5444_MSGTYPE_RERR that contains all the mandatory message TLVs
*/
static struct rfc5444_reader_tlvblock_consumer _rerr_consumer =
{
.msg_id = RFC5444_MSGTYPE_RERR,
.block_callback = _cb_rerr_blocktlv_messagetlvs_okay,
.end_callback = _cb_rerr_end_callback,
};
/*
* Address consumer. Will be called once for every address in a message of
* type RFC5444_MSGTYPE_RERR.
*/
static struct rfc5444_reader_tlvblock_consumer _rerr_address_consumer =
{
.msg_id = RFC5444_MSGTYPE_RERR,
.addrblock_consumer = true,
.block_callback = _cb_rerr_blocktlv_addresstlvs_okay,
};
/*
* Address consumer entries definition
* TLV types RFC5444_MSGTLV__SEQNUM and RFC5444_MSGTLV_METRIC
*/
static struct rfc5444_reader_tlvblock_consumer_entry _rreq_rrep_address_consumer_entries[] =
{
[RFC5444_MSGTLV_ORIGSEQNUM] = { .type = RFC5444_MSGTLV_ORIGSEQNUM},
[RFC5444_MSGTLV_TARGSEQNUM] = { .type = RFC5444_MSGTLV_TARGSEQNUM},
[RFC5444_MSGTLV_METRIC] = { .type = RFC5444_MSGTLV_METRIC }
};
/*
* Address consumer entries definition
* TLV types RFC5444_MSGTLV__SEQNUM and RFC5444_MSGTLV_METRIC
*/
static struct rfc5444_reader_tlvblock_consumer_entry _rerr_address_consumer_entries[] =
{
[RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM] = {
.type = RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM
},
};
/**
* This block callback is called for every address
*
* @param cont
* @return
*/
static enum rfc5444_result _cb_rreq_blocktlv_messagetlvs_okay(struct rfc5444_reader_tlvblock_context *cont)
{
if (!cont->has_hoplimit) {
AODV_DEBUG("\tERROR: missing hop limit\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit = cont->hoplimit;
if (packet_data.hoplimit == 0) {
AODV_DEBUG("\tERROR: Hoplimit is 0.\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit--;
return RFC5444_OKAY;
}
/**
* This block callback is called for every address of a RREQ Message.
*
* @param cont
* @return
*/
static enum rfc5444_result _cb_rreq_blocktlv_addresstlvs_okay(struct rfc5444_reader_tlvblock_context *cont)
{
#if AODV_DEBUG
struct netaddr_str nbuf;
#endif
struct rfc5444_reader_tlvblock_entry *tlv;
bool is_origNode_addr = false;
bool is_targNode_addr = false;
/* handle OrigNode SeqNum TLV */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_ORIGSEQNUM].tlv;
if (tlv) {
is_origNode_addr = true;
packet_data.origNode.addr = cont->addr;
packet_data.origNode.seqnum = *tlv->single_value;
}
/* handle TargNode SeqNum TLV */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_TARGSEQNUM].tlv;
if (tlv) {
is_targNode_addr = true;
packet_data.targNode.addr = cont->addr;
packet_data.targNode.seqnum = *tlv->single_value;
}
if (!tlv && !is_origNode_addr) {
/* assume that tlv missing => targNode Address */
is_targNode_addr = true;
packet_data.targNode.addr = cont->addr;
}
if (!is_origNode_addr && !is_targNode_addr) {
AODV_DEBUG("\tERROR: mandatory RFC5444_MSGTLV_ORIGSEQNUM TLV missing.\n");
return RFC5444_DROP_PACKET;
}
/* handle Metric TLV */
/* cppcheck: suppress false positive on non-trivially initialized arrays.
* this is a known bug: http://trac.cppcheck.net/ticket/5497 */
/* cppcheck-suppress arrayIndexOutOfBounds */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_METRIC].tlv;
if (!tlv && is_origNode_addr) {
AODV_DEBUG("\tERROR: Missing or unknown metric TLV.\n");
return RFC5444_DROP_PACKET;
}
if (tlv) {
if (!is_origNode_addr) {
AODV_DEBUG("\tERROR: Metric TLV belongs to wrong address.\n");
return RFC5444_DROP_PACKET;
}
packet_data.metricType = tlv->type_ext;
packet_data.origNode.metric = *tlv->single_value;
}
return RFC5444_OKAY;
}
/**
* This callback is called every time the _rreq_consumer finishes reading a
* packet.
* @param cont
* @param dropped indicates whether the packet has been dropped previously by
* another callback
*/
static enum rfc5444_result _cb_rreq_end_callback(
struct rfc5444_reader_tlvblock_context *cont, bool dropped)
{
(void) cont;
struct aodvv2_routing_entry_t *rt_entry;
timex_t now;
/* We've received a valid RREQ, log this. */
print_json_received_rreq();
/* Check if packet contains the required information */
if (dropped) {
AODV_DEBUG("\t Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((packet_data.origNode.addr._type == AF_UNSPEC) || !packet_data.origNode.seqnum) {
AODV_DEBUG("\tERROR: missing OrigNode Address or SeqNum. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if (packet_data.targNode.addr._type == AF_UNSPEC) {
AODV_DEBUG("\tERROR: missing TargNode Address. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if (packet_data.hoplimit == 0) {
AODV_DEBUG("\tERROR: Hoplimit is 0. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((_get_max_metric(packet_data.metricType) - _get_link_cost(packet_data.metricType))
<= packet_data.origNode.metric) {
AODV_DEBUG("\tMetric Limit reached. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
/*
The incoming RREQ MUST be checked against previously received
information from the RREQ Table Section 7.6. If the information
in the incoming RteMsg is redundant, then then no further action
is taken.
*/
if (rreqtable_is_redundant(&packet_data)) {
AODV_DEBUG("\tPacket is redundant. Dropping Packet. %i\n", RFC5444_DROP_PACKET);
return RFC5444_DROP_PACKET;
}
/* Update the cost of the route, since the packet has successfully traversed
* one more hop. */
packet_data.origNode.metric = _get_route_cost(packet_data.metricType,
packet_data.origNode.metric);
vtimer_now(&now);
packet_data.timestamp = now;
/* for every relevant
* address (RteMsg.Addr) in the RteMsg, HandlingRtr searches its route
* table to see if there is a route table entry with the same MetricType
* of the RteMsg, matching RteMsg.Addr.
*/
rt_entry = routingtable_get_entry(&packet_data.origNode.addr, packet_data.metricType);
if (!rt_entry || (rt_entry->metricType != packet_data.metricType)) {
/* CAUTION SUPER HACKY FIX FIXME ASAP
problem: sometimes we get broadcasted RREQs from 2 hop neighbors and then
AODVv2 gets super confused when they're not in the routing table and starts a
Route discovery to find them and all hell breaks loose. let's see if we can fix
this (horribly).
(another fix would be to stop bouncing the RREP back to the sender and asking
the routing table for the next hop (or just send towards TargNode and let the
network stack figure out the rest?))
TODO evaluate that
*/
ipv6_addr_t sender_tmp;
netaddr_to_ipv6_addr_t(&packet_data.sender, &sender_tmp);
ndp_neighbor_cache_t *ndp_nc_entry = ndp_neighbor_cache_search(&sender_tmp);
if (ndp_nc_entry == NULL) {
AODV_DEBUG("No bidirectional link to sender. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
/* HACKY FIX ENDS HERE */
struct aodvv2_routing_entry_t *tmp_rt_entry = (struct aodvv2_routing_entry_t *)
malloc(sizeof(struct aodvv2_routing_entry_t));
memset(tmp_rt_entry, 0, sizeof(*tmp_rt_entry));
routingtable_fill_routing_entry_t_rreq(&packet_data, tmp_rt_entry);
routingtable_add_entry(tmp_rt_entry);
/* add entry to FIB */
fib_add_entry(aodvv2_if_id, tmp_rt_entry->addr._addr, sizeof(ipv6_addr_t), 0,
tmp_rt_entry->nextHopAddr._addr, sizeof(ipv6_addr_t), 0, aodvv2_validity_t);
free(tmp_rt_entry);
}
else {
if (!routingtable_offers_improvement(rt_entry, &packet_data.origNode)) {
AODV_DEBUG("\tPacket offers no improvement over known route. Dropping Packet.\n");
return RFC5444_DROP_PACKET;
}
/* The incoming routing information is better than existing routing
* table information and SHOULD be used to improve the route table. */
AODV_DEBUG("\tUpdating Routing Table entry...\n");
routingtable_fill_routing_entry_t_rreq(&packet_data, rt_entry);
/* update the FIB */
fib_update_entry(rt_entry->addr._addr, sizeof(ipv6_addr_t), rt_entry->nextHopAddr._addr,
sizeof(ipv6_addr_t), 0, aodvv2_validity_t);
}
/*
* If TargNode is a client of the router receiving the RREQ, then the
* router generates a RREP message as specified in Section 7.4, and
* subsequently processing for the RREQ is complete. Otherwise,
* processing continues as follows.
*/
if (clienttable_is_client(&packet_data.targNode.addr)) {
AODV_DEBUG("TargNode is in client list, sending RREP\n");
/* make sure to start with a clean metric value */
packet_data.targNode.metric = 0;
aodv_send_rrep(&packet_data, &packet_data.sender);
}
else {
AODV_DEBUG("I am not TargNode, forwarding RREQ\n");
aodv_send_rreq(&packet_data);
}
return RFC5444_OKAY;
}
/**
* This block callback is called for every address
*
* @param cont
* @return
*/
static enum rfc5444_result _cb_rrep_blocktlv_messagetlvs_okay(struct rfc5444_reader_tlvblock_context *cont)
{
if (!cont->has_hoplimit) {
AODV_DEBUG("\tERROR: missing hop limit\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit = cont->hoplimit;
if (packet_data.hoplimit == 0) {
AODV_DEBUG("\tERROR: Hoplimit is 0.\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit--;
return RFC5444_OKAY;
}
/**
* This block callback is called for every address of a RREP Message.
*
* @param cont
* @return
*/
static enum rfc5444_result _cb_rrep_blocktlv_addresstlvs_okay(struct rfc5444_reader_tlvblock_context *cont)
{
#if AODV_DEBUG
/* cppcheck-suppress unusedVariable as nbuf is needed by AODV_DEBUG. */
struct netaddr_str nbuf;
#endif
struct rfc5444_reader_tlvblock_entry *tlv;
bool is_targNode_addr = false;
/* handle TargNode SeqNum TLV */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_TARGSEQNUM].tlv;
if (tlv) {
is_targNode_addr = true;
packet_data.targNode.addr = cont->addr;
packet_data.targNode.seqnum = *tlv->single_value;
}
/* handle OrigNode SeqNum TLV */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_ORIGSEQNUM].tlv;
if (tlv) {
is_targNode_addr = false;
packet_data.origNode.addr = cont->addr;
packet_data.origNode.seqnum = *tlv->single_value;
}
if (!tlv && !is_targNode_addr) {
AODV_DEBUG("\tERROR: mandatory SeqNum TLV missing.\n");
return RFC5444_DROP_PACKET;
}
/* handle Metric TLV */
/* cppcheck: suppress false positive on non-trivially initialized arrays.
* this is a known bug: http://trac.cppcheck.net/ticket/5497 */
/* cppcheck-suppress arrayIndexOutOfBounds */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_METRIC].tlv;
if (!tlv && is_targNode_addr) {
AODV_DEBUG("\tERROR: Missing or unknown metric TLV.\n");
return RFC5444_DROP_PACKET;
}
if (tlv) {
if (!is_targNode_addr) {
AODV_DEBUG("\tERROR: metric TLV belongs to wrong address.\n");
return RFC5444_DROP_PACKET;
}
packet_data.metricType = tlv->type_ext;
packet_data.targNode.metric = *tlv->single_value;
}
return RFC5444_OKAY;
}
/**
* This callback is called every time the _rreq_consumer finishes reading a
* packet.
* @param cont
* @param dropped indicates wehther the packet has been dropped previously by
* another callback
*/
static enum rfc5444_result _cb_rrep_end_callback(
struct rfc5444_reader_tlvblock_context *cont, bool dropped)
{
(void) cont;
struct aodvv2_routing_entry_t *rt_entry;
#if AODV_DEBUG
struct netaddr_str nbuf;
#endif
timex_t now;
/* We've received a valid RREP, log this. */
print_json_received_rrep();
/* Check if packet contains the required information */
if (dropped) {
AODV_DEBUG("\t Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((packet_data.origNode.addr._type == AF_UNSPEC)
|| !packet_data.origNode.seqnum) {
AODV_DEBUG("\tERROR: missing OrigNode Address or SeqNum. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((packet_data.targNode.addr._type == AF_UNSPEC)
|| !packet_data.targNode.seqnum) {
AODV_DEBUG("\tERROR: missing TargNode Address or SeqNum. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((_get_max_metric(packet_data.metricType) - _get_link_cost(packet_data.metricType))
<= packet_data.targNode.metric) {
AODV_DEBUG("\tMetric Limit reached. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
/* Update the cost of the route, since the packet has successfully traversed
* one more hop. */
packet_data.targNode.metric = _get_route_cost(packet_data.metricType,
packet_data.targNode.metric);
vtimer_now(&now);
packet_data.timestamp = now;
/* for every relevant address (RteMsg.Addr) in the RteMsg, HandlingRtr
searches its route table to see if there is a route table entry with the
same MetricType of the RteMsg, matching RteMsg.Addr. */
rt_entry = routingtable_get_entry(&packet_data.targNode.addr, packet_data.metricType);
if (!rt_entry || (rt_entry->metricType != packet_data.metricType)) {
/* CAUTION SUPER HACKY FIX FIXME ASAP
problem: sometimes we get broadcasted RREQs from 2 hop neighbors and then
AODVv2 gets super confused when they're not in the routing table and starts a
Route discovery to find them and all hell breaks loose. let's see if we can fix
this (horribly).
(another fix would be to stop bouncing the RREP back to the sender and asking
the routing table for the next hop (or just send towards TargNode and let the network stack figure out the rest?))
TODO evaluate that
*/
ipv6_addr_t sender_tmp;
netaddr_to_ipv6_addr_t(&packet_data.sender, &sender_tmp);
ndp_neighbor_cache_t *ndp_nc_entry = ndp_neighbor_cache_search(&sender_tmp);
if (ndp_nc_entry == NULL) {
AODV_DEBUG("No bidirectional link to sender. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
/* HACKY FIX ENDS HERE */
struct aodvv2_routing_entry_t *tmp_rt_entry = (struct aodvv2_routing_entry_t *)
malloc(sizeof(struct aodvv2_routing_entry_t));
memset(tmp_rt_entry, 0, sizeof(*tmp_rt_entry));
routingtable_fill_routing_entry_t_rrep(&packet_data, tmp_rt_entry);
routingtable_add_entry(tmp_rt_entry);
/* add entry to FIB */
fib_add_entry(aodvv2_if_id, tmp_rt_entry->addr._addr, sizeof(ipv6_addr_t), 0,
tmp_rt_entry->nextHopAddr._addr, sizeof(ipv6_addr_t), 0, aodvv2_validity_t);
free(tmp_rt_entry);
}
else {
if (!routingtable_offers_improvement(rt_entry, &packet_data.targNode)) {
AODV_DEBUG("\tPacket offers no improvement over known route. Dropping Packet.\n");
return RFC5444_DROP_PACKET;
}
/* The incoming routing information is better than existing routing
* table information and SHOULD be used to improve the route table. */
AODV_DEBUG("\tUpdating Routing Table entry...\n");
routingtable_fill_routing_entry_t_rrep(&packet_data, rt_entry);
/* update the FIB */
fib_update_entry(rt_entry->addr._addr, sizeof(ipv6_addr_t), rt_entry->nextHopAddr._addr,
sizeof(ipv6_addr_t), 0, aodvv2_validity_t);
}
/* If HandlingRtr is RREQ_Gen then the RREP satisfies RREQ_Gen's
earlier RREQ, and RREP processing is completed. Any packets
buffered for OrigNode should be transmitted. */
if (clienttable_is_client(&packet_data.origNode.addr)) {
AODV_DEBUG("\t%s: This is my RREP. We are done here!\n",
netaddr_to_string(&nbuf, &packet_data.origNode.addr));
}
else {
/* If HandlingRtr is not RREQ_Gen then the outgoing RREP is sent to the
* Route.NextHopAddress for the RREP.AddrBlk[OrigNodeNdx]. */
AODV_DEBUG("Not my RREP, passing it on to the next hop\n");
aodv_send_rrep(&packet_data,
routingtable_get_next_hop(&packet_data.origNode.addr,packet_data.metricType));
}
return RFC5444_OKAY;
}
static enum rfc5444_result _cb_rerr_blocktlv_messagetlvs_okay(struct rfc5444_reader_tlvblock_context *cont)
{
if (!cont->has_hoplimit) {
AODV_DEBUG("\tERROR: missing hop limit\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit = cont->hoplimit;
if (packet_data.hoplimit == 0) {
AODV_DEBUG("\tERROR: Hoplimit is 0.\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit--;
/* prepare buffer for unreachable nodes */
num_unreachable_nodes = 0;
for (unsigned i = 0; i < AODVV2_MAX_UNREACHABLE_NODES; i++) {
memset(&unreachable_nodes[i], 0, sizeof(unreachable_nodes[i]));
}
return RFC5444_OKAY;
}
static enum rfc5444_result _cb_rerr_blocktlv_addresstlvs_okay(struct rfc5444_reader_tlvblock_context *cont)
{
#if AODV_DEBUG
/* cppcheck-suppress unusedVariable as nbuf is needed by AODV_DEBUG. */
struct netaddr_str nbuf;
#endif
struct aodvv2_routing_entry_t *unreachable_entry;
struct rfc5444_reader_tlvblock_entry *tlv;
AODV_DEBUG("%s()\n", __func__);
AODV_DEBUG("\tmessage type: %d\n", cont->type);
AODV_DEBUG("\taddr: %s\n", netaddr_to_string(&nbuf, &cont->addr));
/* Out of buffer size for more unreachable nodes. We're screwed, basically. */
if (num_unreachable_nodes == AODVV2_MAX_UNREACHABLE_NODES) {
return RFC5444_OKAY;
}
/* gather packet data */
packet_data.origNode.addr = cont->addr;
/* handle this unreachable node's SeqNum TLV */
/* cppcheck: suppress false positive on non-trivially initialized arrays.
* this is a known bug: http://trac.cppcheck.net/ticket/5497 */
/* cppcheck-suppress arrayIndexOutOfBounds */
tlv = _rerr_address_consumer_entries[RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM].tlv;
if (tlv) {
AODV_DEBUG("\ttlv RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM: %d\n", *tlv->single_value);
packet_data.origNode.seqnum = *tlv->single_value;
}
/* Check if there is an entry for unreachable node in our routing table */
unreachable_entry = routingtable_get_entry(&packet_data.origNode.addr, packet_data.metricType);
if (unreachable_entry) {
AODV_DEBUG("\t found possibly unreachable entry.\n");
/* check if route to unreachable node has to be marked as broken and RERR has to be forwarded */
if (netaddr_cmp(&unreachable_entry->nextHopAddr, &packet_data.sender) == 0
&& (!tlv || seqnum_cmp(unreachable_entry->seqnum, packet_data.origNode.seqnum) == 0)) {
unreachable_entry->state = ROUTE_STATE_INVALID;
unreachable_nodes[num_unreachable_nodes].addr = packet_data.origNode.addr;
unreachable_nodes[num_unreachable_nodes].seqnum = packet_data.origNode.seqnum;
num_unreachable_nodes++;
}
/* remove entry from FIB */
fib_remove_entry(packet_data.origNode.addr._addr, sizeof(ipv6_addr_t));
}
return RFC5444_OKAY;
}
static enum rfc5444_result _cb_rerr_end_callback(struct rfc5444_reader_tlvblock_context *cont, bool dropped)
{
(void) cont;
if (dropped) {
AODV_DEBUG("\tDropping packet.\n");
return RFC5444_DROP_PACKET;
}
if (num_unreachable_nodes == 0) {
AODV_DEBUG("\tNo unreachable nodes from my routing table. Dropping Packet.\n");
return RFC5444_DROP_PACKET;
}
/* gather all unreachable nodes and put them into a RERR */
aodv_send_rerr(unreachable_nodes, num_unreachable_nodes, &na_mcast);
return RFC5444_OKAY;
}
void aodv_packet_reader_init(void)
{
AODV_DEBUG("%s()\n", __func__);
/* initialize reader */
rfc5444_reader_init(&reader);
/* register message consumers. We have no message TLVs, so we can leave the
* rfc5444_reader_tlvblock_consumer_entry empty */
rfc5444_reader_add_message_consumer(&reader, &_rreq_consumer,
NULL, 0);
rfc5444_reader_add_message_consumer(&reader, &_rrep_consumer,
NULL, 0);
rfc5444_reader_add_message_consumer(&reader, &_rerr_consumer,
NULL, 0);
/* register address consumer */
rfc5444_reader_add_message_consumer(&reader, &_rreq_address_consumer,
_rreq_rrep_address_consumer_entries,
ARRAYSIZE(_rreq_rrep_address_consumer_entries));
rfc5444_reader_add_message_consumer(&reader, &_rrep_address_consumer,
_rreq_rrep_address_consumer_entries,
ARRAYSIZE(_rreq_rrep_address_consumer_entries));
rfc5444_reader_add_message_consumer(&reader, &_rerr_address_consumer,
_rerr_address_consumer_entries,
ARRAYSIZE(_rerr_address_consumer_entries));
}
void aodv_packet_reader_cleanup(void)
{
rfc5444_reader_cleanup(&reader);
}
int aodv_packet_reader_handle_packet(void *buffer, size_t length, struct netaddr *sender)
{
memcpy(&packet_data.sender, sender, sizeof(*sender));
return rfc5444_reader_handle_packet(&reader, buffer, length);
}
/*============= HELPER FUNCTIONS =============================================*/
static void print_json_received_rreq(void)
{
#if TEST_SETUP
static struct netaddr_str nbuf_origaddr, nbuf_targaddr, nbuf_send;
printf("{\"log_type\": \"received_rreq\", "
"\"log_data\":{ \"last_hop\": \"%s\", \"orig_addr\": \"%s\", "
"\"orig_seqnum\": %d, \"targ_addr\": \"%s\", \"metric\": %d}}\n",
netaddr_to_string(&nbuf_send, &packet_data.sender),
netaddr_to_string(&nbuf_origaddr, &packet_data.origNode.addr),
packet_data.origNode.seqnum,
netaddr_to_string(&nbuf_targaddr, &packet_data.targNode.addr),
packet_data.origNode.metric);
#endif
}
static void print_json_received_rrep(void)
{
#if TEST_SETUP
static struct netaddr_str nbuf_origaddr, nbuf_targaddr, nbuf_send;
printf("{\"log_type\": \"received_rrep\", "
"\"log_data\":{ \"last_hop\": \"%s\", \"orig_addr\": \"%s\", "
"\"orig_seqnum\": %d, \"targ_addr\": \"%s\", \"targ_seqnum\":%d}}\n",
netaddr_to_string(&nbuf_send, &packet_data.sender),
netaddr_to_string(&nbuf_origaddr, &packet_data.origNode.addr),
packet_data.origNode.seqnum,
netaddr_to_string(&nbuf_targaddr, &packet_data.targNode.addr),
packet_data.targNode.seqnum);
#endif
}
/*
* Cost(L): Get Cost of a Link regarding the specified metric.
* (currently only AODVV2_DEFAULT_METRIC_TYPE (HopCount) implemented)
* returns cost if metric is known, 0 otherwise
*/
static uint8_t _get_link_cost(aodvv2_metric_t metricType)
{
if (metricType == AODVV2_DEFAULT_METRIC_TYPE) {
return 1;
}
return 0;
}
/*
* MAX_METRIC[MetricType]:
* returns maximum value of the given metric if metric is known, 0 otherwise.
*/
static uint8_t _get_max_metric(aodvv2_metric_t metricType)
{
if (metricType == AODVV2_DEFAULT_METRIC_TYPE) {
return AODVV2_MAX_HOPCOUNT;
}
return 0;
}
/*
* Cost(R): Get Cost of a Route regarding the specified metric, based on the
* earlier metric value of the Route.
* (currently only AODVV2_DEFAULT_METRIC_TYPE (HopCount) implemented)
* returns cost if metric is known, 0 otherwise
*/
static uint8_t _get_route_cost(aodvv2_metric_t metricType, uint8_t metric)
{
if (metricType == AODVV2_DEFAULT_METRIC_TYPE){
return metric + _get_link_cost(AODVV2_DEFAULT_METRIC_TYPE);
}
return 0;
}

View File

@ -1,62 +0,0 @@
/*
* 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
* @brief reading and handling of RFC5444 aodvv2 messages
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_READER_H_
#define AODVV2_READER_H_
#include <string.h>
#include <stdio.h>
#include "common/netaddr.h"
#include "rfc5444/rfc5444_reader.h"
#include "utils.h"
#include "routingtable.h"
#include "constants.h"
#include "seqnum.h"
#include "aodv.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize reader.
*/
void aodv_packet_reader_init(void);
/**
* @brief Clean up after reader. Only needs to be called upon shutdown.
*/
void aodv_packet_reader_cleanup(void);
/**
* @brief Read data buffer as RFC5444 packet and handle the data it contains
*
* @param[in] buffer Data to be read and handled
* @param[in] length Length of data
* @param[in] sender Address of the node from which the packet was received
*/
int aodv_packet_reader_handle_packet(void *buffer, size_t length, struct netaddr *sender);
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_READER_H_ */

View File

@ -1,299 +0,0 @@
/*
* 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
* @brief Cobbled-together routing table.
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#include <stdio.h>
#include <inttypes.h>
#include "routingtable.h"
#include "aodv_debug.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* helper functions */
static void _reset_entry_if_stale(uint8_t i);
static void print_json_added_rt_entry(struct aodvv2_routing_entry_t *entry);
static struct aodvv2_routing_entry_t routing_table[AODVV2_MAX_ROUTING_ENTRIES];
static timex_t null_time, max_seqnum_lifetime, active_interval, max_idletime, validity_t;
timex_t now;
#if ENABLE_DEBUG
static struct netaddr_str nbuf;
#endif
void routingtable_init(void)
{
null_time = timex_set(0, 0);
max_seqnum_lifetime = timex_set(AODVV2_MAX_SEQNUM_LIFETIME, 0);
active_interval = timex_set(AODVV2_ACTIVE_INTERVAL, 0);
max_idletime = timex_set(AODVV2_MAX_IDLETIME, 0);
validity_t = timex_set(AODVV2_ACTIVE_INTERVAL + AODVV2_MAX_IDLETIME, 0);
memset(&routing_table, 0, sizeof(routing_table));
AODV_DEBUG("routing table initialized.\n");
}
struct netaddr *routingtable_get_next_hop(struct netaddr *dest, aodvv2_metric_t metricType)
{
struct aodvv2_routing_entry_t *entry = routingtable_get_entry(dest, metricType);
if (!entry) {
return NULL;
}
return (&entry->nextHopAddr);
}
void routingtable_add_entry(struct aodvv2_routing_entry_t *entry)
{
print_json_added_rt_entry(entry);
/* only add if we don't already know the address */
if (routingtable_get_entry(&(entry->addr), entry->metricType)) {
return;
}
/*find free spot in RT and place rt_entry there */
for (unsigned i = 0; i < AODVV2_MAX_ROUTING_ENTRIES; i++) {
if (routing_table[i].addr._type == AF_UNSPEC) {
memcpy(&routing_table[i], entry, sizeof(struct aodvv2_routing_entry_t));
return;
}
}
}
struct aodvv2_routing_entry_t *routingtable_get_entry(struct netaddr *addr,
aodvv2_metric_t metricType)
{
for (unsigned i = 0; i < AODVV2_MAX_ROUTING_ENTRIES; i++) {
_reset_entry_if_stale(i);
if (!netaddr_cmp(&routing_table[i].addr, addr)
&& routing_table[i].metricType == metricType) {
DEBUG("[routing] found entry for %s :", netaddr_to_string(&nbuf, addr));
#if ENABLE_DEBUG
print_routingtable_entry(&routing_table[i]);
#endif
return &routing_table[i];
}
}
return NULL;
}
void routingtable_delete_entry(struct netaddr *addr, aodvv2_metric_t metricType)
{
for (unsigned i = 0; i < AODVV2_MAX_ROUTING_ENTRIES; i++) {
_reset_entry_if_stale(i);
if (!netaddr_cmp(&routing_table[i].addr, addr)
&& routing_table[i].metricType == metricType) {
memset(&routing_table[i], 0, sizeof(routing_table[i]));
return;
}
}
}
void routingtable_break_and_get_all_hopping_over(struct netaddr *hop,
struct unreachable_node unreachable_nodes[],
size_t *len)
{
*len = 0; /* to be sure */
for (unsigned i = 0; i < AODVV2_MAX_ROUTING_ENTRIES; i++) {
_reset_entry_if_stale(i);
if (netaddr_cmp(&routing_table[i].nextHopAddr, hop) == 0) {
if (routing_table[i].state == ROUTE_STATE_ACTIVE &&
*len < AODVV2_MAX_UNREACHABLE_NODES) {
/* when the max number of unreachable nodes is reached we're screwed.
* the above check is just damage control. */
unreachable_nodes[*len].addr = routing_table[i].addr;
unreachable_nodes[*len].seqnum = routing_table[i].seqnum;
(*len)++;
DEBUG("\t[routing] unreachable node found: %s\n", netaddr_to_string(&nbuf, &routing_table[i].nextHopAddr));
}
routing_table[i].state = ROUTE_STATE_INVALID;
DEBUG("\t[routing] number of unreachable nodes: %i\n", *len);
}
}
}
/*
* Check if entry at index i is stale as described in Section 6.3.
* and clear the struct it fills if it is
*/
static void _reset_entry_if_stale(uint8_t i)
{
vtimer_now(&now);
timex_t lastUsed, expirationTime;
if (timex_cmp(routing_table[i].expirationTime, null_time) == 0) {
return;
}
int state = routing_table[i].state;
lastUsed = routing_table[i].lastUsed;
expirationTime = routing_table[i].expirationTime;
/* an Active route is considered to remain Active as long as it is used at least once
* during every ACTIVE_INTERVAL. When a route is no longer Active, it becomes an Idle route. */
/* if the node is younger than the active interval, don't bother */
if (timex_cmp(now, active_interval) < 0) {
return;
}
if ((state == ROUTE_STATE_ACTIVE) &&
(timex_cmp(timex_sub(now, active_interval), lastUsed) == 1)) {
DEBUG("\t[routing] route towards %s Idle\n",
netaddr_to_string(&nbuf, &routing_table[i].addr));
routing_table[i].state = ROUTE_STATE_IDLE;
routing_table[i].lastUsed = now; /* mark the time entry was set to Idle */
}
/* After an Idle route remains Idle for MAX_IDLETIME, it becomes an Invalid route. */
/* if the node is younger than the expiration time, don't bother */
if (timex_cmp(now, expirationTime) < 0) {
return;
}
/* If Current_Time > Route.ExpirationTime, set Route.State := Invalid. */
if ((state == ROUTE_STATE_IDLE) &&
(timex_cmp(now, expirationTime) > 0)) {
DEBUG("\t[routing] route towards %s became Invalid\n",
netaddr_to_string(&nbuf, &routing_table[i].addr));
routing_table[i].state = ROUTE_STATE_INVALID;
routing_table[i].lastUsed = now; /* mark the time entry was set to Invalid */
}
/* If (Current_Time - Route.LastUsed) > (ACTIVE_INTERVAL + MAX_IDLETIME),
* and if (Route.Timed == FALSE), set Route.State := Invalid. */
if ((timex_cmp(timex_sub(now, lastUsed), timex_add(active_interval, max_idletime)) > 0) &&
(state != ROUTE_STATE_TIMED)) {
routing_table[i].state = ROUTE_STATE_INVALID;
}
/* After that time, old sequence number information is considered no longer
* valid and the Invalid route MUST BE expunged */
if (timex_cmp(timex_sub(now, lastUsed), max_seqnum_lifetime) >= 0) {
DEBUG("\t[routing] Expunged routing table entry for %s at %i\n",
netaddr_to_string(&nbuf, &routing_table[i].addr), i);
memset(&routing_table[i], 0, sizeof(routing_table[i]));
}
}
bool routingtable_offers_improvement(struct aodvv2_routing_entry_t *rt_entry,
struct node_data *node_data)
{
/* (TODO only guaranteed for AODVV2_DEFAULT_METRIC_TYPE!)*/
bool is_loop_free = node_data->metric <= rt_entry->metric;
int stale = seqnum_cmp(node_data->seqnum, rt_entry->seqnum);
if ((stale == 1) /* New info is more recent and MUST be used */
|| ((stale == 0) && (node_data->metric < rt_entry->metric)) /* New info offers a better route and SHOULD be used */
|| ((stale == 0) && (node_data->metric >= rt_entry->metric) /* Route is not an improvement, */
&& (rt_entry->state == ROUTE_STATE_INVALID) /* but repairs an invalid route */
&& is_loop_free) /* and contains no loops */
) {
return true;
}
return false;
}
void routingtable_fill_routing_entry_t_rreq(struct aodvv2_packet_data *packet_data,
struct aodvv2_routing_entry_t *rt_entry)
{
rt_entry->addr = packet_data->origNode.addr;
rt_entry->seqnum = packet_data->origNode.seqnum;
rt_entry->nextHopAddr = packet_data->sender;
rt_entry->lastUsed = packet_data->timestamp;
rt_entry->expirationTime = timex_add(packet_data->timestamp, validity_t);
rt_entry->metricType = packet_data->metricType;
rt_entry->metric = packet_data->origNode.metric;
rt_entry->state = ROUTE_STATE_ACTIVE;
}
void routingtable_fill_routing_entry_t_rrep(struct aodvv2_packet_data *packet_data,
struct aodvv2_routing_entry_t *rt_entry)
{
rt_entry->addr = packet_data->targNode.addr;
rt_entry->seqnum = packet_data->targNode.seqnum;
rt_entry->nextHopAddr = packet_data->sender;
rt_entry->lastUsed = packet_data->timestamp;
rt_entry->expirationTime = timex_add(packet_data->timestamp, validity_t);
rt_entry->metricType = packet_data->metricType;
rt_entry->metric = packet_data->targNode.metric;
rt_entry->state = ROUTE_STATE_ACTIVE;
}
#if TEST_SETUP
/* Write JSON representation of rt_entry to json_str */
static void routingtable_entry_to_json(struct aodvv2_routing_entry_t *rt_entry, char* json_str)
{
struct netaddr_str nbuf_addr, nbuf_nexthop;
sprintf(json_str,"{\"addr\": \"%s\", \"next_hop\": \"%s\", \"seqnum\": %d,"
"\"metric\": %d, \"state\": %d}",
netaddr_to_string(&nbuf_addr, &rt_entry->addr),
netaddr_to_string(&nbuf_nexthop, &rt_entry->nextHopAddr),
rt_entry->seqnum, rt_entry->metric, rt_entry->state);
}
#endif
static void print_json_added_rt_entry(struct aodvv2_routing_entry_t *entry)
{
#if TEST_SETUP
char rt_entry_json [500];
routingtable_entry_to_json(entry, rt_entry_json);
printf("{\"log_type\": \"added_rt_entry\", \"log_data\": %s}\n", rt_entry_json);
#else
(void) entry; /* silence compiler */
#endif
}
void print_routingtable(void)
{
printf("===== BEGIN ROUTING TABLE ===================\n");
for (int i = 0; i < AODVV2_MAX_ROUTING_ENTRIES; i++) {
/* route has been used before => non-empty entry */
if (routing_table[i].lastUsed.seconds
|| routing_table[i].lastUsed.microseconds) {
print_routingtable_entry(&routing_table[i]);
}
}
printf("===== END ROUTING TABLE =====================\n");
}
void print_routingtable_entry(struct aodvv2_routing_entry_t *rt_entry)
{
struct netaddr_str nbuf;
printf(".................................\n");
printf("\t address: %s\n", netaddr_to_string(&nbuf, &(rt_entry->addr)));
printf("\t seqnum: %i\n", rt_entry->seqnum);
printf("\t nextHopAddress: %s\n",
netaddr_to_string(&nbuf, &(rt_entry->nextHopAddr)));
printf("\t lastUsed: %"PRIu32":%"PRIu32"\n",
rt_entry->lastUsed.seconds, rt_entry->lastUsed.microseconds);
printf("\t expirationTime: %"PRIu32":%"PRIu32"\n",
rt_entry->expirationTime.seconds, rt_entry->expirationTime.microseconds);
printf("\t metricType: %i\n", rt_entry->metricType);
printf("\t metric: %d\n", rt_entry->metric);
printf("\t state: %d\n", rt_entry->state);
}

View File

@ -1,160 +0,0 @@
/*
* 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
* @brief Cobbled-together routing table.
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_ROUTINGTABLE_H_
#define AODVV2_ROUTINGTABLE_H_
#include <string.h>
#include "common/netaddr.h"
#include "aodvv2/types.h"
#include "constants.h"
#include "seqnum.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* A route table entry (i.e., a route) may be in one of the following states:
*/
enum aodvv2_routing_states
{
ROUTE_STATE_ACTIVE,
ROUTE_STATE_IDLE,
ROUTE_STATE_INVALID,
ROUTE_STATE_TIMED
};
/**
* all fields of a routing table entry
*/
struct aodvv2_routing_entry_t
{
struct netaddr addr; /**< IP address of this route's destination */
aodvv2_seqnum_t seqnum; /**< The Sequence Number obtained from the
* last packet that updated the entry */
struct netaddr nextHopAddr; /**< IP address of the the next hop towards
* the destination */
timex_t lastUsed; /**< IP address of this route's destination */
timex_t expirationTime; /**< Time at which this route expires */
aodvv2_metric_t metricType; /**< Metric type of this route */
uint8_t metric; /**< Metric value of this route*/
uint8_t state; /**< State of this route
* (i.e. one of aodvv2_routing_states) */
};
/**
* @brief Initialize routing table.
*/
void routingtable_init(void);
/**
* @brief Get next hop towards dest.
* Returns NULL if dest is not in routing table.
*
* @param[in] dest Destination of the packet
* @param[in] metricType Metric Type of the desired route
* @return next hop towards dest if it exists, NULL otherwise
*/
struct netaddr *routingtable_get_next_hop(struct netaddr *dest, aodvv2_metric_t metricType);
/**
* @brief Add new entry to routing table, if there is no other entry
* to the same destination.
*
* @param[in] entry The routing table entry to add
*/
void routingtable_add_entry(struct aodvv2_routing_entry_t *entry);
/**
* @brief Retrieve pointer to a routing table entry.
* To edit, simply follow the pointer.
* Returns NULL if addr is not in routing table.
*
* @param[in] addr The address towards which the route should point
* @param[in] metricType Metric Type of the desired route
* @return Routing table entry if it exists, NULL otherwise
*/
struct aodvv2_routing_entry_t *routingtable_get_entry(struct netaddr *addr, aodvv2_metric_t metricType);
/**
* @brief Delete routing table entry towards addr with metric type MetricType,
* if it exists.
*
* @param[in] addr The address towards which the route should point
* @param[in] metricType Metric Type of the desired route
*/
void routingtable_delete_entry(struct netaddr *addr, aodvv2_metric_t metricType);
/**
* Find all routing table entries that use hop as their nextHopAddress, mark them
* as broken, write the active one into unreachable_nodes[] and increment len
* accordingly. (Sorry about the Name.)
*
* @param hop Address of the newly unreachable next hop
* @param unreachable_nodes[] array of newlu unreachable nodes to be filled.
* should be empty.
* @param len size_t* which will contain the length of
* unreachable_nodes[] after execution
*/
void routingtable_break_and_get_all_hopping_over(struct netaddr *hop,
struct unreachable_node unreachable_nodes[],
size_t *len);
/**
* Check if the data of a RREQ or RREP offers improvement for an existing routing
* table entry.
* @param rt_entry the routing table entry to check
* @param node_data The data to check against. When handling a RREQ,
* the OrigNode's information (i.e. packet_data.origNode)
* must be passed. When handling a RREP, the
* TargNode's data (i.e. packet_data.targNode) must
* be passed.
*/
bool routingtable_offers_improvement(struct aodvv2_routing_entry_t *rt_entry,
struct node_data *node_data);
/**
* Fills a routing table entry with the data of a RREQ.
* @param packet_data the RREQ's data
* @param rt_entry the routing table entry to fill
* @param link_cost the link cost for this RREQ
*/
void routingtable_fill_routing_entry_t_rreq(struct aodvv2_packet_data *packet_data,
struct aodvv2_routing_entry_t *rt_entry);
/**
* Fills a routing table entry with the data of a RREP.
* @param packet_data the RREP's data
* @param rt_entry the routing table entry to fill
* @param link_cost the link cost for this RREP
*/
void routingtable_fill_routing_entry_t_rrep(struct aodvv2_packet_data *packet_data,
struct aodvv2_routing_entry_t *rt_entry);
void print_routingtable(void);
void print_routingtable_entry(struct aodvv2_routing_entry_t *rt_entry);
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_ROUTINGTABLE_H_*/

View File

@ -1,49 +0,0 @@
/*
* 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
* @brief aodvv2 sequence number
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#include "seqnum.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static aodvv2_seqnum_t seqnum;
void seqnum_init(void)
{
seqnum = 1;
}
void seqnum_inc(void)
{
if (seqnum == 65535) {
seqnum = 1;
}
else if (seqnum == 0) {
DEBUG("ERROR: SeqNum shouldn't be 0! \n"); /* TODO handle properly */
}
else {
seqnum++;
}
}
aodvv2_seqnum_t seqnum_get(void)
{
return seqnum;
}

View File

@ -1,63 +0,0 @@
/*
* 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
* @brief aodvv2 sequence number
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_SEQNUM_H_
#define AODVV2_SEQNUM_H_
#include <stdint.h>
#include "aodvv2/types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize sequence number.
*/
void seqnum_init(void);
/**
* @brief Get sequence number.
*
* @return sequence number
*/
aodvv2_seqnum_t seqnum_get(void);
/**
* @brief Increment the sequence number by 1.
*/
void seqnum_inc(void);
/**
* @brief Compare 2 sequence numbers.
* @param[in] s1 first sequence number
* @param[in] s2 second sequence number
* @return -1 when s1 is smaller, 0 if equal, 1 if s1 is bigger.
*/
static inline int seqnum_cmp(aodvv2_seqnum_t s1, aodvv2_seqnum_t s2)
{
return s1 == s2 ? 0 : (s1 > s2 ? +1 : -1);
}
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_SEQNUM_H_ */

View File

@ -1,241 +0,0 @@
/*
* 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
* @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);
}

View File

@ -1,116 +0,0 @@
/*
* 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
* @brief client- and RREQ-table, ipv6 address representation converters
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_UTILS_H_
#define AODVV2_UTILS_H_
#include <stdio.h>
#include "ipv6.h"
#include "common/netaddr.h"
#include "aodvv2/types.h"
#include "constants.h"
#include "seqnum.h"
#ifdef __cplusplus
extern "C" {
#endif
#define AODVV2_MAX_CLIENTS 1 /** multiple clients are currently not supported. */
#define AODVV2_RREQ_BUF 128 /** should be enough for now... */
#define AODVV2_RREQ_WAIT_TIME 2 /** seconds */
#define AODVV2_RIOT_PREFIXLEN 128 /** Prefix length of the IPv6 addresses
* used in the network served by AODVv2 () */
/**
* @brief RREQ Table entry which stores all information about a RREQ that was received
* in order to avoid duplicates.
*/
struct aodvv2_rreq_entry
{
struct netaddr origNode; /**< Node which originated the RREQ*/
struct netaddr targNode; /**< Target (destination) of the RREQ */
aodvv2_metric_t metricType; /**< Metric type of the RREQ */
uint8_t metric; /**< Metric of the RREQ */
aodvv2_seqnum_t seqnum; /**< Sequence number of the RREQ */
timex_t timestamp; /**< Last time this entry was updated */
};
/**
* Initialize table of clients that the router currently serves.
*/
void clienttable_init(void);
/**
* Add client to the list of clients that the router currently serves.
* @param addr address of the client
* (Since the current version doesn't offer support for
* Client Networks, the prefixlen is currently ignored.)
*/
void clienttable_add_client(struct netaddr *addr);
/**
* Find out if a client is in the list of clients that the router currently serves.
* @param addr address of the client in question
* (Since the current version doesn't offer support for
* Client Networks, the prefixlen is currently ignored.)
*/
bool clienttable_is_client(struct netaddr *addr);
/**
* Delete a client from the list of clients that the router currently serves.
* @param addr address of the client to delete
* (Since the current version doesn't offer support for
* Client Networks, the prefixlen is currently ignored.)
*/
void clienttable_delete_client(struct netaddr *addr);
/**
* Initialize RREQ table.
*/
void rreqtable_init(void);
/**
* Check if a RREQ is redundant, i.e. was received from another node already.
* Behaves as described in Sections 5.7. and 7.6.
* @param packet_data data of the RREQ in question
* @return true if packet_data is redundant, false otherwise.
*/
bool rreqtable_is_redundant(struct aodvv2_packet_data *packet_data);
/**
* Convert an IP stored as an ipv6_addr_t to a netaddr
* @param src ipv6_addr_t to convert
* @param dst (empty) netaddr to convert into
*/
void ipv6_addr_t_to_netaddr(ipv6_addr_t *src, struct netaddr *dst);
/**
* Convert an IP stored as a netaddr to an ipv6_addr_t
* @param src (empty) netaddr to convert into
* @param dst ipv6_addr_t to convert
*/
void netaddr_to_ipv6_addr_t(struct netaddr *src, ipv6_addr_t *dst);
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_UTILS_H_ */

View File

@ -1,348 +0,0 @@
/*
* 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
* @brief writer to create RFC5444 aodvv2 messages
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifdef RIOT
#include "net_help.h"
#endif
#include "writer.h"
#include "aodv_debug.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static void _cb_addMessageHeader(struct rfc5444_writer *wr,
struct rfc5444_writer_message *message);
static void _cb_rreq_addAddresses(struct rfc5444_writer *wr);
static void _cb_rrep_addAddresses(struct rfc5444_writer *wr);
static void _cb_rerr_addAddresses(struct rfc5444_writer *wr);
struct rfc5444_writer writer;
static struct writer_target _target;
static struct unreachable_node *_unreachable_nodes;
static size_t _num_unreachable_nodes;
static uint8_t _msg_buffer[128];
static uint8_t _msg_addrtlvs[1000];
static uint8_t _packet_buffer[128];
static struct rfc5444_writer_message *_rreq_msg;
static struct rfc5444_writer_message *_rrep_msg;
static struct rfc5444_writer_message *_rerr_msg;
/*
* message content provider that will add message TLVs,
* addresses and address block TLVs to all messages of type RREQ.
*/
static struct rfc5444_writer_content_provider _rreq_message_content_provider =
{
.msg_type = RFC5444_MSGTYPE_RREQ,
.addAddresses = _cb_rreq_addAddresses,
};
/* declaration of all address TLVs added to the RREQ message */
static struct rfc5444_writer_tlvtype _rreq_addrtlvs[] =
{
[RFC5444_MSGTLV_ORIGSEQNUM] = { .type = RFC5444_MSGTLV_ORIGSEQNUM },
[RFC5444_MSGTLV_METRIC] = {
.type = RFC5444_MSGTLV_METRIC,
.exttype = AODVV2_DEFAULT_METRIC_TYPE
},
};
/*
* message content provider that will add message TLVs,
* addresses and address block TLVs to all messages of type RREQ.
*/
static struct rfc5444_writer_content_provider _rrep_message_content_provider =
{
.msg_type = RFC5444_MSGTYPE_RREP,
.addAddresses = _cb_rrep_addAddresses,
};
/* declaration of all address TLVs added to the RREP message */
static struct rfc5444_writer_tlvtype _rrep_addrtlvs[] =
{
[RFC5444_MSGTLV_ORIGSEQNUM] = { .type = RFC5444_MSGTLV_ORIGSEQNUM},
[RFC5444_MSGTLV_TARGSEQNUM] = { .type = RFC5444_MSGTLV_TARGSEQNUM},
[RFC5444_MSGTLV_METRIC] = {
.type = RFC5444_MSGTLV_METRIC,
.exttype = AODVV2_DEFAULT_METRIC_TYPE
},
};
/*
* message content provider that will add message TLVs,
* addresses and address block TLVs to all messages of type RREQ.
*/
static struct rfc5444_writer_content_provider _rerr_message_content_provider =
{
.msg_type = RFC5444_MSGTYPE_RERR,
.addAddresses = _cb_rerr_addAddresses,
};
/* declaration of all address TLVs added to the RREP message */
static struct rfc5444_writer_tlvtype _rerr_addrtlvs[] =
{
[RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM] = { .type = RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM},
};
/**
* Callback to define the message header for a RFC5444 RREQ message
* @param message
*/
static void
_cb_addMessageHeader(struct rfc5444_writer *wr, struct rfc5444_writer_message *message)
{
AODV_DEBUG("%s()\n", __func__);
/* no originator, no hopcount, has hoplimit, no seqno */
rfc5444_writer_set_msg_header(wr, message, false, false, true, false);
rfc5444_writer_set_msg_hoplimit(wr, message, _target.packet_data.hoplimit);
}
/**
* Callback to add addresses and address TLVs to a RFC5444 RREQ message
*/
static void
_cb_rreq_addAddresses(struct rfc5444_writer *wr)
{
AODV_DEBUG("%s()\n", __func__);
struct rfc5444_writer_address *origNode_addr;
/* add origNode address (has no address tlv); is mandatory address */
origNode_addr = rfc5444_writer_add_address(wr, _rreq_message_content_provider.creator,
&_target.packet_data.origNode.addr, true);
/* add targNode address (has no address tlv); is mandatory address */
rfc5444_writer_add_address(wr, _rreq_message_content_provider.creator,
&_target.packet_data.targNode.addr, true);
/* add SeqNum TLV and metric TLV to origNode */
/* TODO: allow_dup true or false? */
rfc5444_writer_add_addrtlv(wr, origNode_addr, &_rreq_addrtlvs[RFC5444_MSGTLV_ORIGSEQNUM],
&_target.packet_data.origNode.seqnum,
sizeof(_target.packet_data.origNode.seqnum), false);
/* cppcheck: suppress false positive on non-trivially initialized arrays.
* this is a known bug: http://trac.cppcheck.net/ticket/5497 */
/* cppcheck-suppress arrayIndexOutOfBounds */
rfc5444_writer_add_addrtlv(wr, origNode_addr, &_rreq_addrtlvs[RFC5444_MSGTLV_METRIC],
&_target.packet_data.origNode.metric,
sizeof(_target.packet_data.origNode.metric), false);
}
/**
* Callback to add addresses and address TLVs to a RFC5444 RREQ message
*/
static void
_cb_rrep_addAddresses(struct rfc5444_writer *wr)
{
AODV_DEBUG("%s()\n", __func__);
struct rfc5444_writer_address *origNode_addr, *targNode_addr;
uint16_t origNode_seqnum = _target.packet_data.origNode.seqnum;
uint16_t targNode_seqnum = seqnum_get();
seqnum_inc();
uint8_t targNode_hopCt = _target.packet_data.targNode.metric;
/* add origNode address (has no address tlv); is mandatory address */
origNode_addr = rfc5444_writer_add_address(wr, _rrep_message_content_provider.creator,
&_target.packet_data.origNode.addr, true);
/* add targNode address (has no address tlv); is mandatory address */
targNode_addr = rfc5444_writer_add_address(wr, _rrep_message_content_provider.creator,
&_target.packet_data.targNode.addr, true);
/* add OrigNode and TargNode SeqNum TLVs */
/* TODO: allow_dup true or false? */
rfc5444_writer_add_addrtlv(wr, origNode_addr, &_rrep_addrtlvs[RFC5444_MSGTLV_ORIGSEQNUM],
&origNode_seqnum, sizeof(origNode_seqnum), false);
rfc5444_writer_add_addrtlv(wr, targNode_addr, &_rrep_addrtlvs[RFC5444_MSGTLV_TARGSEQNUM],
&targNode_seqnum, sizeof(targNode_seqnum), false);
/* Add Metric TLV to targNode Address */
rfc5444_writer_add_addrtlv(wr, targNode_addr, &_rrep_addrtlvs[RFC5444_MSGTLV_METRIC],
&targNode_hopCt, sizeof(targNode_hopCt), false);
}
/**
* Callback to add addresses and address TLVs to a RFC5444 RERR message
*/
static void
_cb_rerr_addAddresses(struct rfc5444_writer *wr)
{
AODV_DEBUG("%s()\n", __func__);
for (unsigned i = 0; i < _num_unreachable_nodes; i++) {
/* add unreachableNode addresses (has no address tlv); is mandatory address */
struct rfc5444_writer_address *unreachableNode_addr = rfc5444_writer_add_address(
wr, _rerr_message_content_provider.creator,
&_unreachable_nodes[i].addr, true);
/* add SeqNum TLV to unreachableNode */
/* TODO: allow_dup true or false? */
/* cppcheck: suppress false positive on non-trivially initialized arrays.
* this is a known bug: http://trac.cppcheck.net/ticket/5497 */
/* cppcheck-suppress arrayIndexOutOfBounds */
rfc5444_writer_add_addrtlv(wr, unreachableNode_addr,
&_rerr_addrtlvs[RFC5444_MSGTLV_UNREACHABLE_NODE_SEQNUM],
&_unreachable_nodes[i].seqnum,
sizeof(_unreachable_nodes[i].seqnum), false);
}
}
void aodv_packet_writer_init(write_packet_func_ptr ptr)
{
AODV_DEBUG("%s()\n", __func__);
/* define interface for generating rfc5444 packets */
_target.interface.packet_buffer = _packet_buffer;
_target.interface.packet_size = sizeof(_packet_buffer);
/* set function to send binary packet content */
_target.interface.sendPacket = ptr;
/* define the rfc5444 writer */
writer.msg_buffer = _msg_buffer;
writer.msg_size = sizeof(_msg_buffer);
writer.addrtlv_buffer = _msg_addrtlvs;
writer.addrtlv_size = sizeof(_msg_addrtlvs);
/* initialize writer */
rfc5444_writer_init(&writer);
/* register a target (for sending messages to) in writer */
rfc5444_writer_register_target(&writer, &_target.interface);
/* register a message content providers for RREQ and RREP */
rfc5444_writer_register_msgcontentprovider(&writer, &_rreq_message_content_provider,
_rreq_addrtlvs, ARRAYSIZE(_rreq_addrtlvs));
rfc5444_writer_register_msgcontentprovider(&writer, &_rrep_message_content_provider,
_rrep_addrtlvs, ARRAYSIZE(_rrep_addrtlvs));
rfc5444_writer_register_msgcontentprovider(&writer, &_rerr_message_content_provider,
_rerr_addrtlvs, ARRAYSIZE(_rerr_addrtlvs));
/* register rreq and rrep messages with 16 byte (ipv6) addresses.
* AddPacketHeader & addMessageHeader callbacks are triggered here. */
_rreq_msg = rfc5444_writer_register_message(&writer, RFC5444_MSGTYPE_RREQ,
false, RFC5444_MAX_ADDRLEN);
_rrep_msg = rfc5444_writer_register_message(&writer, RFC5444_MSGTYPE_RREP,
false, RFC5444_MAX_ADDRLEN);
_rerr_msg = rfc5444_writer_register_message(&writer, RFC5444_MSGTYPE_RERR,
false, RFC5444_MAX_ADDRLEN);
_rreq_msg->addMessageHeader = _cb_addMessageHeader;
_rrep_msg->addMessageHeader = _cb_addMessageHeader;
_rerr_msg->addMessageHeader = _cb_addMessageHeader;
}
/**
* Send a RREQ. DO NOT use this function to dispatch packets from anything else
* than the sender_thread. To send RREQs, use aodv_send_rreq().
* @param packet_data parameters of the RREQ
* @param next_hop Address the RREP is sent to
*/
void aodv_packet_writer_send_rreq(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop)
{
AODV_DEBUG("%s()\n", __func__);
if ((packet_data == NULL) || (next_hop == NULL)) {
return;
}
/* Make sure no other thread is using the writer right now */
memcpy(&_target.packet_data, packet_data, sizeof(struct aodvv2_packet_data));
_target.type = RFC5444_MSGTYPE_RREQ;
_target.packet_data.hoplimit = packet_data->hoplimit;
/* set address to which the write_packet callback should send our RREQ */
memcpy(&_target.target_addr, next_hop, sizeof (struct netaddr));
rfc5444_writer_create_message_alltarget(&writer, RFC5444_MSGTYPE_RREQ);
rfc5444_writer_flush(&writer, &_target.interface, false);
}
/**
* Send a RREP. DO NOT use this function to dispatch packets from anything else
* than the sender_thread. To send RREPs, use aodv_send_rrep().
* @param packet_data parameters of the RREP
* @param next_hop Address the RREP is sent to
*/
void aodv_packet_writer_send_rrep(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop)
{
AODV_DEBUG("%s()\n", __func__);
if ((packet_data == NULL) || (next_hop == NULL)) {
return;
}
memcpy(&_target.packet_data, packet_data, sizeof(struct aodvv2_packet_data));
_target.type = RFC5444_MSGTYPE_RREP;
_target.packet_data.hoplimit = AODVV2_MAX_HOPCOUNT;
/* set address to which the write_packet callback should send our RREQ */
memcpy(&_target.target_addr, next_hop, sizeof (struct netaddr));
rfc5444_writer_create_message_alltarget(&writer, RFC5444_MSGTYPE_RREP);
rfc5444_writer_flush(&writer, &_target.interface, false);
}
/**
* Send a RERR. DO NOT use this function to dispatch packets from anything else
* than the sender_thread. To send RERRs, use aodv_send_rerr().
* @param unreachable_nodes[] array containing all newly unreachable nodes. each
* in a struct unreachable_node
* @param len length of unreachable_nodes[]
* @param hoplimit the message's hop limit
* @param next_hop Address the RREP is sent to
*/
void aodv_packet_writer_send_rerr(struct unreachable_node unreachable_nodes[], size_t len,
int hoplimit, struct netaddr *next_hop)
{
AODV_DEBUG("%s()\n", __func__);
if ((unreachable_nodes == NULL) || (next_hop == NULL)) {
return;
}
_target.packet_data.hoplimit = hoplimit;
_target.type = RFC5444_MSGTYPE_RERR;
_unreachable_nodes = unreachable_nodes;
_num_unreachable_nodes = len;
/* set address to which the write_packet callback should send our RREQ */
memcpy(&_target.target_addr, next_hop, sizeof (struct netaddr));
rfc5444_writer_create_message_alltarget(&writer, RFC5444_MSGTYPE_RERR);
rfc5444_writer_flush(&writer, &_target.interface, false);
}
void aodv_packet_writer_cleanup(void)
{
AODV_DEBUG("%s()\n", __func__);
rfc5444_writer_cleanup(&writer);
}

View File

@ -1,101 +0,0 @@
/*
* 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
* @brief writer to create RFC5444 aodvv2 messages
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifndef AODVV2_WRITER_H_
#define AODVV2_WRITER_H_
#include "common/netaddr.h"
#include "rfc5444/rfc5444_writer.h"
#include "mutex.h"
#include "constants.h"
#include "seqnum.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Wrapper for the rfc5444_writer_target that the _write_packet() callback receives.
* _write_packet() needs to know the type, payload and target address
* of the RFC5444 message to be sent as well, but the oonf api does not
* offer this feature. Having this wrapper enables the use of the
* container_of macro to fetch this information.
* It is hacky, but it does the trick.
*/
struct writer_target
{
struct rfc5444_writer_target interface; /**< Interface for generating rfc5444 packets */
struct netaddr target_addr; /**< Address to which the packet should be sent */
struct aodvv2_packet_data packet_data; /**< Payload of the AODVv2 Message */
int type; /**< Type of the AODVv2 Message (i.e. rfc5444_msg_type) */
};
/**
* @brief oonf api voodo. Pointer to a callback function which is passed to
* writer_init() and called when the packet is ready to send.
*/
typedef void (*write_packet_func_ptr)(
struct rfc5444_writer *wr, struct rfc5444_writer_target *iface,
void *buffer, size_t length);
/**
* @brief Initialize RFC5444 writer
* @param ptr pointer to "send_packet" callback
*/
void aodv_packet_writer_init(write_packet_func_ptr ptr);
/**
* @brief Clean up after the RFC5444 writer
*/
void aodv_packet_writer_cleanup(void);
/**
* @brief Send a RREQ. DO NOT use this function to dispatch packets from anything else
* than the sender_thread. To send RREQs, use aodv_send_rreq().
* @param packet_data parameters of the RREQ
* @param next_hop Address the RREP is sent to
*/
void aodv_packet_writer_send_rreq(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop);
/**
* @brief Send a RREP. DO NOT use this function to dispatch packets from anything else
* than the sender_thread. To send RREPs, use aodv_send_rrep().
* @param packet_data parameters of the RREP
* @param next_hop Address the RREP is sent to
*/
void aodv_packet_writer_send_rrep(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop);
/**
* @brief Send a RERR. DO NOT use this function to dispatch packets from anything else
* than the sender_thread. To send RERRs, use aodv_send_rerr().
* @param unreachable_nodes[] array containing all newly unreachable nodes. each
* in a struct unreachable_node
* @param len length of unreachable_nodes[]
* @param hoplimit the message's hop limit
* @param next_hop Address the RREP is sent to
*/
void aodv_packet_writer_send_rerr(struct unreachable_node unreachable_nodes[], size_t len,
int hoplimit, struct netaddr *next_hop);
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_WRITER_H_ */

View File

@ -1,31 +0,0 @@
# name of your application
APPLICATION = aodvv2_tests
include ../Makefile.tests_common
# If no BOARD is found in the environment, use this default:
BOARD ?= native
# This test has not been verified to work on any other boards-- proceed with caution.
BOARD_WHITELIST := native
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
CFLAGS += -DDEVELHELP
CFLAGS += -DRIOT
CFLAGS += -DFIB_DEVEL_HELPER
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
# Modules to include
USEMODULE += defaulttransceiver
USEMODULE += aodvv2
USEMODULE += udp
export INCLUDES += -I$(RIOTBASE)/sys/net/routing/aodvv2/
include $(RIOTBASE)/Makefile.include

View File

@ -1,190 +0,0 @@
/*
* Copyright (C) 2014 Hochschule für Angewandte Wissenschaften Hamburg (HAW)
* Copyright (C) 2015 Lotte Steenbrink <lotte.steenbrink@haw-hamburg.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 tests
* @{
*
* @file
* @brief tests for the interaction between AODVv2 and the FIB
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <unistd.h>
#include "aodv_fib_tests.h"
#include "aodv_tests.h"
#include "common/autobuf.h"
#include "rfc5444/rfc5444_writer.h"
#include "rfc5444/rfc5444_print.h"
#include "ng_fib.h"
#include "reader.h"
#include "utils.h"
/* make sure packet is not rejected because "sender" is not in the neighbor cache */
static void _aodv_test_add_to_nc(struct netaddr *sender_na){
ipv6_addr_t sender;
netaddr_to_ipv6_addr_t(sender_na, &sender);
/* TODO: isrouter = 1 correct? */
ndp_neighbor_cache_add(aodvv2_iface_id, &sender, &sender.uint16[7], 2, 1,
NDP_NCE_STATUS_REACHABLE, NDP_NCE_TYPE_TENTATIVE, 0xffff);
}
/* Handle RREQ with no anomalies */
static void aodv_test_add_to_fib_regular_rreq(void)
{
printf("\n============= Handling regular RREQ ================================\n");
ipv6_addr_t next_hop;
kernel_pid_t iface_id;
size_t next_hop_size = sizeof(ipv6_addr_t);
uint32_t next_hop_flags = 0;
_aodv_test_add_to_nc(aodv_test_plain_rreq.sender);
aodv_packet_reader_handle_packet((void *) aodv_test_plain_rreq.buffer,
aodv_test_plain_rreq.length,
aodv_test_plain_rreq.sender);
printf("Checking FIB ...\n");
/* Check if route back to origaddr was created */
int fib_success = fib_get_next_hop(&iface_id, &next_hop.uint8[0], &next_hop_size,
&next_hop_flags, aodvv2_test_origaddr._addr,
sizeof(ipv6_addr_t), 0);
assert(0 == fib_success);
printf("Done.\n");
}
/* Handle RREQ with no anomalies */
static void aodv_test_add_to_fib_regular_rrep(void)
{
printf("\n============= Handling regular RREP ================================\n");
ipv6_addr_t next_hop;
kernel_pid_t iface_id;
size_t next_hop_size = sizeof(ipv6_addr_t);
uint32_t next_hop_flags = 0;
timex_t now;
_aodv_test_add_to_nc(aodv_test_plain_rrep.sender);
/* Make sure route back is known TODO make this global too?!*/
vtimer_now(&now);
struct aodvv2_routing_entry_t tmp_rt_entry = {
.addr = aodvv2_test_origaddr,
.seqnum = 1,
.nextHopAddr = aodvv2_test_sender_oa,
.lastUsed = now,
.expirationTime = timex_add(now,
timex_set(AODVV2_ACTIVE_INTERVAL + AODVV2_MAX_IDLETIME, 0)),
.metricType = AODVV2_DEFAULT_METRIC_TYPE,
.metric = 2,
.state = ROUTE_STATE_ACTIVE,
};
routingtable_add_entry(&tmp_rt_entry);
aodv_packet_reader_handle_packet((void *) aodv_test_plain_rrep.buffer,
aodv_test_plain_rrep.length,
aodv_test_plain_rrep.sender);
printf("Checking FIB ...\n");
/* Check if route back to origaddr was created */
int fib_success = fib_get_next_hop(&iface_id, &next_hop.uint8[0], &next_hop_size,
&next_hop_flags, aodvv2_test_targaddr._addr,
sizeof(ipv6_addr_t), 0);
assert(0 == fib_success);
printf("Done.\n");
}
static void aodv_test_update_fib_regular_rreq(void)
{
printf("\n============= Handling more recent RREQ ============================\n");
timex_t lifetime, now;
printf("Checking FIB ...\n");
aodv_packet_reader_handle_packet((void *) aodv_test_more_recent_rreq.buffer,
aodv_test_more_recent_rreq.length,
aodv_test_more_recent_rreq.sender);
assert(0 == fib_devel_get_lifetime(&lifetime, aodvv2_test_origaddr._addr, sizeof(ipv6_addr_t)));
/* assuming some ms passed during these operations... */
vtimer_now(&now);
timex_t cmp_lifetime = timex_add(now, timex_set(0, 900000));
assert(1 == timex_cmp(lifetime, cmp_lifetime));
printf("Done. \n");
}
static void aodv_test_update_fib_regular_rrep(void)
{
printf("\n============= Handling more recent RREP ============================\n");
timex_t lifetime, now;
printf("Checking FIB ...\n");
aodv_packet_reader_handle_packet((void *) aodv_test_more_recent_rrep.buffer,
aodv_test_more_recent_rrep.length,
aodv_test_more_recent_rrep.sender);
assert(0 == fib_devel_get_lifetime(&lifetime, aodvv2_test_targaddr._addr, sizeof(ipv6_addr_t)));
/* assuming some ms passed during these operations... */
vtimer_now(&now);
timex_t cmp_lifetime = timex_add(now, timex_set(0, 900000));
assert(1 == timex_cmp(lifetime, cmp_lifetime));
printf("Done.\n");
}
static void aodv_test_route_expired(void)
{
printf("\n============= testing if route vanishes after expiring ===========\n");
kernel_pid_t iface_id;
uint32_t next_hop_flags = 0;
size_t next_hop_size = sizeof(ipv6_addr_t);
ipv6_addr_t next_hop;
printf("waiting until route expires... (about 4.5 minutes)\n");
/* TODO: use MAXTIME */
sleep(AODVV2_ACTIVE_INTERVAL + AODVV2_MAX_IDLETIME);
printf("Checking FIB ...\n");
/* Check if route back to origaddr was created */
int fib_success = fib_get_next_hop(&iface_id, &next_hop.uint8[0], &next_hop_size,
&next_hop_flags, aodvv2_test_origaddr._addr,
sizeof(ipv6_addr_t), 0);
assert( 0 != fib_success);
printf("Done.\n");
}
void aodv_test_add_to_fib(void)
{
/* overwrite the aodvv2 packet writer so that messages aren't actually swnt */
aodv_packet_writer_init(aodv_test_drop_packet);
printf("Starting tests...\n");
aodv_test_add_to_fib_regular_rreq();
sleep(5);
aodv_test_update_fib_regular_rreq();
sleep(5);
aodv_test_add_to_fib_regular_rrep();
sleep(5);
aodv_test_update_fib_regular_rrep();
sleep(5);
aodv_test_route_expired();
printf("All done!\n");
}

View File

@ -1,35 +0,0 @@
/*
* Copyright (C) 2014 Hochschule für Angewandte Wissenschaften Hamburg (HAW)
* Copyright (C) 2015 Lotte Steenbrink <lotte.steenbrink@haw-hamburg.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 tests
* @{
*
* @file
* @brief tests for the interaction between AODVv2 and the FIB
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
*
* @}
*/
#ifndef AODV_FIB_TESTS_H_
#define AODV_FIB_TESTS_H_
#ifdef __cplusplus
extern "C" {
#endif
void aodv_test_add_to_fib(void);
#ifdef __cplusplus
}
#endif
#endif /* AODV_FIB_TESTS_H_ */

View File

@ -1,69 +0,0 @@
/*
* Copyright (C) 2014 Hochschule für Angewandte Wissenschaften Hamburg (HAW)
* Copyright (C) 2015 Lotte Steenbrink <lotte.steenbrink@haw-hamburg.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 tests
* @{
*
* @file
* @brief constants and global variables for AODVv2 tests
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
*
* @}
*/
#ifndef AODV_TESTS_H_
#define AODV_TESTS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "udp.h"
#include "rfc5444/rfc5444_writer.h"
#define AODV_TEST_MSGBUF_MAX (500)
typedef struct
{
unsigned char buffer[AODV_TEST_MSGBUF_MAX];
uint8_t length;
struct netaddr* sender;
} aodvv2_test_msg;
extern radio_address_t aodvv2_iface_id;
extern aodvv2_test_msg aodv_test_plain_rreq;
extern aodvv2_test_msg aodv_test_more_recent_rreq;
extern aodvv2_test_msg aodv_test_plain_rrep;
extern aodvv2_test_msg aodv_test_more_recent_rrep;
/*
Messages will always be sent/stored along the following path:
OrigAddr -> sender_oa -> TESTNODE -> sender_ta -> TargAddr
OrigAddr <- sender_oa <- TESTNODE <- sender_ta <- TargAddr */
extern struct netaddr aodvv2_test_origaddr;
extern struct netaddr aodvv2_test_sender_oa;
extern struct netaddr aodvv2_test_sender_ta;
extern struct netaddr aodvv2_test_targaddr;
/* callback for the rfc5444 packet writer. can be set with aodv_packet_writer_init()
* To enforce the dropping of all control packets (and reduce overhead) */
void aodv_test_drop_packet(struct rfc5444_writer *wr __attribute__ ((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length);
#ifdef __cplusplus
}
#endif
#endif /* AODV_FIB_TESTS_H_ */

View File

@ -1,171 +0,0 @@
/*
* Copyright (C) 2014 Hochschule für Angewandte Wissenschaften Hamburg (HAW)
* Copyright (C) 2015 Lotte Steenbrink <lotte.steenbrink@haw-hamburg.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 tests
* @{
*
* @file
* @brief tests for the AODVv2 writer
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "aodv_writer_tests.h"
#include "aodv_tests.h"
#include "aodv.h"
#include "aodvv2/aodvv2.h"
#include "common/autobuf.h"
#include "rfc5444/rfc5444_writer.h"
#include "rfc5444/rfc5444_print.h"
#include "writer.h"
#include "thread.h"
aodvv2_test_msg aodv_test_plain_rreq;
aodvv2_test_msg aodv_test_more_recent_rreq;
aodvv2_test_msg aodv_test_plain_rrep;
aodvv2_test_msg aodv_test_more_recent_rrep;
static aodvv2_test_msg* current_msg; /* Point to the buffer the current message should be written to.
* Yes, this is awful, but I fear the oonf_apis
* callback infrastructure leaves me no other choice...
* Sorry. :( */
/* All the test data */
static timex_t now, validity_t;
static struct aodvv2_packet_data plain_rreq_msg, plain_rrep_msg;
static int aodv_test_writer_init_data(void)
{
vtimer_now(&now);
validity_t = timex_set(AODVV2_ACTIVE_INTERVAL + AODVV2_MAX_IDLETIME, 0);
plain_rreq_msg = (struct aodvv2_packet_data) {
.hoplimit = AODVV2_MAX_HOPCOUNT,
.sender = aodvv2_test_sender_oa,
.metricType = AODVV2_DEFAULT_METRIC_TYPE,
.origNode = {
.addr = aodvv2_test_origaddr,
.metric = 2,
.seqnum = 1,
},
.targNode = {
.addr = aodvv2_test_targaddr,
.metric = 12,
.seqnum = 1,
},
.timestamp = now,
};
vtimer_now(&now);
plain_rrep_msg = (struct aodvv2_packet_data) {
.hoplimit = AODVV2_MAX_HOPCOUNT,
.sender = aodvv2_test_sender_ta,
.metricType = AODVV2_DEFAULT_METRIC_TYPE,
.origNode = {
.addr = aodvv2_test_origaddr,
.metric = 4,
.seqnum = 1,
},
.targNode = {
.addr = aodvv2_test_targaddr,
.metric = 2,
.seqnum = 2,
},
.timestamp = now,
};
return 0;
}
static void aodv_test_write_packet(struct rfc5444_writer *wr __attribute__ ((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length)
{
printf("Writing message to buffer\n");
/* make sure buffer is clear */
memcpy(current_msg->buffer, buffer, length);
current_msg->length = length;
printf("Done.\n");
}
static void aodv_test_writer_write_new_rreq(void)
{
current_msg = &aodv_test_plain_rreq;
current_msg->sender = &aodvv2_test_sender_oa;
aodv_send_rreq(&plain_rreq_msg);
}
static void aodv_test_writer_write_more_recent_rreq(void)
{
plain_rreq_msg.origNode.seqnum += 1;
current_msg = &aodv_test_more_recent_rreq;
current_msg->sender = &aodvv2_test_sender_oa;
aodv_send_rreq(&plain_rreq_msg);
}
static void aodv_test_writer_write_new_rrep(void)
{
current_msg = &aodv_test_plain_rrep;
current_msg->sender = &aodvv2_test_sender_ta;
aodv_send_rrep(&plain_rrep_msg, &aodvv2_test_sender_ta);
}
static void aodv_test_writer_write_more_recent_rrep(void)
{
plain_rrep_msg.targNode.seqnum += 1;
current_msg = &aodv_test_more_recent_rrep;
current_msg->sender = &aodvv2_test_sender_ta;
aodv_send_rrep(&plain_rrep_msg, &aodvv2_test_sender_ta);
}
/* Store packets in buffers that we can use them for testing */
void write_packets_to_buf(void)
{
printf("============= Preparing to write packets to buffers ==================\n");
/* Make sure the threads are up and running */
sleep(2);
if (0 != aodv_test_writer_init_data()){
printf ("FAILED: unable to init data!\n");
return;
}
/* overwrite the aodvv2 packet writer */
aodv_packet_writer_init(aodv_test_write_packet);
aodv_test_writer_write_new_rreq();
/* make sure sender_thread is done */
sleep(2);
aodv_test_writer_write_more_recent_rreq();
/* make sure sender_thread is done */
sleep(2);
aodv_test_writer_write_new_rrep();
/* make sure sender_thread is done */
sleep(2);
aodv_test_writer_write_more_recent_rrep();
/* give current writer time to finish and init aodvv2 again cleanly
* to undo the change to the aodv_packet_writer callback */
sleep(2);
aodv_init();
}

View File

@ -1,35 +0,0 @@
/*
* Copyright (C) 2014 Hochschule für Angewandte Wissenschaften Hamburg (HAW)
* Copyright (C) 2015 Lotte Steenbrink <lotte.steenbrink@haw-hamburg.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 tests
* @{
*
* @file
* @brief tests for the AODVv2 writer
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
*
* @}
*/
#ifndef AODV_WRITER_TESTS_H_
#define AODV_WRITER_TESTS_H_
#ifdef __cplusplus
extern "C" {
#endif
void write_packets_to_buf(void);
#ifdef __cplusplus
}
#endif
#endif /* AODV_WRITER_TESTS_H_ */

View File

@ -1,124 +0,0 @@
/*
* Copyright (C) 2014 Hochschule für Angewandte Wissenschaften Hamburg (HAW)
* Copyright (C) 2015 Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
* Copyright (C) 2014 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.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 tests
* @{
*
* @file
* @brief tests for the interaction between AODVv2 and the FIB
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
* @author Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <unistd.h>
#include "udp.h"
#include "thread.h"
#include "aodvv2/aodvv2.h"
#include "aodv_writer_tests.h"
#include "aodv_fib_tests.h"
#include "aodv_tests.h"
#define AODVV2_IFACE (0) /**< The used Trasmssion device */
/** The node IPv6 address */
ipv6_addr_t myaddr;
radio_address_t aodvv2_iface_id;
struct netaddr aodvv2_test_sender_oa, aodvv2_test_sender_ta, aodvv2_test_origaddr, aodvv2_test_targaddr;
/**
* @brief prepares this node
* @return 0 on success
*/
static int aodvv2_setup_node(void)
{
/* setup the radio interface */
if( net_if_set_src_address_mode(AODVV2_IFACE, NET_IF_TRANS_ADDR_M_SHORT) != 1 ) {
return -1;
}
aodvv2_iface_id = net_if_get_hardware_address(AODVV2_IFACE);
if( aodvv2_iface_id == 0 ) {
return -1;
}
/* choose addresses */
ipv6_addr_init(&myaddr, 0x2015, 0x3, 0x18, 0x1111, 0x0, 0x0, 0x0, aodvv2_iface_id);
/* and set it */
if( ipv6_net_if_add_addr(AODVV2_IFACE, &myaddr, NDP_ADDR_STATE_PREFERRED, 0, 0, 0) != 1) {
return -1;
}
return 0;
}
/**
* @brief init data that needs to be globally known
*/
static int aodvv2_init_testdata(void)
{
if( netaddr_from_string(&aodvv2_test_origaddr, "::10") == -1 ) {
return -1;
}
if( netaddr_from_string(&aodvv2_test_sender_oa, "::11") == -1 ) {
return -1;
}
if( netaddr_from_string(&aodvv2_test_sender_ta, "::12") == -1 ) {
return -1;
}
if( netaddr_from_string(&aodvv2_test_targaddr, "::13") == -1 ) {
return -1;
}
return 0;
}
void aodv_test_drop_packet(struct rfc5444_writer *wr __attribute__ ((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length)
{
(void) buffer;
(void) length;
}
int main(void)
{
if( aodvv2_init_testdata() != 0 ) {
return -1;
}
if( aodvv2_setup_node() != 0 ) {
return -1;
}
aodv_init();
write_packets_to_buf();
sleep(5);
/* TODO:
- use route and see if it updates the lifetime
*/
aodv_test_add_to_fib();
return 0;
}