Browse Source

Add the AODVv2 Routing Protocol

This PR depends on #1766.

It contains a minimal implementation of the AODVv2 routing protocol.
*Not* implemented are:

	- AckReqs
	- alternate metrics
	- multiple interfaces
	- clients and Client Networks
	- buffering
	- all addresses, TLVs, and features that are marked as optional

An example application can be found at https://github.com/Lotterleben/RIOT-AODVv2/tree/master/aodvv2_demo.

The implementation relies heavily on a functioning Neighbor Discovery Protocol.
It might be necessary to fill the neighbor cache manually with the current state
of RIOTs NDP implementation.

The value of AODVV2_MAX_UNREACHABLE_NODES has been chosen arbitrarily and will be subject to
future improvement.

Please note that based on my experience, with the default transceiver
buffer size (3) of the native port, about 2/3 of the route discoveries
will fail. This has been addressed in issue #1747. It is advised to increase
the transceiver buffer size when using AODVv2 as a routing protocol.
dev/timer
Lotte Steenbrink 9 years ago
parent
commit
0c67c02047
  1. 7
      Makefile.dep
  2. 3
      sys/Makefile
  3. 52
      sys/net/include/aodvv2/aodvv2.h
  4. 102
      sys/net/include/aodvv2/types.h
  5. 1
      sys/net/routing/aodvv2/Makefile
  6. 478
      sys/net/routing/aodvv2/aodv.c
  7. 131
      sys/net/routing/aodvv2/aodv.h
  8. 54
      sys/net/routing/aodvv2/aodv_debug.h
  9. 61
      sys/net/routing/aodvv2/constants.h
  10. 754
      sys/net/routing/aodvv2/reader.c
  11. 62
      sys/net/routing/aodvv2/reader.h
  12. 268
      sys/net/routing/aodvv2/routingtable.c
  13. 163
      sys/net/routing/aodvv2/routingtable.h
  14. 49
      sys/net/routing/aodvv2/seqnum.c
  15. 63
      sys/net/routing/aodvv2/seqnum.h
  16. 242
      sys/net/routing/aodvv2/utils.c
  17. 115
      sys/net/routing/aodvv2/utils.h
  18. 359
      sys/net/routing/aodvv2/writer.c
  19. 101
      sys/net/routing/aodvv2/writer.h

7
Makefile.dep

@ -47,6 +47,13 @@ ifneq (,$(filter sixlowpan,$(USEMODULE)))
USEMODULE += vtimer
endif
ifneq (,$(filter aodvv2,$(USEMODULE)))
USEMODULE += vtimer
USEMODULE += sixlowpan
USEMODULE += oonf_common
USEMODULE += oonf_rfc5444
endif
ifneq (,$(filter uart0,$(USEMODULE)))
USEMODULE += posix
endif

3
sys/Makefile

@ -44,6 +44,9 @@ 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

52
sys/net/include/aodvv2/aodvv2.h

@ -0,0 +1,52 @@
/*
* 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 aodvv2/aodvv2.h
* @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_ */
/** @} */

102
sys/net/include/aodvv2/types.h

@ -0,0 +1,102 @@
/*
* 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 aodvv2/types.h
* @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 */

1
sys/net/routing/aodvv2/Makefile

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

478
sys/net/routing/aodvv2/aodv.c

