2014-07-08 16:54:54 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013, 2014 INRIA.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
/**
|
2014-07-08 16:54:54 +02:00
|
|
|
* @ingroup rpl
|
|
|
|
* @{
|
2013-06-22 05:11:53 +02:00
|
|
|
*
|
2014-07-08 16:54:54 +02:00
|
|
|
* @file rpl.c
|
|
|
|
* @brief Implementation of the RPL-core.
|
2013-06-22 05:11:53 +02:00
|
|
|
*
|
2014-07-08 16:54:54 +02:00
|
|
|
* Implementation of core RPL-functions. Normally it shouldn't be necessary to
|
|
|
|
* modify this file.
|
2013-06-22 05:11:53 +02:00
|
|
|
*
|
2014-07-08 16:54:54 +02:00
|
|
|
* @author Eric Engel <eric.engel@fu-berlin.de>
|
|
|
|
* @author Fabian Brandt <fabianbr@zedat.fu-berlin.de>
|
2013-06-22 05:11:53 +02:00
|
|
|
*/
|
|
|
|
|
2012-01-19 17:35:50 +01:00
|
|
|
#include <string.h>
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "vtimer.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "mutex.h"
|
2013-08-09 03:13:37 +02:00
|
|
|
|
2012-01-26 20:26:55 +01:00
|
|
|
#include "msg.h"
|
2012-01-19 17:35:50 +01:00
|
|
|
#include "rpl.h"
|
2013-03-15 17:48:13 +01:00
|
|
|
#include "etx_beaconing.h"
|
2012-01-26 20:26:55 +01:00
|
|
|
#include "of0.h"
|
2013-03-15 17:48:13 +01:00
|
|
|
#include "of_mrhof.h"
|
2012-02-02 21:31:28 +01:00
|
|
|
#include "trickle.h"
|
2012-01-19 17:35:50 +01:00
|
|
|
|
2013-08-05 16:10:54 +02:00
|
|
|
#include "sixlowpan.h"
|
2013-11-20 23:41:21 +01:00
|
|
|
#include "net_help.h"
|
2012-01-19 17:35:50 +01:00
|
|
|
|
2014-06-18 12:11:12 +02:00
|
|
|
/* You can only run Storing Mode by now. Other unsupported modes lead to default (Storing Mode) */
|
|
|
|
#if RPL_DEFAULT_MOP == RPL_STORING_MODE_NO_MC
|
2014-08-06 13:48:18 +02:00
|
|
|
#include "rpl/rpl_storing.h"
|
2014-07-08 16:54:54 +02:00
|
|
|
#elif RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
|
|
|
#include "rpl/rpl_nonstoring.h"
|
2014-06-18 12:11:12 +02:00
|
|
|
#else
|
2014-08-06 13:48:18 +02:00
|
|
|
#include "rpl/rpl_storing.h"
|
2014-06-18 12:11:12 +02:00
|
|
|
#endif
|
|
|
|
|
2013-11-19 21:23:52 +01:00
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
#if ENABLE_DEBUG
|
|
|
|
#undef TRICKLE_TIMER_STACKSIZE
|
|
|
|
#define TRICKLE_TIMER_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
|
2014-02-27 13:52:13 +01:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
2013-11-19 21:23:52 +01:00
|
|
|
#endif
|
|
|
|
#include "debug.h"
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
/* global variables */
|
2014-08-06 09:44:31 +02:00
|
|
|
kernel_pid_t rpl_process_pid = KERNEL_PID_UNDEF;
|
2014-07-17 12:27:29 +02:00
|
|
|
mutex_t rpl_send_mutex = MUTEX_INIT;
|
2014-06-18 12:11:12 +02:00
|
|
|
msg_t rpl_msg_queue[RPL_PKT_RECV_BUF_SIZE];
|
|
|
|
char rpl_process_buf[RPL_PROCESS_STACKSIZE];
|
2012-03-26 00:04:21 +02:00
|
|
|
uint8_t rpl_buffer[BUFFER_SIZE - LL_HDR_LEN];
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
|
|
|
uint8_t srh_buffer[BUFFER_SIZE];
|
|
|
|
uint8_t srh_send_buffer[BUFFER_SIZE];
|
|
|
|
ipv6_addr_t *down_next_hop;
|
|
|
|
ipv6_srh_t *srh_header;
|
|
|
|
msg_t srh_m_send, srh_m_recv;
|
|
|
|
rpl_routing_entry_t rpl_routing_table[RPL_MAX_ROUTING_ENTRIES_NON_STORING];
|
|
|
|
#else
|
|
|
|
rpl_routing_entry_t rpl_routing_table[RPL_MAX_ROUTING_ENTRIES_STORING];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint8_t rpl_max_routing_entries;
|
|
|
|
ipv6_addr_t my_address;
|
|
|
|
|
2014-06-18 12:11:12 +02:00
|
|
|
/* IPv6 message buffer */
|
|
|
|
ipv6_hdr_t *ipv6_buf;
|
2014-07-08 16:54:54 +02:00
|
|
|
icmpv6_hdr_t *icmp_buf;
|
2012-02-26 19:30:48 +01:00
|
|
|
|
2014-02-13 13:57:59 +01:00
|
|
|
uint8_t rpl_init(int if_id)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-11-22 23:57:33 +01:00
|
|
|
rpl_instances_init();
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
/* initialize routing table */
|
|
|
|
rpl_clear_routing_table();
|
2014-07-08 16:54:54 +02:00
|
|
|
|
|
|
|
if (RPL_DEFAULT_MOP == RPL_STORING_MODE_NO_MC) {
|
|
|
|
rpl_max_routing_entries = RPL_MAX_ROUTING_ENTRIES_STORING;
|
|
|
|
rpl_clear_routing_table();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rpl_max_routing_entries = RPL_MAX_ROUTING_ENTRIES_NON_STORING;
|
|
|
|
rpl_clear_routing_table();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rpl_routing_table == NULL) {
|
|
|
|
DEBUGF("Routing table init failed!\n");
|
|
|
|
return SIXLOWERROR_NULLPTR;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DEBUGF("Routing table init finished!\n");
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
init_trickle();
|
|
|
|
rpl_process_pid = thread_create(rpl_process_buf, RPL_PROCESS_STACKSIZE,
|
|
|
|
PRIORITY_MAIN - 1, CREATE_STACKTEST,
|
2014-03-04 20:20:01 +01:00
|
|
|
rpl_process, NULL, "rpl_process");
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-02-13 13:57:59 +01:00
|
|
|
sixlowpan_lowpan_init_interface(if_id);
|
2013-07-16 13:41:23 +02:00
|
|
|
/* need link local prefix to query _our_ corresponding address */
|
2013-06-22 05:11:53 +02:00
|
|
|
ipv6_addr_t ll_address;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_addr_set_link_local_prefix(&ll_address);
|
2014-02-13 13:57:59 +01:00
|
|
|
ipv6_net_if_get_best_src_addr(&my_address, &ll_address);
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_register_rpl_handler(rpl_process_pid);
|
2014-07-08 16:54:54 +02:00
|
|
|
ipv6_iface_set_srh_indicator(rpl_is_root);
|
|
|
|
ipv6_iface_set_routing_provider(rpl_get_next_hop);
|
|
|
|
DEBUGF("All addresses set!\n");
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-04-30 14:41:00 +02:00
|
|
|
/* initialize objective function manager */
|
|
|
|
rpl_of_manager_init(&my_address);
|
2014-12-04 10:46:59 +01:00
|
|
|
rpl_init_mode(&my_address);
|
2013-09-23 18:01:23 +02:00
|
|
|
return SIXLOWERROR_SUCCESS;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void rpl_init_root(void)
|
|
|
|
{
|
2014-06-18 12:11:12 +02:00
|
|
|
rpl_init_root_mode();
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
uint8_t rpl_is_root(void)
|
|
|
|
{
|
|
|
|
return rpl_is_root_mode();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
|
|
|
void internal_srh_process(ipv6_srh_t *srh_header)
|
|
|
|
{
|
|
|
|
/* modify it accordingly - the number of entries is not depending on padding, because there is none. */
|
|
|
|
uint8_t n = srh_header->hdrextlen / sizeof(ipv6_addr_t);
|
|
|
|
|
|
|
|
if (srh_header->segments_left > n) {
|
|
|
|
memset(&down_next_hop, 0, sizeof(ipv6_addr_t));
|
|
|
|
DEBUGF("[Error] source-routing header is invalid.\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
uint8_t segs = srh_header->segments_left;
|
|
|
|
DEBUGF("SRH-length: %d\n", srh_header->hdrextlen);
|
|
|
|
down_next_hop = &srh_header->route[n - segs];
|
|
|
|
srh_header->segments_left = segs - 1;
|
|
|
|
DEBUGF("Segments left after reduction: %d\n", srh_header->segments_left);
|
|
|
|
DEBUGF("Next hop is: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, down_next_hop));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-04 20:20:01 +01:00
|
|
|
void *rpl_process(void *arg)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-03-04 20:20:01 +01:00
|
|
|
(void) arg;
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
msg_t m_recv;
|
2014-06-18 12:11:12 +02:00
|
|
|
msg_init_queue(rpl_msg_queue, RPL_PKT_RECV_BUF_SIZE);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
while (1) {
|
2013-06-22 05:11:53 +02:00
|
|
|
msg_receive(&m_recv);
|
2014-07-08 16:54:54 +02:00
|
|
|
|
2013-07-16 13:41:23 +02:00
|
|
|
/* differentiate packet types */
|
2014-07-08 16:54:54 +02:00
|
|
|
ipv6_buf = ((ipv6_hdr_t *)m_recv.content.ptr);
|
2014-02-27 13:52:44 +01:00
|
|
|
memcpy(&rpl_buffer, ipv6_buf, NTOHS(ipv6_buf->length) + IPV6_HDR_LEN);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
/* This is an RPL-related message. */
|
|
|
|
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_ICMPV6) {
|
|
|
|
icmp_buf = ((icmpv6_hdr_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
|
|
|
|
|
|
|
/* get code for message-interpretation and process message */
|
|
|
|
DEBUGF("Received RPL information of type %04X and length %u\n", icmp_buf->code, NTOHS(ipv6_buf->length));
|
|
|
|
|
|
|
|
switch (icmp_buf->code) {
|
|
|
|
case (ICMP_CODE_DIS): {
|
|
|
|
rpl_recv_DIS();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (ICMP_CODE_DIO): {
|
|
|
|
rpl_recv_DIO();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (ICMP_CODE_DAO): {
|
|
|
|
rpl_recv_DAO();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (ICMP_CODE_DAO_ACK): {
|
|
|
|
rpl_recv_DAO_ACK();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2014-07-08 16:54:54 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
|
|
|
/* If the message is not RPL-type, it relates to non-storing mode */
|
|
|
|
else if (RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) {
|
|
|
|
|
|
|
|
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_SRH) {
|
|
|
|
srh_header = ((ipv6_srh_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
|
|
|
|
|
|
|
/* if there are no segments left, the routing is finished */
|
|
|
|
if (srh_header->segments_left == 0) {
|
|
|
|
DEBUGF("Source routing finished with next header: %02X.\n", srh_header->nextheader);
|
|
|
|
DEBUGF("Size of srh: %d\n", srh_header->hdrextlen);
|
|
|
|
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN + sizeof(ipv6_srh_t)+srh_header->hdrextlen));
|
|
|
|
rpl_remove_srh_header(ipv6_buf, payload, srh_header->nextheader);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
internal_srh_process(srh_header);
|
|
|
|
if (down_next_hop != NULL) {
|
|
|
|
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
|
|
|
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr, down_next_hop, srh_header, 0);
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2014-07-08 16:54:54 +02:00
|
|
|
else {
|
|
|
|
srh_header = rpl_get_srh_header(ipv6_buf);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
if (srh_header != NULL) {
|
|
|
|
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
|
|
|
|
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr, &ipv6_buf->destaddr, srh_header, srh_header->hdrextlen + sizeof(ipv6_srh_t));
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2014-07-08 16:54:54 +02:00
|
|
|
|
|
|
|
#endif
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_send_DIO(ipv6_addr_t *destination)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
if (destination) {
|
|
|
|
DEBUGF("Send DIO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_lock(&rpl_send_mutex);
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_send_DIO_mode(destination);
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_unlock(&rpl_send_mutex);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_send_DAO(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
if (destination) {
|
|
|
|
DEBUGF("Send DAO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_lock(&rpl_send_mutex);
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_send_DAO_mode(destination, lifetime, default_lifetime, start_index);
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_unlock(&rpl_send_mutex);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_send_DIS(ipv6_addr_t *destination)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
if (destination) {
|
|
|
|
DEBUGF("Send DIS to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_lock(&rpl_send_mutex);
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_send_DIS_mode(destination);
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_unlock(&rpl_send_mutex);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_send_DAO_ACK(ipv6_addr_t *destination)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
if (destination) {
|
|
|
|
DEBUGF("Send DAO ACK to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_lock(&rpl_send_mutex);
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_send_DAO_ACK_mode(destination);
|
2014-06-18 12:11:12 +02:00
|
|
|
mutex_unlock(&rpl_send_mutex);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_recv_DIO(void)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-06-18 12:11:12 +02:00
|
|
|
DEBUGF("DIO received\n");
|
2012-03-26 00:04:21 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_recv_DIO_mode();
|
2014-06-18 12:11:12 +02:00
|
|
|
}
|
2012-03-26 00:04:21 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_recv_DAO(void)
|
2014-06-18 12:11:12 +02:00
|
|
|
{
|
|
|
|
DEBUGF("DAO received\n");
|
2013-11-20 23:41:21 +01:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_recv_DAO_mode();
|
2014-06-18 12:11:12 +02:00
|
|
|
}
|
2013-07-16 13:41:23 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_recv_DIS(void)
|
2014-06-18 12:11:12 +02:00
|
|
|
{
|
|
|
|
DEBUGF("DIS received\n");
|
2012-02-14 22:22:01 +01:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_recv_DIS_mode();
|
2012-02-14 22:22:01 +01:00
|
|
|
|
2014-06-18 12:11:12 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
void rpl_recv_DAO_ACK(void)
|
2014-06-18 12:11:12 +02:00
|
|
|
{
|
|
|
|
DEBUGF("DAO ACK received\n");
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
rpl_recv_dao_ack_mode();
|
2014-06-18 12:11:12 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr)
|
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
|
|
|
|
DEBUGF("Looking up the next hop to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
2014-06-18 12:11:12 +02:00
|
|
|
if (rpl_routing_table[i].used) {
|
|
|
|
DEBUGF("checking %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
|
2014-03-16 20:51:29 +01:00
|
|
|
}
|
2014-07-08 16:54:54 +02:00
|
|
|
|
|
|
|
if ((RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) && rpl_is_root()) {
|
|
|
|
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
|
|
|
|
DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
|
|
|
|
return &rpl_routing_table[i].address;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
|
|
|
|
DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop));
|
|
|
|
return &rpl_routing_table[i].next_hop;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-22 02:12:15 +01:00
|
|
|
return (rpl_get_my_preferred_parent());
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void rpl_add_routing_entry(ipv6_addr_t *addr, ipv6_addr_t *next_hop, uint16_t lifetime)
|
|
|
|
{
|
|
|
|
rpl_routing_entry_t *entry = rpl_find_routing_entry(addr);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (entry != NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
entry->lifetime = lifetime;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
DEBUGF("Adding routing entry %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
2014-06-18 12:11:12 +02:00
|
|
|
if (!rpl_routing_table[i].used) {
|
|
|
|
memcpy(&rpl_routing_table[i].address, addr, sizeof(ipv6_addr_t));
|
|
|
|
memcpy(&rpl_routing_table[i].next_hop, next_hop, sizeof(ipv6_addr_t));
|
|
|
|
rpl_routing_table[i].lifetime = lifetime;
|
|
|
|
rpl_routing_table[i].used = 1;
|
2013-06-22 05:11:53 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpl_del_routing_entry(ipv6_addr_t *addr)
|
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
|
|
|
|
DEBUGF("Deleting routing entry %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
2014-06-18 12:11:12 +02:00
|
|
|
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
|
|
|
|
memset(&rpl_routing_table[i], 0, sizeof(rpl_routing_table[i]));
|
2013-06-22 05:11:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl_routing_entry_t *rpl_find_routing_entry(ipv6_addr_t *addr)
|
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
|
|
|
|
DEBUGF("Finding routing entry %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
2014-06-18 12:11:12 +02:00
|
|
|
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
|
|
|
|
return &rpl_routing_table[i];
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpl_clear_routing_table(void)
|
|
|
|
{
|
2014-07-08 16:54:54 +02:00
|
|
|
|
|
|
|
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
|
|
|
memset(&rpl_routing_table[i], 0, sizeof(rpl_routing_table[i]));
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
rpl_routing_entry_t *rpl_get_routing_table(void)
|
|
|
|
{
|
2014-06-18 12:11:12 +02:00
|
|
|
return rpl_routing_table;
|
2012-02-22 00:50:40 +01:00
|
|
|
}
|
2014-06-18 12:11:12 +02:00
|
|
|
|
2014-07-08 16:54:54 +02:00
|
|
|
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
|
|
|
|
/* everything from here on is non-storing mode related */
|
|
|
|
|
|
|
|
void rpl_add_srh_entry(ipv6_addr_t *child, ipv6_addr_t *parent, uint16_t lifetime)
|
|
|
|
{
|
|
|
|
|
|
|
|
rpl_routing_entry_t *entry = rpl_find_routing_entry(child);
|
|
|
|
|
|
|
|
/* If we already have this entry and the parent from parent/child is the same as already
|
|
|
|
* registered, we only update the lifetime. If only the parent of the child changes, we
|
|
|
|
* delete the previous entry and add it below.
|
|
|
|
*/
|
|
|
|
if (entry != NULL) {
|
|
|
|
if (ipv6_addr_is_equal(parent, &entry->next_hop)) {
|
|
|
|
entry->lifetime = lifetime;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rpl_del_routing_entry(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This maybe a bit confusing since the root also using the standard routing table, but in this case
|
|
|
|
* the code stays cleaner - especially for rt_over_timer from trickle.c. Just keep in mind that
|
|
|
|
* address is now child (unique, iteration variable) and parent is now next_hop. The whole routing table
|
|
|
|
* transforms to a list of childs and their parents, so that route aggregation can be done properly.
|
|
|
|
*/
|
|
|
|
DEBUGF("Adding source-routing entry child: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, child));
|
|
|
|
DEBUGF("Adding source-routing entry parent: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, parent));
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
|
|
|
if (!rpl_routing_table[i].used) {
|
|
|
|
memcpy(&rpl_routing_table[i].address, child, sizeof(ipv6_addr_t));
|
|
|
|
memcpy(&rpl_routing_table[i].next_hop, parent, sizeof(ipv6_addr_t));
|
|
|
|
rpl_routing_table[i].lifetime = lifetime;
|
|
|
|
rpl_routing_table[i].used = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Checks if two IPv6 host suffixes are equal.
|
|
|
|
*
|
|
|
|
* @param[in] a An IPv6 address.
|
|
|
|
* @param[in] b Another IPv6 address.
|
|
|
|
*
|
|
|
|
* @return 1 if *a* and *b* are equal for host suffixes, 0 otherwise.
|
|
|
|
*/
|
|
|
|
int ipv6_suffix_is_equal(const ipv6_addr_t *a, const ipv6_addr_t *b)
|
|
|
|
{
|
|
|
|
return (a->uint32[2] == b->uint32[2]) &&
|
|
|
|
(a->uint32[3] == b->uint32[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ipv6_srh_t *rpl_get_srh_header(ipv6_hdr_t *act_ipv6_hdr)
|
|
|
|
{
|
|
|
|
uint8_t route_length = RPL_MAX_SRH_PATH_LENGTH;
|
|
|
|
ipv6_addr_t rev_route[route_length];
|
|
|
|
ipv6_addr_t *actual_node;
|
|
|
|
uint8_t counter = 0;
|
|
|
|
uint8_t traceable;
|
|
|
|
ipv6_srh_t *srh_header = (ipv6_srh_t *)(&srh_buffer);
|
|
|
|
|
|
|
|
/* init source route with child */
|
|
|
|
actual_node = &(act_ipv6_hdr->destaddr);
|
|
|
|
DEBUGF("DESTINATION NODE: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
|
|
|
|
|
|
|
|
while (!(rpl_equal_id(actual_node, &my_address))) {
|
|
|
|
/* set check variable - this is reversed, if a child/parent-relation is found in one iteration of the routing table */
|
|
|
|
traceable = 0;
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
|
|
|
|
if (rpl_routing_table[i].used && ipv6_suffix_is_equal(&rpl_routing_table[i].address, actual_node)) {
|
|
|
|
DEBUGF("[INFO] Found parent-child relation with P: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop));
|
|
|
|
DEBUGF(" and C: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
|
|
|
|
memcpy(&rev_route[counter], actual_node, sizeof(ipv6_addr_t));
|
|
|
|
|
|
|
|
actual_node = &rpl_routing_table[i].next_hop;
|
|
|
|
counter++;
|
|
|
|
traceable = 1;
|
|
|
|
|
|
|
|
if (counter > route_length) {
|
|
|
|
DEBUGF("[INFO] Both lengths are %d and %d\n", counter, route_length);
|
|
|
|
DEBUGF("Error with computing source routing header.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (traceable == 0) {
|
|
|
|
DEBUGF("No route to destination.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* build real route based on reversed route. After building it starts with the node next to destination */
|
|
|
|
if (counter > 1) {
|
|
|
|
for (uint8_t i = 0; i < counter-1; i++) {
|
|
|
|
memcpy(&srh_header->route[i], &rev_route[counter-i-2], sizeof(ipv6_addr_t));
|
|
|
|
}
|
|
|
|
srh_header->hdrextlen = sizeof(ipv6_addr_t)*(counter-1);
|
|
|
|
memcpy(&(act_ipv6_hdr->destaddr), &rev_route[counter-1], sizeof(ipv6_addr_t));
|
|
|
|
DEBUGF("Route size: %d\n", srh_header->hdrextlen);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
srh_header->hdrextlen = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* actually build SRH-header */
|
|
|
|
memcpy(&srh_header->nextheader, &(act_ipv6_hdr->nextheader), sizeof(uint8_t));
|
|
|
|
srh_header->routing_type = 3;
|
|
|
|
srh_header->segments_left = counter - 1;
|
|
|
|
/* cmpri & cmpre are both 0, because by now there is only support for full addresses */
|
|
|
|
srh_header->cmpri = 0;
|
|
|
|
srh_header->cmpre = 0;
|
|
|
|
/* since the route has exactly the length of its intermediate nodes, padding is zero. */
|
|
|
|
srh_header->pad = 0;
|
|
|
|
srh_header->reserved = 0;
|
|
|
|
/* set the destination-address in ipv6-buf->destaddr, which is the pointer of child */
|
|
|
|
return srh_header;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpl_remove_srh_header(ipv6_hdr_t *ipv6_header, const void *buf, uint8_t nextheader)
|
|
|
|
{
|
|
|
|
ipv6_hdr_t *temp_ipv6_header = ((ipv6_hdr_t *)(&srh_send_buffer));
|
|
|
|
uint8_t *payload = &srh_send_buffer[IPV6_HDR_LEN];
|
|
|
|
memcpy(temp_ipv6_header, ipv6_header, sizeof(ipv6_hdr_t));
|
|
|
|
int msg_length = NTOHS(ipv6_header->length) - sizeof(ipv6_srh_t);
|
|
|
|
temp_ipv6_header->length = HTONS(msg_length);
|
|
|
|
temp_ipv6_header->nextheader = nextheader;
|
|
|
|
memcpy(payload, buf, msg_length);
|
|
|
|
DEBUGF("Source routing header extraction finished.\n");
|
|
|
|
DEBUGF("Dest is now: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &temp_ipv6_header->destaddr));
|
|
|
|
srh_m_send.content.ptr = (char *) srh_send_buffer;
|
|
|
|
DEBUGF("Return from relay: %d\n", msg_send_receive(&srh_m_send, &srh_m_recv, ip_process_pid));
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpl_srh_sendto(const void *buf, uint16_t len, ipv6_addr_t *src, ipv6_addr_t *dest, ipv6_srh_t *srh_header, uint8_t srh_length)
|
|
|
|
{
|
|
|
|
ipv6_hdr_t *temp_ipv6_header = ((ipv6_hdr_t *)(&srh_send_buffer));
|
|
|
|
ipv6_srh_t *current_packet = ((ipv6_srh_t *)(&srh_send_buffer[IPV6_HDR_LEN]));
|
|
|
|
uint8_t *payload = &srh_send_buffer[IPV6_HDR_LEN + srh_length];
|
|
|
|
memcpy(&(temp_ipv6_header->destaddr), dest, sizeof(ipv6_addr_t));
|
|
|
|
memcpy(&(temp_ipv6_header->srcaddr), src, sizeof(ipv6_addr_t));
|
|
|
|
memcpy(current_packet, srh_header, srh_length);
|
|
|
|
memcpy(payload, buf, len);
|
|
|
|
uint16_t plength = srh_length + len;
|
|
|
|
|
|
|
|
DEBUGF("Build SRH package finished. Going to send it.\n");
|
|
|
|
DEBUGF("SRH-length: %d\n", current_packet->hdrextlen);
|
|
|
|
DEBUGF("My payload length: %d\n", plength);
|
|
|
|
|
|
|
|
return ipv6_sendto(&temp_ipv6_header->destaddr, IPV6_PROTO_NUM_SRH, (uint8_t *)current_packet, plength, &temp_ipv6_header->destaddr);
|
|
|
|
}
|
|
|
|
#endif
|