1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/net/routing/nhdp/nhdp.c

333 lines
10 KiB
C

/*
* Copyright (C) 2014 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup nhdp
* @{
*
* @file
* @brief Implementation of NHDP's core functionality
*
* @author Fabian Nack <nack@inf.fu-berlin.de>
*
* @}
*/
#include "msg.h"
#include "netapi.h"
#include "net/gnrc/netif.h"
#include "thread.h"
#include "utlist.h"
#include "mutex.h"
#include "rfc5444/rfc5444_writer.h"
#include "lib_table.h"
#include "iib_table.h"
#include "nib_table.h"
#include "nhdp.h"
#include "nhdp_address.h"
#include "nhdp_writer.h"
#include "nhdp_reader.h"
char nhdp_stack[NHDP_STACK_SIZE];
char nhdp_rcv_stack[NHDP_STACK_SIZE];
/* Internal variables */
static kernel_pid_t nhdp_pid = KERNEL_PID_UNDEF;
static kernel_pid_t nhdp_rcv_pid = KERNEL_PID_UNDEF;
static kernel_pid_t helper_pid = KERNEL_PID_UNDEF;
static nhdp_if_entry_t nhdp_if_table[GNRC_NETIF_NUMOF];
static mutex_t send_rcv_mutex = MUTEX_INIT;
static sockaddr6_t sa_bcast;
static int sock_rcv;
#if (NHDP_METRIC_NEEDS_TIMER)
static vtimer_t metric_timer;
static timex_t metric_interval;
#endif
/* Internal function prototypes */
static void *_nhdp_runner(void *arg __attribute__((unused)));
static void *_nhdp_receiver(void *arg __attribute__((unused)));
static void write_packet(struct rfc5444_writer *wr __attribute__((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length);
/*---------------------------------------------------------------------------*
* NHDP Core API *
*---------------------------------------------------------------------------*/
void nhdp_init(void)
{
if (nhdp_pid != KERNEL_PID_UNDEF) {
/* do not initialize twice */
return;
}
/* Prepare interface table */
for (int i = 0; i < GNRC_NETIF_NUMOF; i++) {
nhdp_if_table[i].if_pid = KERNEL_PID_UNDEF;
memset(&nhdp_if_table[i].wr_target, 0, sizeof(struct rfc5444_writer_target));
}
/* Initialize reader and writer */
nhdp_writer_init();
nhdp_reader_init();
}
kernel_pid_t nhdp_start(void)
{
if (nhdp_pid == KERNEL_PID_UNDEF) {
/* Init destination address for NHDP's packets */
sa_bcast.sin6_family = AF_INET6;
sa_bcast.sin6_port = HTONS(MANET_PORT);
ipv6_addr_set_all_nodes_addr(&sa_bcast.sin6_addr);
/* Configure sending/receiving UDP socket */
sock_rcv = socket_base_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
/* Start the NHDP thread */
nhdp_pid = thread_create(nhdp_stack, sizeof(nhdp_stack), THREAD_PRIORITY_MAIN - 1,
CREATE_STACKTEST, _nhdp_runner, NULL, "NHDP");
#if (NHDP_METRIC_NEEDS_TIMER)
/* Configure periodic timer message to refresh metric values */
if (nhdp_pid != KERNEL_PID_UNDEF) {
metric_interval = timex_from_uint64(DAT_REFRESH_INTERVAL * SEC_IN_USEC);
vtimer_set_msg(&metric_timer, metric_interval, nhdp_pid, NHDP_METRIC_TIMER, NULL);
}
#endif
}
return nhdp_pid;
}
int nhdp_register_if_default(kernel_pid_t if_pid, uint8_t *addr, size_t addr_size,
uint8_t addr_type, uint16_t max_pl_size)
{
return nhdp_register_if(if_pid, addr, addr_size, addr_type, max_pl_size,
NHDP_DEFAULT_HELLO_INT_MS, NHDP_DEFAULT_HOLD_TIME_MS);
}
int nhdp_register_if(kernel_pid_t if_pid, uint8_t *addr, size_t addr_size, uint8_t addr_type,
uint16_t max_pl_size, uint16_t hello_int_ms, uint16_t val_time_ms)
{
nhdp_if_entry_t *if_entry = NULL;
nhdp_addr_t *nhdp_addr;
msg_t signal_msg;
if (nhdp_rcv_pid != KERNEL_PID_UNDEF) {
return -2;
}
for (int i = 0; i < GNRC_NETIF_NUMOF; i++) {
if (nhdp_if_table[i].if_pid == KERNEL_PID_UNDEF) {
if_entry = &nhdp_if_table[i];
break;
}
}
if (!if_entry) {
/* Maximum number of registerable interfaces reached */
return -2;
}
uint16_t payload_size = max_pl_size > NHDP_MAX_RFC5444_PACKET_SZ
? NHDP_MAX_RFC5444_PACKET_SZ : max_pl_size;
if_entry->wr_target.packet_buffer = (uint8_t *) calloc(payload_size, sizeof(uint8_t));
if (!if_entry->wr_target.packet_buffer) {
/* Insufficient memory */
return -1;
}
if_entry->wr_target.packet_size = payload_size;
if_entry->wr_target.sendPacket = write_packet;
/* Get NHDP address entry for the given address */
nhdp_addr = nhdp_addr_db_get_address(addr, addr_size, addr_type);
if (!nhdp_addr) {
/* Insufficient memory */
free(if_entry->wr_target.packet_buffer);
return -1;
}
/* Add the interface to the LIB */
if (lib_add_if_addr(if_pid, nhdp_addr) != 0) {
free(if_entry->wr_target.packet_buffer);
nhdp_decrement_addr_usage(nhdp_addr);
return -1;
}
/* Create new IIB for the interface */
if (iib_register_if(if_pid) != 0) {
/* TODO: Cleanup lib entry */
free(if_entry->wr_target.packet_buffer);
nhdp_decrement_addr_usage(nhdp_addr);
return -1;
}
/* Set Interface's PID */
if_entry->if_pid = if_pid;
/* Set HELLO_INTERVAL and H_HOLD_TIME (validity time) */
if_entry->hello_interval.seconds = 0;
if_entry->hello_interval.microseconds = MS_IN_USEC * hello_int_ms;
if_entry->validity_time.seconds = 0;
if_entry->validity_time.microseconds = MS_IN_USEC * val_time_ms;
timex_normalize(&if_entry->hello_interval);
timex_normalize(&if_entry->validity_time);
/* Reset sequence number */
if_entry->seq_no = 0;
/* Everything went well */
nhdp_decrement_addr_usage(nhdp_addr);
nhdp_writer_register_if(&if_entry->wr_target);
helper_pid = if_pid;
/* Start the receiving thread */
nhdp_rcv_pid = thread_create(nhdp_rcv_stack, sizeof(nhdp_rcv_stack), THREAD_PRIORITY_MAIN - 1,
CREATE_STACKTEST, _nhdp_receiver, NULL, "nhdp_rcv_thread");
/* Start sending periodic HELLO */
signal_msg.type = MSG_TIMER;
signal_msg.content.ptr = (char *) if_entry;
/* TODO: msg_send or msg_try_send? */
msg_try_send(&signal_msg, nhdp_pid);
return 0;
}
int nhdp_register_non_manet_if(kernel_pid_t if_pid, uint8_t *addr, size_t addr_size,
uint8_t addr_type)
{
return nhdp_add_address(if_pid, addr, addr_size, addr_type);
}
int nhdp_add_address(kernel_pid_t if_pid, uint8_t *addr, size_t addr_size, uint8_t addr_type)
{
int result;
/* Get NHDP address entry for the given address */
nhdp_addr_t *nhdp_addr = nhdp_addr_db_get_address(addr, addr_size, addr_type);
if (!nhdp_addr) {
/* Insufficient memory */
return -1;
}
result = lib_add_if_addr(if_pid, nhdp_addr);
nhdp_decrement_addr_usage(nhdp_addr);
return result;
}
/*------------------------------------------------------------------------------------*/
/* Internal functions */
/*------------------------------------------------------------------------------------*/
/**
* Function executed by NHDP thread receiving messages in an endless loop
*/
static void *_nhdp_runner(void *arg)
{
nhdp_if_entry_t *if_entry;
msg_t msg_rcvd, msg_queue[NHDP_MSG_QUEUE_SIZE];
(void)arg;
msg_init_queue(msg_queue, NHDP_MSG_QUEUE_SIZE);
while (1) {
msg_receive(&msg_rcvd);
switch (msg_rcvd.type) {
case MSG_TIMER:
mutex_lock(&send_rcv_mutex);
if_entry = (nhdp_if_entry_t *) msg_rcvd.content.ptr;
nhdp_writer_send_hello(if_entry);
/* TODO: Add jitter */
/* Schedule next sending */
vtimer_set_msg(&if_entry->if_timer, if_entry->hello_interval,
thread_getpid(), MSG_TIMER, (void *) if_entry);
mutex_unlock(&send_rcv_mutex);
break;
#if (NHDP_METRIC_NEEDS_TIMER)
case NHDP_METRIC_TIMER:
mutex_lock(&send_rcv_mutex);
/* Process necessary metric computations */
iib_process_metric_refresh();
/* Schedule next sending */
vtimer_set_msg(&metric_timer, metric_interval,
thread_getpid(), NHDP_METRIC_TIMER, NULL);
mutex_unlock(&send_rcv_mutex);
break;
#endif
default:
break;
}
}
return 0;
}
/**
* Receive HELLOs over the configured socket and handle them
*/
static void *_nhdp_receiver(void *arg __attribute__((unused)))
{
uint32_t fromlen;
char nhdp_rcv_buf[NHDP_MAX_RFC5444_PACKET_SZ];
msg_t msg_q[NHDP_MSG_QUEUE_SIZE];
msg_init_queue(msg_q, NHDP_MSG_QUEUE_SIZE);
/* Configure socket address for the manet port 269 */
sockaddr6_t sa_rcv = {.sin6_family = AF_INET6,
.sin6_port = HTONS(MANET_PORT)
};
/* Bind UDP socket to socket address */
if (socket_base_bind(sock_rcv, &sa_rcv, sizeof(sa_rcv)) == -1) {
/* Failed binding the socket */
socket_base_close(sock_rcv);
return 0;
}
while (1) {
int32_t rcv_size = socket_base_recvfrom(sock_rcv, (void *)nhdp_rcv_buf,
NHDP_MAX_RFC5444_PACKET_SZ, 0, &sa_rcv, &fromlen);
if (rcv_size > 0) {
/* Packet received, let the reader handle it */
mutex_lock(&send_rcv_mutex);
nhdp_reader_handle_packet(helper_pid, (void *)nhdp_rcv_buf, rcv_size);
mutex_unlock(&send_rcv_mutex);
}
}
socket_base_close(sock_rcv);
return 0;
}
/**
* Send packet for the registered interface
* Called by oonf_api to send packet over the configured socket
*/
static void write_packet(struct rfc5444_writer *wr __attribute__((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length)
{
socket_base_sendto(sock_rcv, buffer, length, 0, &sa_bcast, sizeof(sa_bcast));
}