@ -0,0 +1,478 @@
/*
* 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 aodv.c
* @brief aodvv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#include "debug.h"
#include "aodv.h"
#include "aodvv2/aodvv2.h"
#include "aodv_debug.h"
#define ENABLE_DEBUG (0)
#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 _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);
#ifdef DEBUG_ENABLED
char addr_str[IPV6_MAX_ADDR_STR_LEN];
static struct netaddr_str nbuf;
#endif
static char aodv_rcv_stack_buf[KERNEL_CONF_STACKSIZE_MAIN];
static char aodv_snd_stack_buf[KERNEL_CONF_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;
struct netaddr na_mcast = (struct netaddr){};
void aodv_init(void)
{
AODV_DEBUG("%s()\n", __func__);
/* TODO: set if_id properly */
int if_id = 0;
net_if_set_src_address_mode(if_id, NET_IF_TRANS_ADDR_M_SHORT);
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), 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),
PRIORITY_MAIN, CREATE_STACKTEST, _aodv_sender_thread,
NULL, "_aodv_sender_thread");
/* register aodv for routing */
ipv6_iface_set_routing_provider(aodv_get_next_hop);
}
void aodv_set_metric_type(aodvv2_metric_t metric_type)
{
if (metric_type != AODVV2_DEFAULT_METRIC_TYPE) {
return;
}
_metric_type = metric_type;
}
void aodv_send_rreq(struct aodvv2_packet_data *packet_data)
{
AODV_DEBUG("%s()\n", __func__);
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);
}
void aodv_send_rrep(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop)
{
AODV_DEBUG("%s()\n", __func__);
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);
}
void aodv_send_rerr(struct unreachable_node unreachable_nodes[], size_t len, struct netaddr *next_hop)
{
AODV_DEBUG("%s()\n", __func__);
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);
}
/*
* 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, sizeof msgq);
AODV_DEBUG("_aodv_sender_thread initialized.\n");
while (true) {
AODV_DEBUG("%s()\n", __func__);
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 {
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;
AODV_DEBUG("%s()\n", __func__);
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))) {
DEBUG("Error: bind to receive socket failed!\n");
socket_base_close(sock_rcv);
}
AODV_DEBUG("ready to receive data\n");
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");
}
AODV_DEBUG("_aodv_receiver_thread() %s:",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_local));
DEBUG(" UDP packet received from %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &sa_rcv.sin6_addr));
struct netaddr _sender;
ipv6_addr_t_to_netaddr(&sa_rcv.sin6_addr, &_sender);
/* For some reason 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");
aodv_packet_reader_handle_packet((void *) buf_rcv, rcv_size, &_sender);
}
}
socket_base_close(sock_rcv);
return NULL;
}
ipv6_addr_t *aodv_get_next_hop(ipv6_addr_t *dest)
{
AODV_DEBUG("aodv_get_next_hop() %s:",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_local));
DEBUG(" getting next hop for %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
struct netaddr _tmp_dest;
ipv6_addr_t_to_netaddr(dest, &_tmp_dest);
timex_t now;
struct unreachable_node unreachable_nodes[AODVV2_MAX_UNREACHABLE_NODES];
size_t len;
/* The network stack sometimes asks us for the next hop towards our own IP */
if (memcmp(dest, &_v6_addr_local, sizeof(ipv6_addr_t)) == 0) {
AODV_DEBUG("That's me, returning loopback\n");
return &_v6_addr_loopback;
}
/*
* TODO use ndp_neighbor_get_ll_address() as soon as it's available.
* note: delete check for active/stale/delayed entries, get_ll_address
* does that for us then
*/
ndp_neighbor_cache_t *ndp_nc_entry = ndp_neighbor_cache_search(dest);
struct aodvv2_routing_entry_t *rt_entry = routingtable_get_entry(&_tmp_dest, _metric_type);
if (ndp_nc_entry != NULL) {
/* Case 2: Broken Link (detected by lower layer) */
int link_broken = (ndp_nc_entry->state == NDP_NCE_STATUS_INCOMPLETE ||
ndp_nc_entry->state == NDP_NCE_STATUS_PROBE) &&
(rt_entry != NULL && rt_entry->state != ROUTE_STATE_BROKEN);
if (link_broken) {
DEBUG("\tNeighbor Cache entry found, but invalid (state: %i). Sending RERR.\n",
ndp_nc_entry->state);
/* mark all routes (active, idle, expired) that use next_hop as broken
* and add all *Active* routes to the list of unreachable nodes */
routingtable_break_and_get_all_hopping_over(&_tmp_dest, unreachable_nodes, &len);
aodv_send_rerr(unreachable_nodes, len, &na_mcast);
return NULL;
}
DEBUG("[aodvv2][ndp] found NC entry. Returning dest addr.\n");
return dest;
}
DEBUG("\t[ndp] no entry for addr %s found\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
if (rt_entry) {
/* Case 1: Undeliverable Packet */
int packet_indeliverable = rt_entry->state == ROUTE_STATE_BROKEN ||
rt_entry->state == ROUTE_STATE_EXPIRED;
if (packet_indeliverable) {
DEBUG("\tRouting table entry found, but invalid (state %i). Sending RERR.\n",
rt_entry->state);
unreachable_nodes[0].addr = _tmp_dest;
unreachable_nodes[0].seqnum = rt_entry->seqnum;
aodv_send_rerr(unreachable_nodes, 1, &na_mcast);
return NULL;
}
DEBUG("\tfound dest %s in routing table\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
vtimer_now(&now);
rt_entry->lastUsed = now;
if (rt_entry->state == ROUTE_STATE_IDLE) {
rt_entry->state = ROUTE_STATE_ACTIVE;
}
/* Currently, there is no way to do this, so I'm doing it the worst
* possible, but safe way: I can't make sure that the current call to
* aodv_get_next_hop() is overridden by another call to aodv_get_next_hop()
* by a thread with higher priority, thus messing up return values if I just
* use a static ipv6_addr_t.
* The following malloc will never be free()'d. TODO: FIX THIS ASAP.
*/
ipv6_addr_t *next_hop = (ipv6_addr_t *) malloc(sizeof(ipv6_addr_t));
netaddr_to_ipv6_addr_t(&rt_entry->nextHopAddr, next_hop);
return next_hop;
}
aodvv2_seqnum_t seqnum = seqnum_get();
seqnum_inc();
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 = _tmp_dest,
},
.timestamp = (timex_t) {0,0} /* this timestamp is never used, it exists
* merely to make the compiler shut up */
};
DEBUG("\tNo route found towards %s, starting route discovery... \n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
aodv_send_rreq(&rreq_data);
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);
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);
}
/* 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);
}

131
sys/net/routing/aodvv2/aodv.h

@ -0,0 +1,131 @@
/*
* 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 aodv.h
* @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_ */

