mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
279 lines
9.6 KiB
C
279 lines
9.6 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 Writer implementation for message generation in NHDP
|
|
*
|
|
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "timex.h"
|
|
#include "mutex.h"
|
|
|
|
#include "rfc5444/rfc5444.h"
|
|
#include "rfc5444/rfc5444_iana.h"
|
|
#include "rfc5444/rfc5444_writer.h"
|
|
|
|
#include "nhdp.h"
|
|
#include "nhdp_address.h"
|
|
#include "nhdp_writer.h"
|
|
#include "lib_table.h"
|
|
#include "nib_table.h"
|
|
#include "iib_table.h"
|
|
|
|
/* Internal variables */
|
|
static mutex_t mtx_packet_write = MUTEX_INIT;
|
|
static struct rfc5444_writer nhdp_writer;
|
|
static nhdp_if_entry_t *nhdp_wr_curr_if_entry;
|
|
static uint8_t msg_buffer[NHDP_WR_MSG_BUF_SIZE];
|
|
static uint8_t msg_addrtlvs[NHDP_WR_TLV_BUF_SIZE];
|
|
|
|
/* Internal function prototypes */
|
|
static void _nhdp_add_hello_msg_header_cb(struct rfc5444_writer *wr,
|
|
struct rfc5444_writer_message *msg);
|
|
static void _nhdp_add_message_tlvs_cb(struct rfc5444_writer *wr);
|
|
static void _nhdp_add_addresses_cb(struct rfc5444_writer *wr);
|
|
static void _nhdp_add_packet_header_cb(struct rfc5444_writer *writer,
|
|
struct rfc5444_writer_target *rfc5444_target);
|
|
static void netaddr_from_nhdp_address(struct netaddr *target, nhdp_addr_t *n_addr);
|
|
|
|
/* Array containing the known Address TLVs */
|
|
static struct rfc5444_writer_tlvtype _nhdp_addrtlvs[] = {
|
|
[RFC5444_ADDRTLV_LOCAL_IF] = { .type = RFC5444_ADDRTLV_LOCAL_IF },
|
|
[RFC5444_ADDRTLV_LINK_STATUS] = { .type = RFC5444_ADDRTLV_LINK_STATUS },
|
|
[RFC5444_ADDRTLV_OTHER_NEIGHB] = { .type = RFC5444_ADDRTLV_OTHER_NEIGHB },
|
|
[RFC5444_ADDRTLV_LINK_METRIC] = { .type = RFC5444_ADDRTLV_LINK_METRIC, .exttype = NHDP_METRIC }
|
|
};
|
|
|
|
/* Writer content provider for HELLO messages */
|
|
static struct rfc5444_writer_content_provider _nhdp_message_content_provider = {
|
|
.msg_type = RFC5444_MSGTYPE_HELLO,
|
|
.addMessageTLVs = _nhdp_add_message_tlvs_cb,
|
|
.addAddresses = _nhdp_add_addresses_cb,
|
|
};
|
|
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* NHDP Writer API *
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
void nhdp_writer_init(void)
|
|
{
|
|
struct rfc5444_writer_message *_hello_msg;
|
|
|
|
mutex_lock(&mtx_packet_write);
|
|
|
|
/* Reset current interface */
|
|
nhdp_wr_curr_if_entry = NULL;
|
|
|
|
/* Configure NHDP writer */
|
|
nhdp_writer.msg_buffer = msg_buffer;
|
|
nhdp_writer.msg_size = sizeof(msg_buffer);
|
|
nhdp_writer.addrtlv_buffer = msg_addrtlvs;
|
|
nhdp_writer.addrtlv_size = sizeof(msg_addrtlvs);
|
|
|
|
/* Initialize writer */
|
|
rfc5444_writer_init(&nhdp_writer);
|
|
|
|
/* Register HELLO msg with 16 byte addresses and content provider */
|
|
rfc5444_writer_register_msgcontentprovider(&nhdp_writer,
|
|
&_nhdp_message_content_provider, _nhdp_addrtlvs, ARRAYSIZE(_nhdp_addrtlvs));
|
|
_hello_msg = rfc5444_writer_register_message(&nhdp_writer, RFC5444_MSGTYPE_HELLO, false, 16);
|
|
_hello_msg->addMessageHeader = _nhdp_add_hello_msg_header_cb;
|
|
|
|
mutex_unlock(&mtx_packet_write);
|
|
}
|
|
|
|
void nhdp_writer_cleanup(void)
|
|
{
|
|
mutex_lock(&mtx_packet_write);
|
|
|
|
nhdp_wr_curr_if_entry = NULL;
|
|
rfc5444_writer_cleanup(&nhdp_writer);
|
|
|
|
mutex_unlock(&mtx_packet_write);
|
|
}
|
|
|
|
void nhdp_writer_register_if(struct rfc5444_writer_target *new_if)
|
|
{
|
|
mutex_lock(&mtx_packet_write);
|
|
|
|
/* Add packet header callback to writer target of the interface */
|
|
new_if->addPacketHeader = _nhdp_add_packet_header_cb;
|
|
/* Register target interface in writer */
|
|
rfc5444_writer_register_target(&nhdp_writer, new_if);
|
|
|
|
mutex_unlock(&mtx_packet_write);
|
|
}
|
|
|
|
void nhdp_writer_send_hello(nhdp_if_entry_t *if_entry)
|
|
{
|
|
mutex_lock(&mtx_packet_write);
|
|
|
|
/* Register interface as current sending interface */
|
|
nhdp_wr_curr_if_entry = if_entry;
|
|
|
|
/* Create HELLO message and send it using the given interface */
|
|
rfc5444_writer_create_message(&nhdp_writer, RFC5444_MSGTYPE_HELLO,
|
|
rfc5444_writer_singletarget_selector, &if_entry->wr_target);
|
|
rfc5444_writer_flush(&nhdp_writer, &if_entry->wr_target, false);
|
|
|
|
mutex_unlock(&mtx_packet_write);
|
|
}
|
|
|
|
void nhdp_writer_add_addr(struct rfc5444_writer *wr, nhdp_addr_t *addr,
|
|
enum rfc5444_addrtlv_iana type, uint8_t value,
|
|
uint16_t metric_in, uint16_t metric_out)
|
|
{
|
|
struct rfc5444_writer_address *wr_addr;
|
|
struct netaddr n_addr;
|
|
|
|
netaddr_from_nhdp_address(&n_addr, addr);
|
|
|
|
switch (type) {
|
|
case RFC5444_ADDRTLV_LOCAL_IF:
|
|
/* Address is mandatory for every sub-msg (if message is splitted) */
|
|
wr_addr = rfc5444_writer_add_address(wr, _nhdp_message_content_provider.creator,
|
|
&n_addr, true);
|
|
break;
|
|
|
|
case RFC5444_ADDRTLV_LINK_STATUS:
|
|
/* Fall through */
|
|
|
|
case RFC5444_ADDRTLV_OTHER_NEIGHB:
|
|
/* Address only has to be included in one sub-msg (if message is splitted) */
|
|
wr_addr = rfc5444_writer_add_address(wr, _nhdp_message_content_provider.creator,
|
|
&n_addr, false);
|
|
break;
|
|
|
|
default:
|
|
/* Unknown type, extend switch if other types are allowed */
|
|
return;
|
|
}
|
|
|
|
rfc5444_writer_add_addrtlv(wr, wr_addr, &_nhdp_addrtlvs[type],
|
|
&value, sizeof(uint8_t), false);
|
|
|
|
/* Add LINK_METRIC TLV if necessary */
|
|
if ((NHDP_METRIC == NHDP_LMT_DAT) && (metric_in != NHDP_METRIC_UNKNOWN)) {
|
|
switch(type) {
|
|
case RFC5444_ADDRTLV_LINK_STATUS:
|
|
metric_in |= NHDP_KD_LM_INC;
|
|
metric_in |= (metric_in == metric_out) ? NHDP_KD_LM_OUT : 0x00;
|
|
break;
|
|
case RFC5444_ADDRTLV_OTHER_NEIGHB:
|
|
metric_in |= NHDP_KD_NM_INC;
|
|
metric_in |= (metric_in == metric_out) ? NHDP_KD_NM_OUT : 0x00;
|
|
break;
|
|
default:
|
|
/* Other types are not used and therefore no address tlv is added */
|
|
return;
|
|
}
|
|
rfc5444_writer_add_addrtlv(wr, wr_addr, &_nhdp_addrtlvs[RFC5444_ADDRTLV_LINK_METRIC],
|
|
&metric_in, sizeof(metric_in), true);
|
|
}
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------------*/
|
|
/* Internal functions */
|
|
/*------------------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Set the header for the currently constructed HELLO message
|
|
* Called by oonf_api during message creation
|
|
*/
|
|
static void
|
|
_nhdp_add_hello_msg_header_cb(struct rfc5444_writer *wr, struct rfc5444_writer_message *msg)
|
|
{
|
|
/* No originator, no hopcount, no hoplimit, no sequence number */
|
|
rfc5444_writer_set_msg_header(wr, msg, false, false, false, false);
|
|
}
|
|
|
|
/**
|
|
* Add validity time and interval time message TLVs to current message
|
|
* Called by oonf_api during message creation
|
|
*/
|
|
static void _nhdp_add_message_tlvs_cb(struct rfc5444_writer *wr)
|
|
{
|
|
uint8_t validity_time, interval_time;
|
|
/* Convert validity time and interval time to milliseconds */
|
|
uint64_t val_tmp = (uint64_t) nhdp_wr_curr_if_entry->validity_time.seconds * MS_PER_SEC
|
|
+ (nhdp_wr_curr_if_entry->validity_time.microseconds / 1000ULL);
|
|
uint64_t int_tmp = (uint64_t) nhdp_wr_curr_if_entry->hello_interval.seconds * MS_PER_SEC
|
|
+ (nhdp_wr_curr_if_entry->hello_interval.microseconds / 1000ULL);
|
|
|
|
/* Add validity time (mandatory) and interval time to msg */
|
|
validity_time = rfc5444_timetlv_encode(val_tmp);
|
|
interval_time = rfc5444_timetlv_encode(int_tmp);
|
|
rfc5444_writer_add_messagetlv(wr, RFC5444_MSGTLV_VALIDITY_TIME, 0, &validity_time,
|
|
sizeof(validity_time));
|
|
rfc5444_writer_add_messagetlv(wr, RFC5444_MSGTLV_INTERVAL_TIME, 0, &interval_time,
|
|
sizeof(interval_time));
|
|
}
|
|
|
|
/**
|
|
* Add addresses and corresponding TLVs to current message
|
|
* Called by oonf_api during message creation
|
|
*/
|
|
static void _nhdp_add_addresses_cb(struct rfc5444_writer *wr)
|
|
{
|
|
lib_fill_wr_addresses(nhdp_wr_curr_if_entry->if_pid, wr);
|
|
iib_fill_wr_addresses(nhdp_wr_curr_if_entry->if_pid, wr);
|
|
nib_fill_wr_addresses(wr);
|
|
nhdp_reset_addresses_tmp_usg(0);
|
|
}
|
|
|
|
/**
|
|
* Add packet header with sequence number to current packet
|
|
* Called by oonf_api during packet creation
|
|
*/
|
|
static void _nhdp_add_packet_header_cb(struct rfc5444_writer *writer,
|
|
struct rfc5444_writer_target *rfc5444_target)
|
|
{
|
|
rfc5444_writer_set_pkt_header(writer, rfc5444_target, true);
|
|
rfc5444_writer_set_pkt_seqno(writer, rfc5444_target, ++nhdp_wr_curr_if_entry->seq_no);
|
|
}
|
|
|
|
/**
|
|
* Construct a netaddr from a given NHDP address
|
|
*/
|
|
static void netaddr_from_nhdp_address(struct netaddr *target, nhdp_addr_t *n_addr)
|
|
{
|
|
memset(target->_addr, 0, NETADDR_MAX_LENGTH);
|
|
memcpy(target->_addr, n_addr->addr, n_addr->addr_size);
|
|
|
|
switch (n_addr->addr_type) {
|
|
case AF_CC110X:
|
|
target->_prefix_len = 8u;
|
|
target->_type = AF_CC110X;
|
|
break;
|
|
|
|
case AF_INET:
|
|
target->_prefix_len = 32u;
|
|
target->_type = AF_INET;
|
|
break;
|
|
|
|
case AF_INET6:
|
|
/* Fall-through */
|
|
|
|
default:
|
|
target->_prefix_len = 128u;
|
|
target->_type = AF_INET6;
|
|
break;
|
|
}
|
|
}
|