1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/net/routing/aodvv2/aodv.c
Lotte Steenbrink 3591894698 aodvv2: fix calls to DEBUG()
``debug.h`` was included before ``ENABLE_DEBUG`` was set to 0 or 1. In consequence, setting ``ENABLE_DEBUG`` to 1 had no effect. This should be fixed now.
2015-01-06 15:57:12 -08:00

480 lines
16 KiB
C

/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014 Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup aodvv2
* @{
*
* @file aodv.c
* @brief aodvv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#include "aodv.h"
#include "aodvv2/aodvv2.h"
#include "aodv_debug.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 _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);
#if ENABLE_DEBUG
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);
/* 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;
}
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);
}