54
sys/net/routing/aodvv2/aodv_debug.h

@ -0,0 +1,54 @@
/*
* 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.
*/
/**
* @addtogroup core_util
* @{
*
* @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
#ifdef DEBUG_ENABLED
#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_*/
/** @} */

61
sys/net/routing/aodvv2/constants.h

@ -0,0 +1,61 @@
/*
* 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 constants.h
* @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;
#ifdef __cplusplus
}
#endif
#endif /* AODVV2_CONSTANTS_H_ */

754
sys/net/routing/aodvv2/reader.c

@ -0,0 +1,754 @@
/*
* 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 reader.c
* @brief reading and handling of RFC5444 aodvv2 messages
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#ifdef RIOT
#include "net_help.h"
#endif
#include "debug.h"
#include "reader.h"
#include "aodv_debug.h"
#define ENABLE_DEBUG (0)
#define VERBOSE_DEBUG (0)
#if VERBOSE_DEBUG
#define VDEBUG(...) AODV_DEBUG(__VA_ARGS__)
#else
#define VDEBUG(...)
#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 uint8_t _get_link_cost(aodvv2_metric_t metricType);
static uint8_t _get_max_metric(aodvv2_metric_t metricType);
static void _update_metric(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 struct rfc5444_reader reader;
#ifdef DEBUG_ENABLED
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)
{
VDEBUG("%s()\n", __func__);
if (!cont->has_hoplimit) {
DEBUG("\tERROR: missing hop limit\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit = cont->hoplimit;
if (packet_data.hoplimit == 0) {
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)
{
#ifdef DEBUG_ENABLED
struct netaddr_str nbuf;
#endif
struct rfc5444_reader_tlvblock_entry *tlv;
bool is_origNode_addr = false;
bool is_targNode_addr = false;
VDEBUG("%s()\n", __func__);
DEBUG("\taddr: %s\n", netaddr_to_string(&nbuf, &cont->addr));
/* handle OrigNode SeqNum TLV */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_ORIGSEQNUM].tlv;
if (tlv) {
DEBUG("\ttlv RFC5444_MSGTLV_ORIGSEQNUM: %d\n", *tlv->single_value);
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) {
DEBUG("\ttlv RFC5444_MSGTLV_TARGSEQNUM: %d\n", *tlv->single_value);
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) {
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) {
DEBUG("\tERROR: Missing or unknown metric TLV.\n");
return RFC5444_DROP_PACKET;
}
if (tlv) {
if (!is_origNode_addr) {
DEBUG("\tERROR: Metric TLV belongs to wrong address.\n");
return RFC5444_DROP_PACKET;
}
VDEBUG("\ttlv RFC5444_MSGTLV_METRIC val: %d, exttype: %d\n",
*tlv->single_value, tlv->type_ext);
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;
uint8_t link_cost = _get_link_cost(packet_data.metricType);
/* Check if packet contains the required information */
if (dropped) {
DEBUG("\t Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((packet_data.origNode.addr._type == AF_UNSPEC) || !packet_data.origNode.seqnum) {
DEBUG("\tERROR: missing OrigNode Address or SeqNum. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if (packet_data.targNode.addr._type == AF_UNSPEC) {
DEBUG("\tERROR: missing TargNode Address. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if (packet_data.hoplimit == 0) {
DEBUG("\tERROR: Hoplimit is 0. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((_get_max_metric(packet_data.metricType) - link_cost)
<= packet_data.origNode.metric) {
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)) {
DEBUG("\tPacket is redundant. Dropping Packet. %i\n", RFC5444_DROP_PACKET);
return RFC5444_DROP_PACKET;
}
_update_metric(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) {
DEBUG("OH NOES! No bidirectional link to sender. Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
/* HACKY FIX ENDS HERE */
VDEBUG("\tCreating new Routing Table entry...\n");
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, link_cost);
routingtable_add_entry(tmp_rt_entry);
free(tmp_rt_entry);
}
else {
if (!routingtable_offers_improvement(rt_entry, &packet_data.origNode)) {
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. */
VDEBUG("\tUpdating Routing Table entry...\n");
routingtable_fill_routing_entry_t_rreq(&packet_data, rt_entry, link_cost);
}
/*
* 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)
{
VDEBUG("%s()\n", __func__);
if (!cont->has_hoplimit) {
VDEBUG("\tERROR: missing hop limit\n");
return RFC5444_DROP_PACKET;
}
packet_data.hoplimit = cont->hoplimit;
if (packet_data.hoplimit == 0) {
VDEBUG("\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)
{
#ifdef DEBUG_ENABLED
struct netaddr_str nbuf;
#endif
struct rfc5444_reader_tlvblock_entry *tlv;
bool is_targNode_addr = false;
VDEBUG("%s()\n", __func__);
VDEBUG("\taddr: %s\n", netaddr_to_string(&nbuf, &cont->addr));
/* handle TargNode SeqNum TLV */
tlv = _rreq_rrep_address_consumer_entries[RFC5444_MSGTLV_TARGSEQNUM].tlv;
if (tlv) {
VDEBUG("\ttlv RFC5444_MSGTLV_TARGSEQNUM: %d\n", *tlv->single_value);
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) {
VDEBUG("\ttlv RFC5444_MSGTLV_ORIGSEQNUM: %d\n", *tlv->single_value);
is_targNode_addr = false;
packet_data.origNode.addr = cont->addr;
packet_data.origNode.seqnum = *tlv->single_value;
}
if (!tlv && !is_targNode_addr) {
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) {
DEBUG("\tERROR: Missing or unknown metric TLV.\n");
return RFC5444_DROP_PACKET;
}
if (tlv) {
if (!is_targNode_addr) {
DEBUG("\tERROR: metric TLV belongs to wrong address.\n");
return RFC5444_DROP_PACKET;
}
VDEBUG("\ttlv RFC5444_MSGTLV_METRIC val: %d, exttype: %d\n",
*tlv->single_value, tlv->type_ext);
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 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;
VDEBUG("%s()\n", __func__);
struct aodvv2_routing_entry_t *rt_entry;
#ifdef DEBUG_ENABLED
struct netaddr_str nbuf;
#endif
timex_t now;
uint8_t link_cost = _get_link_cost(packet_data.metricType);
/* Check if packet contains the required information */
if (dropped) {
DEBUG("\t Dropping packet.\n");
return RFC5444_DROP_PACKET;
}
if ((packet_data.origNode.addr._type == AF_UNSPEC)
|| !packet_data.origNode.seqnum) {
DEBUG("\tERROR: missing OrigNode Address or SeqNum. Dropping packet.\n");
return RFC5444_DROP_PACKET;