Implement RPL non-storing mode

This commit is contained in:
Simon Duquennoy 2016-02-01 18:02:33 +01:00
parent d14b76d869
commit b3e31e1456
17 changed files with 1149 additions and 278 deletions

View file

@ -47,6 +47,11 @@
#include "net/ipv6/uip-ds6.h"
#endif
#if UIP_CONF_IPV6_RPL
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#endif
#include <string.h>
#define DEBUG DEBUG_NONE
@ -525,7 +530,7 @@ void
tcpip_ipv6_output(void)
{
uip_ds6_nbr_t *nbr = NULL;
uip_ipaddr_t *nexthop;
uip_ipaddr_t *nexthop = NULL;
if(uip_len == 0) {
return;
@ -545,14 +550,25 @@ tcpip_ipv6_output(void)
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
/* Next hop determination */
#if UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING
uip_ipaddr_t ipaddr;
/* Look for a RPL Source Route */
if(rpl_srh_get_next_hop(&ipaddr)) {
nexthop = &ipaddr;
}
#endif /* UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING */
nbr = NULL;
/* We first check if the destination address is on our immediate
link. If so, we simply use the destination address as our
nexthop address. */
if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){
if(nexthop == NULL && uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){
nexthop = &UIP_IP_BUF->destipaddr;
} else {
}
if(nexthop == NULL) {
uip_ds6_route_t *route;
/* Check if we have a route to the destination address. */
route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
@ -636,7 +652,7 @@ tcpip_ipv6_output(void)
/* End of next hop determination */
#if UIP_CONF_IPV6_RPL
if(rpl_update_header_final(nexthop)) {
if(!rpl_finalize_header(nexthop)) {
uip_clear_buf();
return;
}
@ -646,6 +662,7 @@ tcpip_ipv6_output(void)
#if UIP_ND6_SEND_NA
if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE, NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
uip_clear_buf();
PRINTF("tcpip_ipv6_output: failed to add neighbor to cache\n");
return;
} else {
#if UIP_CONF_IPV6_QUEUE_PKT
@ -672,6 +689,7 @@ tcpip_ipv6_output(void)
/* Send the first NS try from here (multicast destination IP address). */
}
#else /* UIP_ND6_SEND_NA */
PRINTF("tcpip_ipv6_output: neighbor not in cache\n");
uip_len = 0;
return;
#endif /* UIP_ND6_SEND_NA */

View file

@ -1801,6 +1801,13 @@ typedef struct uip_routing_hdr {
uint8_t seg_left;
} uip_routing_hdr;
/* RPL Source Routing Header */
typedef struct uip_rpl_srh_hdr {
uint8_t cmpr; /* CmprI and CmprE */
uint8_t pad;
uint8_t reserved[2];
} uip_rpl_srh_hdr;
/* fragmentation header */
typedef struct uip_frag_hdr {
uint8_t next;

View file

@ -57,6 +57,7 @@ void NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK(const linkaddr_t *addr);
void NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK(const linkaddr_t *addr);
#endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK */
#if (UIP_CONF_MAX_ROUTES != 0)
/* The nbr_routes holds a neighbor table to be able to maintain
information about what routes go through what neighbor. This
neighbor table is registered with the central nbr-table repository
@ -71,6 +72,11 @@ MEMB(neighborroutememb, struct uip_ds6_route_neighbor_route, UIP_DS6_ROUTE_NB);
LIST(routelist);
MEMB(routememb, uip_ds6_route_t, UIP_DS6_ROUTE_NB);
static int num_routes = 0;
static void rm_routelist_callback(nbr_table_item_t *ptr);
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
/* Default routes are held on the defaultrouterlist and their
structures are allocated from the defaultroutermemb memory block.*/
LIST(defaultrouterlist);
@ -80,13 +86,10 @@ MEMB(defaultroutermemb, uip_ds6_defrt_t, UIP_DS6_DEFRT_NB);
LIST(notificationlist);
#endif
static int num_routes = 0;
#undef DEBUG
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
static void rm_routelist_callback(nbr_table_item_t *ptr);
/*---------------------------------------------------------------------------*/
#if DEBUG != DEBUG_NONE
static void
@ -156,10 +159,12 @@ uip_ds6_notification_rm(struct uip_ds6_notification *n)
void
uip_ds6_route_init(void)
{
#if (UIP_CONF_MAX_ROUTES != 0)
memb_init(&routememb);
list_init(routelist);
nbr_table_register(nbr_routes,
(nbr_table_callback *)rm_routelist_callback);
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
memb_init(&defaultroutermemb);
list_init(defaultrouterlist);
@ -168,6 +173,7 @@ uip_ds6_route_init(void)
list_init(notificationlist);
#endif
}
#if (UIP_CONF_MAX_ROUTES != 0)
/*---------------------------------------------------------------------------*/
static uip_lladdr_t *
uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
@ -179,36 +185,48 @@ uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
return NULL;
}
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
/*---------------------------------------------------------------------------*/
uip_ipaddr_t *
uip_ds6_route_nexthop(uip_ds6_route_t *route)
{
#if (UIP_CONF_MAX_ROUTES != 0)
if(route != NULL) {
return uip_ds6_nbr_ipaddr_from_lladdr(uip_ds6_route_nexthop_lladdr(route));
} else {
return NULL;
}
#else /* (UIP_CONF_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_head(void)
{
#if (UIP_CONF_MAX_ROUTES != 0)
return list_head(routelist);
#else /* (UIP_CONF_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_next(uip_ds6_route_t *r)
{
#if (UIP_CONF_MAX_ROUTES != 0)
if(r != NULL) {
uip_ds6_route_t *n = list_item_next(r);
return n;
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
return NULL;
}
/*---------------------------------------------------------------------------*/
int
uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr)
{
#if (UIP_CONF_MAX_ROUTES != 0)
const uip_lladdr_t *lladdr;
lladdr = uip_ds6_nbr_lladdr_from_ipaddr(ipaddr);
@ -217,17 +235,25 @@ uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr)
}
return nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)lladdr) != NULL;
#else /* (UIP_CONF_MAX_ROUTES != 0) */
return 0;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
int
uip_ds6_route_num_routes(void)
{
#if (UIP_CONF_MAX_ROUTES != 0)
return num_routes;
#else /* (UIP_CONF_MAX_ROUTES != 0) */
return 0;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_lookup(uip_ipaddr_t *addr)
{
#if (UIP_CONF_MAX_ROUTES != 0)
uip_ds6_route_t *r;
uip_ds6_route_t *found_route;
uint8_t longestmatch;
@ -274,12 +300,16 @@ uip_ds6_route_lookup(uip_ipaddr_t *addr)
}
return found_route;
#else /* (UIP_CONF_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
uip_ipaddr_t *nexthop)
{
#if (UIP_CONF_MAX_ROUTES != 0)
uip_ds6_route_t *r;
struct uip_ds6_route_neighbor_route *nbrr;
@ -426,12 +456,17 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */
return r;
#else /* (UIP_CONF_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
void
uip_ds6_route_rm(uip_ds6_route_t *route)
{
#if (UIP_CONF_MAX_ROUTES != 0)
struct uip_ds6_route_neighbor_route *neighbor_route;
#if DEBUG != DEBUG_NONE
assert_nbr_routes_list_sane();
@ -488,8 +523,11 @@ uip_ds6_route_rm(uip_ds6_route_t *route)
#if DEBUG != DEBUG_NONE
assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
return;
}
#if (UIP_CONF_MAX_ROUTES != 0)
/*---------------------------------------------------------------------------*/
static void
rm_routelist(struct uip_ds6_route_neighbor_routes *routes)
@ -517,10 +555,12 @@ rm_routelist_callback(nbr_table_item_t *ptr)
{
rm_routelist((struct uip_ds6_route_neighbor_routes *)ptr);
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
/*---------------------------------------------------------------------------*/
void
uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
{
#if (UIP_CONF_MAX_ROUTES != 0)
/* Get routing entry list of this neighbor */
const uip_lladdr_t *nexthop_lladdr;
struct uip_ds6_route_neighbor_routes *routes;
@ -529,6 +569,7 @@ uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
routes = nbr_table_get_from_lladdr(nbr_routes,
(linkaddr_t *)nexthop_lladdr);
rm_routelist(routes);
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_defrt_t *

View file

@ -50,7 +50,7 @@ NBR_TABLE_DECLARE(nbr_routes);
void uip_ds6_route_init(void);
#ifndef UIP_CONF_UIP_DS6_NOTIFICATIONS
#define UIP_DS6_NOTIFICATIONS 1
#define UIP_DS6_NOTIFICATIONS (UIP_CONF_MAX_ROUTES != 0)
#else
#define UIP_DS6_NOTIFICATIONS UIP_CONF_UIP_DS6_NOTIFICATIONS
#endif

View file

@ -120,9 +120,6 @@ uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
static void
echo_request_input(void)
{
#if UIP_CONF_IPV6_RPL
uint8_t temp_ext_len;
#endif /* UIP_CONF_IPV6_RPL */
/*
* we send an echo reply. It is trivial if there was no extension
* headers in the request otherwise we need to remove the extension
@ -147,27 +144,7 @@ echo_request_input(void)
}
if(uip_ext_len > 0) {
#if UIP_CONF_IPV6_RPL
if((temp_ext_len = rpl_invert_header())) {
/* If there were other extension headers*/
UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6;
if (uip_ext_len != temp_ext_len) {
uip_len -= (uip_ext_len - temp_ext_len);
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
/* move the echo request payload (starting after the icmp header)
* to the new location in the reply.
* The shift is equal to the length of the remaining extension headers present
* Note: UIP_ICMP_BUF still points to the echo request at this stage
*/
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - (uip_ext_len - temp_ext_len),
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
(uip_len - UIP_IPH_LEN - temp_ext_len - UIP_ICMPH_LEN));
}
uip_ext_len = temp_ext_len;
} else {
#endif /* UIP_CONF_IPV6_RPL */
/* If there were extension headers*/
/* Remove extension headers if any */
UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
uip_len -= uip_ext_len;
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
@ -181,10 +158,13 @@ echo_request_input(void)
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
(uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN));
uip_ext_len = 0;
}
/* Insert RPL extension headers */
#if UIP_CONF_IPV6_RPL
}
rpl_insert_header();
#endif /* UIP_CONF_IPV6_RPL */
}
/* Below is important for the correctness of UIP_ICMP_BUF and the
* checksum
*/
@ -329,37 +309,18 @@ echo_reply_input(void)
{
int ttl;
uip_ipaddr_t sender;
#if UIP_CONF_IPV6_RPL
uint8_t temp_ext_len;
#endif /* UIP_CONF_IPV6_RPL */
PRINTF("Received Echo Reply from ");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF(" to ");
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
PRINTF("\n");
uip_ipaddr_copy(&sender, &UIP_IP_BUF->srcipaddr);
ttl = UIP_IP_BUF->ttl;
if(uip_ext_len > 0) {
#if UIP_CONF_IPV6_RPL
if((temp_ext_len = rpl_invert_header())) {
/* If there were other extension headers*/
UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6;
if (uip_ext_len != temp_ext_len) {
uip_len -= (uip_ext_len - temp_ext_len);
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
/* move the echo reply payload (starting after the icmp
* header) to the new location in the reply. The shift is
* equal to the length of the remaining extension headers
* present Note: UIP_ICMP_BUF still points to the echo reply
* at this stage
*/
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - (uip_ext_len - temp_ext_len),
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
(uip_len - UIP_IPH_LEN - temp_ext_len - UIP_ICMPH_LEN));
}
uip_ext_len = temp_ext_len;
uip_len -= uip_ext_len;
} else {
#endif /* UIP_CONF_IPV6_RPL */
/* If there were extension headers*/
/* Remove extension headers if any */
UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
uip_len -= uip_ext_len;
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
@ -373,9 +334,6 @@ echo_reply_input(void)
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
(uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN));
uip_ext_len = 0;
#if UIP_CONF_IPV6_RPL
}
#endif /* UIP_CONF_IPV6_RPL */
}
/* Call all registered applications to let them know an echo reply

View file

@ -79,6 +79,11 @@
#include "net/ipv6/uip-ds6.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#if UIP_CONF_IPV6_RPL
#include "rpl/rpl.h"
#include "rpl/rpl-private.h"
#endif
#include <string.h>
/*---------------------------------------------------------------------------*/
@ -88,10 +93,6 @@
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
#if UIP_CONF_IPV6_RPL
#include "rpl/rpl.h"
#endif /* UIP_CONF_IPV6_RPL */
#if UIP_LOGGING == 1
#include <stdio.h>
void uip_log(char *msg);
@ -889,7 +890,7 @@ ext_hdr_options_process(void)
*/
#if UIP_CONF_IPV6_RPL
PRINTF("Processing RPL option\n");
if(rpl_verify_header(uip_ext_opt_offset)) {
if(rpl_verify_hbh_header(uip_ext_opt_offset)) {
PRINTF("RPL Option Error: Dropping Packet\n");
return 1;
}
@ -1228,9 +1229,9 @@ uip_process(uint8_t flag)
}
#if UIP_CONF_IPV6_RPL
if(rpl_update_header_empty()) {
if(!rpl_update_header()) {
/* Packet can not be forwarded */
PRINTF("RPL Forward Option Error\n");
PRINTF("RPL header update error\n");
goto drop;
}
#endif /* UIP_CONF_IPV6_RPL */
@ -1368,6 +1369,11 @@ uip_process(uint8_t flag)
PRINTF("Processing Routing header\n");
if(UIP_ROUTING_BUF->seg_left > 0) {
#if UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING
if(rpl_process_srh_header()) {
goto send; /* Proceed to forwarding */
}
#endif /* UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING */
uip_icmp6_error_output(ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, UIP_IPH_LEN + uip_ext_len + 2);
UIP_STAT(++uip_stat.ip.drop);
UIP_LOG("ip6: unrecognized routing type");

View file

@ -236,16 +236,25 @@
#endif
/*
* Hop-by-hop option
* This option control the insertion of the RPL Hop-by-Hop extension header
* into packets originating from this node. Incoming Hop-by-hop extension
* header are still processed and forwarded.
* Embed support for storing mode
*/
#ifdef RPL_CONF_INSERT_HBH_OPTION
#define RPL_INSERT_HBH_OPTION RPL_CONF_INSERT_HBH_OPTION
#else
#define RPL_INSERT_HBH_OPTION 1
#endif
#ifdef RPL_CONF_WITH_STORING
#define RPL_WITH_STORING RPL_CONF_WITH_STORING
#else /* RPL_CONF_WITH_STORING */
#define RPL_WITH_STORING 1
#endif /* RPL_CONF_WITH_STORING */
/*
* Embed support for non-storing mode
*/
#ifdef RPL_CONF_WITH_NON_STORING
#define RPL_WITH_NON_STORING RPL_CONF_WITH_NON_STORING
#else /* RPL_CONF_WITH_NON_STORING */
#define RPL_WITH_NON_STORING 0
#endif /* RPL_CONF_WITH_NON_STORING */
#define RPL_IS_STORING(instance) (RPL_WITH_STORING && ((instance) != NULL) && ((instance)->mop > RPL_MOP_NON_STORING))
#define RPL_IS_NON_STORING(instance) (RPL_WITH_NON_STORING && ((instance) != NULL) && ((instance)->mop == RPL_MOP_NON_STORING))
/*
* RPL DAO ACK support. When enabled, DAO ACK will be sent and requested.

View file

@ -43,7 +43,9 @@
#define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1)
#if (UIP_CONF_MAX_ROUTES != 0)
static struct uip_ds6_notification n;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
static uint8_t to_become_root;
static struct ctimer c;
/*---------------------------------------------------------------------------*/
@ -121,6 +123,7 @@ create_dag_callback(void *ptr)
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
}
}
#if (UIP_CONF_MAX_ROUTES != 0)
/*---------------------------------------------------------------------------*/
static void
route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
@ -136,6 +139,7 @@ route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
}
}
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
/*---------------------------------------------------------------------------*/
static uip_ipaddr_t *
set_global_address(void)
@ -171,7 +175,9 @@ rpl_dag_root_init(void)
if(!initialized) {
to_become_root = 0;
set_global_address();
#if (UIP_CONF_MAX_ROUTES != 0)
uip_ds6_notification_add(&n, route_callback);
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
initialized = 1;
}
}
@ -206,7 +212,9 @@ rpl_dag_root_init_dag_immediately(void)
/* If there are routes in this dag, we remove them all as we are
from now on the new dag root and the old routes are wrong */
if(RPL_IS_STORING(dag->instance)) {
rpl_remove_routes(dag);
}
if(dag->instance != NULL &&
dag->instance->def_route != NULL) {
uip_ds6_defrt_rm(dag->instance->def_route);

View file

@ -98,8 +98,8 @@ rpl_print_neighbor_list(void)
rpl_parent_t *p = nbr_table_head(rpl_parents);
clock_time_t clock_now = clock_time();
printf("RPL: OCP %u rank %u dioint %u, nbr count %u\n",
default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
printf("RPL: MOP %u OCP %u rank %u dioint %u, nbr count %u\n",
default_instance->mop, default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
while(p != NULL) {
const struct link_stats *stats = rpl_get_parent_link_stats(p);
printf("RPL: nbr %3u %5u, %5u => %5u -- %2u %c%c (last tx %u min ago)\n",
@ -418,7 +418,9 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
if(instance->current_dag != dag && instance->current_dag != NULL) {
/* Remove routes installed by DAOs. */
if(RPL_IS_STORING(instance)) {
rpl_remove_routes(instance->current_dag);
}
instance->current_dag->joined = 0;
}
@ -667,7 +669,9 @@ rpl_free_dag(rpl_dag_t *dag)
dag->joined = 0;
/* Remove routes installed by DAOs. */
if(RPL_IS_STORING(dag->instance)) {
rpl_remove_routes(dag);
}
/* Remove autoconfigured address */
if((dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
@ -787,7 +791,9 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
if(instance->current_dag != best_dag) {
/* Remove routes installed by DAOs. */
if(RPL_IS_STORING(instance)) {
rpl_remove_routes(instance->current_dag);
}
PRINTF("RPL: New preferred DAG: ");
PRINT6ADDR(&best_dag->dag_id);
@ -816,7 +822,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
if(!acceptable_rank(best_dag, best_dag->rank)) {
PRINTF("RPL: New rank unacceptable!\n");
rpl_set_preferred_parent(instance->current_dag, NULL);
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) {
if(RPL_IS_STORING(instance) && last_parent != NULL) {
/* Send a No-Path DAO to the removed preferred parent. */
dao_output(last_parent, RPL_ZERO_LIFETIME);
}
@ -828,15 +834,13 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n",
(unsigned)old_rank, best_dag->rank);
RPL_STAT(rpl_stats.parent_switch++);
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
if(last_parent != NULL) {
if(RPL_IS_STORING(instance) && last_parent != NULL) {
/* Send a No-Path DAO to the removed preferred parent. */
dao_output(last_parent, RPL_ZERO_LIFETIME);
}
/* The DAO parent set changed - schedule a DAO transmission. */
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
rpl_schedule_dao(instance);
}
rpl_reset_dio_timer(instance);
#if DEBUG
rpl_print_neighbor_list();
@ -954,9 +958,11 @@ rpl_nullify_parent(rpl_parent_t *parent)
uip_ds6_defrt_rm(dag->instance->def_route);
dag->instance->def_route = NULL;
}
/* Send No-Path DAO only to preferred parent, if any */
/* Send No-Path DAO only when nullifying preferred parent */
if(parent == dag->preferred_parent) {
if(RPL_IS_STORING(dag->instance)) {
dao_output(parent, RPL_ZERO_LIFETIME);
}
rpl_set_preferred_parent(dag, NULL);
}
}
@ -982,9 +988,11 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
dag_src->instance->def_route = NULL;
}
} else if(dag_src->joined) {
if(RPL_IS_STORING(dag_src->instance)) {
/* Remove uIPv6 routes that have this parent as the next hop. */
rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(parent), dag_src);
}
}
PRINTF("RPL: Moving parent ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
@ -1006,6 +1014,25 @@ rpl_has_downward_route(void)
}
/*---------------------------------------------------------------------------*/
rpl_dag_t *
rpl_get_dag(const uip_ipaddr_t *addr)
{
int i, j;
for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
if(instance_table[i].used) {
for(j = 0; j < RPL_MAX_DAG_PER_INSTANCE; ++j) {
if(instance_table[i].dag_table[j].joined
&& uip_ipaddr_prefixcmp(&instance_table[i].dag_table[j].dag_id, addr,
instance_table[i].dag_table[j].prefix_info.length)) {
return &instance_table[i].dag_table[j];
}
}
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
rpl_dag_t *
rpl_get_any_dag(void)
{
int i;
@ -1055,6 +1082,12 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
rpl_parent_t *p;
rpl_of_t *of;
if((!RPL_WITH_NON_STORING && dio->mop == RPL_MOP_NON_STORING)
|| (!RPL_WITH_STORING && (dio->mop == RPL_MOP_STORING_NO_MULTICAST
|| dio->mop == RPL_MOP_STORING_MULTICAST))) {
PRINTF("RPL: DIO advertising a non-supported MOP %u\n", dio->mop);
}
/* Determine the objective function by using the
objective code point of the DIO. */
of = rpl_find_of(dio->ocp);
@ -1333,7 +1366,9 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
return_value = 1;
if(uip_ds6_route_is_nexthop(rpl_get_parent_ipaddr(p)) && !rpl_parent_is_reachable(p)) {
if(RPL_IS_STORING(instance)
&& uip_ds6_route_is_nexthop(rpl_get_parent_ipaddr(p))
&& !rpl_parent_is_reachable(p) && instance->mop > RPL_MOP_NON_STORING) {
PRINTF("RPL: Unacceptable link %u, removing routes via: ", rpl_get_parent_link_metric(p));
PRINT6ADDR(rpl_get_parent_ipaddr(p));
PRINTF("\n");

View file

@ -48,6 +48,7 @@
#include "net/ip/tcpip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "net/packetbuf.h"
#define DEBUG DEBUG_NONE
@ -61,12 +62,14 @@
#define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len])
#define UIP_HBHO_BUF ((struct uip_hbho_hdr *)&uip_buf[uip_l2_l3_hdr_len])
#define UIP_HBHO_NEXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_HOP_BY_HOP_LEN])
#define UIP_RH_BUF ((struct uip_routing_hdr *)&uip_buf[uip_l2_l3_hdr_len])
#define UIP_RPL_SRH_BUF ((struct uip_rpl_srh_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_RH_LEN])
#define UIP_EXT_HDR_OPT_BUF ((struct uip_ext_hdr_opt *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
#define UIP_EXT_HDR_OPT_PADN_BUF ((struct uip_ext_hdr_opt_padn *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
#define UIP_EXT_HDR_OPT_RPL_BUF ((struct uip_ext_hdr_opt_rpl *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
/*---------------------------------------------------------------------------*/
int
rpl_verify_header(int uip_ext_opt_offset)
rpl_verify_hbh_header(int uip_ext_opt_offset)
{
rpl_instance_t *instance;
int down;
@ -103,10 +106,12 @@ rpl_verify_header(int uip_ext_opt_offset)
the packet to be forwareded in the first place. We drop any
routes that go through the neighbor that sent the packet to
us. */
if(RPL_IS_STORING(instance)) {
route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
if(route != NULL) {
uip_ds6_route_rm(route);
}
}
RPL_STAT(rpl_stats.forward_errors++);
/* Trigger DAO retransmission */
rpl_reset_dio_timer(instance);
@ -166,35 +171,299 @@ rpl_verify_header(int uip_ext_opt_offset)
}
PRINTF("RPL: Rank OK\n");
return 0;
}
/*---------------------------------------------------------------------------*/
static void
set_rpl_opt(unsigned uip_ext_opt_offset)
#if RPL_WITH_NON_STORING
int
rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr)
{
uint8_t temp_len;
uint8_t *uip_next_hdr;
int last_uip_ext_len = uip_ext_len;
memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN);
UIP_HBHO_BUF->next = UIP_IP_BUF->proto;
UIP_IP_BUF->proto = UIP_PROTO_HBHO;
UIP_HBHO_BUF->len = RPL_HOP_BY_HOP_LEN - 8;
UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
UIP_EXT_HDR_OPT_RPL_BUF->instance = 0;
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0;
uip_len += RPL_HOP_BY_HOP_LEN;
temp_len = UIP_IP_BUF->len[1];
UIP_IP_BUF->len[1] += UIP_HBHO_BUF->len + 8;
if(UIP_IP_BUF->len[1] < temp_len) {
UIP_IP_BUF->len[0]++;
uip_ext_len = 0;
uip_next_hdr = &UIP_IP_BUF->proto;
/* Look for routing header */
while(uip_next_hdr != NULL && *uip_next_hdr != UIP_PROTO_ROUTING) {
switch(*uip_next_hdr) {
case UIP_PROTO_TCP:
case UIP_PROTO_UDP:
case UIP_PROTO_ICMP6:
case UIP_PROTO_NONE:
uip_next_hdr = NULL;
break;
case UIP_PROTO_HBHO:
case UIP_PROTO_DESTO:
case UIP_PROTO_FRAG:
/* Move to next header */
if(uip_next_hdr != &UIP_IP_BUF->proto) {
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
}
uip_next_hdr = &UIP_EXT_BUF->next;
break;
default:
break;
}
}
if(uip_next_hdr != NULL && *uip_next_hdr == UIP_PROTO_ROUTING
&& UIP_RH_BUF->routing_type == RPL_RH_TYPE_SRH) {
/* Routing header found. The next hop should be already copied as the IPv6 destination
* address, via rpl_process_srh_header. We turn this address into a link-local to enable
* forwarding to next hop */
uip_ipaddr_copy(ipaddr, &UIP_IP_BUF->destipaddr);
uip_create_linklocal_prefix(ipaddr);
uip_ext_len = last_uip_ext_len;
return 1;
}
uip_ext_len = last_uip_ext_len;
return 0;
}
/*---------------------------------------------------------------------------*/
int
rpl_update_header_empty(void)
rpl_process_srh_header(void)
{
uint8_t *uip_next_hdr;
int last_uip_ext_len = uip_ext_len;
uip_ext_len = 0;
uip_next_hdr = &UIP_IP_BUF->proto;
/* Look for routing header */
while(uip_next_hdr != NULL && *uip_next_hdr != UIP_PROTO_ROUTING) {
switch(*uip_next_hdr) {
case UIP_PROTO_TCP:
case UIP_PROTO_UDP:
case UIP_PROTO_ICMP6:
case UIP_PROTO_NONE:
uip_next_hdr = NULL;
break;
case UIP_PROTO_HBHO:
case UIP_PROTO_DESTO:
case UIP_PROTO_FRAG:
/* Move to next header */
if(uip_next_hdr != &UIP_IP_BUF->proto) {
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
}
uip_next_hdr = &UIP_EXT_BUF->next;
break;
default:
break;
}
}
if(uip_next_hdr != NULL && *uip_next_hdr == UIP_PROTO_ROUTING
&& UIP_RH_BUF->routing_type == RPL_RH_TYPE_SRH) {
/* SRH found, now look for next hop */
uint8_t cmpri, cmpre;
uint8_t ext_len;
uint8_t padding;
uint8_t path_len;
uint8_t segments_left;
uip_ipaddr_t current_dest_addr;
segments_left = UIP_RH_BUF->seg_left;
ext_len = (UIP_RH_BUF->len * 8) + 8;
cmpri = UIP_RPL_SRH_BUF->cmpr >> 4;
cmpre = UIP_RPL_SRH_BUF->cmpr & 0x0f;
padding = UIP_RPL_SRH_BUF->pad >> 4;
path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
(void)path_len;
PRINTF("RPL: read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n",
path_len, segments_left, cmpri, cmpre, ext_len, padding);
if(segments_left == 0) {
/* We are the final destination, do nothing */
} else {
uint8_t i = path_len - segments_left; /* The index of the next address to be visited */
uint8_t *addr_ptr = ((uint8_t *)UIP_RH_BUF) + RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
/* As per RFC6554: swap the IPv6 destination address and address[i] */
/* First, copy the current IPv6 destination address */
uip_ipaddr_copy(&current_dest_addr, &UIP_IP_BUF->destipaddr);
/* Second, update the IPv6 destination address with addresses[i] */
memcpy(((uint8_t *)&UIP_IP_BUF->destipaddr) + cmpr, addr_ptr, 16 - cmpr);
/* Third, write current_dest_addr to addresses[i] */
memcpy(addr_ptr, ((uint8_t *)&current_dest_addr) + cmpr, 16 - cmpr);
/* Update segments left field */
UIP_RH_BUF->seg_left--;
PRINTF("RPL: SRH next hop ");
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
PRINTF("\n");
}
uip_ext_len = last_uip_ext_len;
return 1;
}
uip_ext_len = last_uip_ext_len;
return 0;
}
/*---------------------------------------------------------------------------*/
static int
count_matching_bytes(const void *p1, const void *p2, size_t n)
{
int i = 0;
for(i = 0; i < n; i++) {
if(((uint8_t *)p1)[i] != ((uint8_t *)p2)[i]) {
return i;
}
}
return n;
}
/*---------------------------------------------------------------------------*/
static int
insert_srh_header(void)
{
/* Implementation of RFC6554 */
uint8_t temp_len;
uint8_t path_len;
uint8_t ext_len;
uint8_t cmpri, cmpre; /* ComprI and ComprE fields of the RPL Source Routing Header */
uint8_t *hop_ptr;
uint8_t padding;
rpl_ns_node_t *dest_node;
rpl_ns_node_t *root_node;
rpl_ns_node_t *node;
rpl_dag_t *dag;
uip_ipaddr_t node_addr;
PRINTF("RPL: SRH creating source routing header with destination ");
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
PRINTF(" \n");
/* Construct source route. We do not do this recursively to keep the runtime stack usage constant. */
/* Get link of the destination and root */
dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
if(dag == NULL) {
PRINTF("RPL: SRH DAG not found\n");
return 0;
}
dest_node = rpl_ns_get_node(dag, &UIP_IP_BUF->destipaddr);
if(dest_node == NULL) {
/* The destination is not found, skip SRH insertion */
return 1;
}
root_node = rpl_ns_get_node(dag, &dag->dag_id);
if(root_node == NULL) {
PRINTF("RPL: SRH root node not found\n");
return 0;
}
if(!rpl_ns_is_node_reachable(dag, &UIP_IP_BUF->destipaddr)) {
PRINTF("RPL: SRH no path found to destination\n");
return 0;
}
/* Compute path length and compression factors (we use cmpri == cmpre) */
path_len = 0;
node = dest_node->parent;
/* For simplicity, we use cmpri = cmpre */
cmpri = 15;
cmpre = 15;
while(node != NULL && node != root_node) {
rpl_ns_get_node_global_addr(&node_addr, node);
/* How many bytes in common between all nodes in the path? */
cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &UIP_IP_BUF->destipaddr, 16));
cmpre = cmpri;
PRINTF("RPL: SRH Hop ");
PRINT6ADDR(&node_addr);
PRINTF("\n");
node = node->parent;
path_len++;
}
if(((DEBUG) & DEBUG_PRINT) && node != NULL) {
rpl_ns_get_node_global_addr(&node_addr, node);
PRINTF("RPL: SRH Next Hop ");
PRINT6ADDR(&node_addr);
PRINTF("\n");
}
/* Extension header length: fixed headers + (n-1) * (16-ComprI) + (16-ComprE)*/
ext_len = RPL_RH_LEN + RPL_SRH_LEN
+ (path_len - 1) * (16 - cmpre)
+ (16 - cmpri);
padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8));
ext_len += padding;
PRINTF("RPL: SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n",
path_len, cmpri, cmpre, ext_len, padding);
/* Check if there is enough space to store the extension header */
if(uip_len + ext_len > UIP_BUFSIZE) {
PRINTF("RPL: Packet too long: impossible to add source routing header (%u bytes)\n", ext_len);
return 1;
}
/* Move existing ext headers and payload uip_ext_len further */
memmove(uip_buf + uip_l2_l3_hdr_len + ext_len,
uip_buf + uip_l2_l3_hdr_len, uip_len - UIP_IPH_LEN);
memset(uip_buf + uip_l2_l3_hdr_len, 0, ext_len);
/* Insert source routing header */
UIP_RH_BUF->next = UIP_IP_BUF->proto;
UIP_IP_BUF->proto = UIP_PROTO_ROUTING;
/* Initialize IPv6 Routing Header */
UIP_RH_BUF->len = (ext_len - 8) / 8;
UIP_RH_BUF->routing_type = RPL_RH_TYPE_SRH;
UIP_RH_BUF->seg_left = path_len;
/* Initialize RPL Source Routing Header */
UIP_RPL_SRH_BUF->cmpr = (cmpri << 4) + cmpre;
UIP_RPL_SRH_BUF->pad = padding << 4;
/* Initialize addresses field (the actual source route).
* From last to first. */
node = dest_node;
hop_ptr = ((uint8_t *)UIP_RH_BUF) + ext_len - padding; /* Pointer where to write the next hop compressed address */
while(node != NULL && node->parent != root_node) {
rpl_ns_get_node_global_addr(&node_addr, node);
hop_ptr -= (16 - cmpri);
memcpy(hop_ptr, ((uint8_t*)&node_addr) + cmpri, 16 - cmpri);
node = node->parent;
}
/* The next hop (i.e. node whose parent is the root) is placed as the current IPv6 destination */
rpl_ns_get_node_global_addr(&node_addr, node);
uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &node_addr);
/* In-place update of IPv6 length field */
temp_len = UIP_IP_BUF->len[1];
UIP_IP_BUF->len[1] += ext_len;
if(UIP_IP_BUF->len[1] < temp_len) {
UIP_IP_BUF->len[0]++;
}
uip_ext_len += ext_len;
uip_len += ext_len;
return 1;
}
#else /* RPL_WITH_NON_STORING */
int insert_srh_header(void);
#endif /* RPL_WITH_NON_STORING */
/*---------------------------------------------------------------------------*/
static int
update_hbh_header(void)
{
rpl_instance_t *instance;
int uip_ext_opt_offset;
@ -212,36 +481,27 @@ rpl_update_header_empty(void)
if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
PRINTF("RPL: Hop-by-hop extension header has wrong size\n");
uip_ext_len = last_uip_ext_len;
return 0;
return 1;
}
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) {
PRINTF("RPL: Non RPL Hop-by-hop option support not implemented\n");
uip_ext_len = last_uip_ext_len;
return 0;
return 1;
}
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
PRINTF("RPL: RPL Hop-by-hop option has wrong length\n");
uip_ext_len = last_uip_ext_len;
return 0;
return 1;
}
instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
if(instance == NULL || !instance->used || !instance->current_dag->joined) {
PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n");
return 0;
return 1;
}
break;
default:
#if RPL_INSERT_HBH_OPTION
PRINTF("RPL: No hop-by-hop option found, creating it\n");
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
uip_ext_len = last_uip_ext_len;
return 0;
}
set_rpl_opt(uip_ext_opt_offset);
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
#endif
return 0;
PRINTF("RPL: No hop-by-hop option found\n");
return 1;
}
switch(UIP_EXT_HDR_OPT_BUF->type) {
@ -249,6 +509,7 @@ rpl_update_header_empty(void)
PRINTF("RPL: Updating RPL option\n");
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);
if(RPL_IS_STORING(instance)) { /* In non-storing mode, downwards traffic does not have the HBH option */
/* Check the direction of the down flag, as per Section 11.2.2.3,
which states that if a packet is going down it should in
general not go back up again. If this happens, a
@ -265,7 +526,7 @@ rpl_update_header_empty(void)
dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
}
/* Drop packet */
return 1;
return 0;
}
} else {
/* Set the down extension flag correctly as described in Section
@ -282,18 +543,64 @@ rpl_update_header_empty(void)
PRINTF("RPL option going down\n");
}
}
}
uip_ext_len = last_uip_ext_len;
return 0;
return 1;
default:
PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
uip_ext_len = last_uip_ext_len;
return 0;
return 1;
}
}
/*---------------------------------------------------------------------------*/
static int
insert_hbh_header(void)
{
int uip_ext_opt_offset;
int last_uip_ext_len;
uint8_t temp_len;
last_uip_ext_len = uip_ext_len;
uip_ext_len = 0;
uip_ext_opt_offset = 2;
/* Insert hop-by-hop header */
PRINTF("RPL: Creating hop-by-hop option\n");
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
uip_ext_len = last_uip_ext_len;
return 0;
}
/* Move existing ext headers and payload UIP_EXT_BUF further */
memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN);
/* Update IP and HBH protocol and fields */
UIP_HBHO_BUF->next = UIP_IP_BUF->proto;
UIP_IP_BUF->proto = UIP_PROTO_HBHO;
/* Initialize HBH option */
UIP_HBHO_BUF->len = (RPL_HOP_BY_HOP_LEN - 8) / 8;
UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
UIP_EXT_HDR_OPT_RPL_BUF->instance = 0;
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0;
uip_len += RPL_HOP_BY_HOP_LEN;
temp_len = UIP_IP_BUF->len[1];
UIP_IP_BUF->len[1] += UIP_HBHO_BUF->len + 8;
if(UIP_IP_BUF->len[1] < temp_len) {
UIP_IP_BUF->len[0]++;
}
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
return 1;
}
/*---------------------------------------------------------------------------*/
int
rpl_update_header_final(uip_ipaddr_t *addr)
rpl_finalize_header(uip_ipaddr_t *addr)
{
rpl_parent_t *parent;
int uip_ext_opt_offset;
@ -307,7 +614,7 @@ rpl_update_header_final(uip_ipaddr_t *addr)
if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n");
uip_ext_len = last_uip_ext_len;
return 0;
return 1;
}
if(UIP_EXT_HDR_OPT_BUF->type == UIP_EXT_HDR_OPT_RPL) {
@ -315,7 +622,7 @@ rpl_update_header_final(uip_ipaddr_t *addr)
PRINTF("RPL: Updating RPL option\n");
if(default_instance == NULL || !default_instance->used || !default_instance->current_dag->joined) {
PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect default instance\n");
return 1;
return 0;
}
parent = rpl_find_parent(default_instance->current_dag, addr);
if(parent == NULL || parent != parent->dag->preferred_parent) {
@ -326,78 +633,101 @@ rpl_update_header_final(uip_ipaddr_t *addr)
}
}
}
return 0;
return 1;
}
/*---------------------------------------------------------------------------*/
void
rpl_remove_header(void)
{
uint8_t temp_len;
uint8_t rpl_ext_hdr_len;
uint8_t *uip_next_hdr;
uip_ext_len = 0;
uip_next_hdr = &UIP_IP_BUF->proto;
PRINTF("RPL: Verifying the presence of the RPL header option\n");
switch(UIP_IP_BUF->proto){
PRINTF("RPL: Verifying the presence of RPL extension headers\n");
/* Look for hop-by-hop and routing headers */
while(uip_next_hdr != NULL) {
switch(*uip_next_hdr) {
case UIP_PROTO_TCP:
case UIP_PROTO_UDP:
case UIP_PROTO_ICMP6:
case UIP_PROTO_NONE:
return;
case UIP_PROTO_HBHO:
PRINTF("RPL: Removing the RPL header option\n");
UIP_IP_BUF->proto = UIP_HBHO_BUF->next;
case UIP_PROTO_ROUTING:
/* Remove hop-by-hop and routing headers */
*uip_next_hdr = UIP_EXT_BUF->next;
rpl_ext_hdr_len = (UIP_EXT_BUF->len * 8) + 8;
temp_len = UIP_IP_BUF->len[1];
uip_len -= UIP_HBHO_BUF->len + 8;
UIP_IP_BUF->len[1] -= UIP_HBHO_BUF->len + 8;
uip_len -= rpl_ext_hdr_len;
UIP_IP_BUF->len[1] -= rpl_ext_hdr_len;
if(UIP_IP_BUF->len[1] > temp_len) {
UIP_IP_BUF->len[0]--;
}
memmove(UIP_EXT_BUF, UIP_HBHO_NEXT_BUF, uip_len - UIP_IPH_LEN);
PRINTF("RPL: Removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len);
memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN);
break;
default:
PRINTF("RPL: No hop-by-hop Option found\n");
/* Move to next header */
if(uip_next_hdr != &UIP_IP_BUF->proto) {
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
}
}
/*---------------------------------------------------------------------------*/
uint8_t
rpl_invert_header(void)
{
uint8_t uip_ext_opt_offset;
uint8_t last_uip_ext_len;
last_uip_ext_len = uip_ext_len;
uip_ext_len = 0;
uip_ext_opt_offset = 2;
PRINTF("RPL: Verifying the presence of the RPL header option\n");
switch(UIP_IP_BUF->proto) {
case UIP_PROTO_HBHO:
uip_next_hdr = &UIP_EXT_BUF->next;
break;
default:
PRINTF("RPL: No hop-by-hop Option found\n");
uip_ext_len = last_uip_ext_len;
return 0;
}
switch (UIP_EXT_HDR_OPT_BUF->type) {
case UIP_EXT_HDR_OPT_RPL:
PRINTF("RPL: Updating RPL option (switching direction)\n");
UIP_EXT_HDR_OPT_RPL_BUF->flags &= RPL_HDR_OPT_DOWN;
UIP_EXT_HDR_OPT_RPL_BUF->flags ^= RPL_HDR_OPT_DOWN;
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance)->current_dag->rank);
uip_ext_len = last_uip_ext_len;
return RPL_HOP_BY_HOP_LEN;
default:
PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
uip_ext_len = last_uip_ext_len;
return 0;
}
}
/*---------------------------------------------------------------------------*/
void
rpl_insert_header(void)
{
#if RPL_INSERT_HBH_OPTION
if(default_instance != NULL && !uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
rpl_update_header_empty();
if(default_instance == NULL) {
return;
}
if(RPL_IS_STORING(default_instance)) {
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
insert_hbh_header();
}
}
if(RPL_IS_NON_STORING(default_instance)) {
if(default_instance->current_dag != NULL) {
if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
insert_srh_header();
} else {
insert_hbh_header();
}
}
}
#endif
}
/*---------------------------------------------------------------------------*/
int
rpl_update_header(void)
{
if(default_instance == NULL) {
return 0;
}
if(default_instance->current_dag != NULL) {
if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
/* At the root, remove headers if any, and insert SRH or HBH
* (SRH is inserted only if the destination is in the DODAG) */
rpl_remove_header();
if(RPL_IS_NON_STORING(default_instance)) {
return insert_srh_header();
} else {
return insert_hbh_header();
}
} else {
return update_hbh_header();
}
} else {
return 0;
}
}
/** @}*/

View file

@ -51,6 +51,7 @@
#include "net/ipv6/uip-nd6.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "net/packetbuf.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#include "random.h"
@ -119,6 +120,7 @@ find_route_entry_by_dao_ack(uint8_t seq)
}
#endif /* RPL_WITH_DAO_ACK */
#if RPL_WITH_STORING
/* prepare for forwarding of DAO */
static uint8_t
prepare_for_dao_fwd(uint8_t sequence, uip_ds6_route_t *rep)
@ -132,6 +134,7 @@ prepare_for_dao_fwd(uint8_t sequence, uip_ds6_route_t *rep)
RPL_ROUTE_SET_DAO_PENDING(rep);
return dao_sequence;
}
#endif /* RPL_WITH_STORING */
/*---------------------------------------------------------------------------*/
static int
get_global_addr(uip_ipaddr_t *addr)
@ -626,8 +629,9 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
}
/*---------------------------------------------------------------------------*/
static void
dao_input(void)
dao_input_storing(void)
{
#if RPL_WITH_STORING
uip_ipaddr_t dao_sender_addr;
rpl_dag_t *dag;
rpl_instance_t *instance;
@ -665,11 +669,6 @@ dao_input(void)
instance_id = buffer[pos++];
instance = rpl_get_instance(instance_id);
if(instance == NULL) {
PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
instance_id);
goto discard;
}
lifetime = instance->default_lifetime;
@ -685,7 +684,7 @@ dao_input(void)
if(flags & RPL_DAO_D_FLAG) {
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
goto discard;
return;
}
pos += 16;
}
@ -710,7 +709,7 @@ dao_input(void)
DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
parent->rank = INFINITE_RANK;
parent->flags |= RPL_PARENT_FLAG_UPDATED;
goto discard;
return;
}
/* If we get the DAO from our parent, we also have a loop. */
@ -718,7 +717,7 @@ dao_input(void)
PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n");
parent->rank = INFINITE_RANK;
parent->flags |= RPL_PARENT_FLAG_UPDATED;
goto discard;
return;
}
}
@ -805,7 +804,7 @@ dao_input(void)
dao_ack_output(instance, &dao_sender_addr, sequence,
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
goto discard;
return;
}
PRINTF("RPL: Adding DAO route\n");
@ -823,7 +822,7 @@ dao_input(void)
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
}
goto discard;
return;
}
rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
@ -836,7 +835,7 @@ dao_input(void)
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
}
goto discard;
return;
}
/* set lifetime and clear NOPATH bit */
@ -892,6 +891,141 @@ fwd_dao:
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
}
#endif /* RPL_WITH_STORING */
}
/*---------------------------------------------------------------------------*/
static void
dao_input_nonstoring(void)
{
#if RPL_WITH_NON_STORING
uip_ipaddr_t dao_sender_addr;
uip_ipaddr_t dao_parent_addr;
rpl_dag_t *dag;
rpl_instance_t *instance;
unsigned char *buffer;
uint16_t sequence;
uint8_t instance_id;
uint8_t lifetime;
uint8_t prefixlen;
uint8_t flags;
uint8_t subopt_type;
uip_ipaddr_t prefix;
uint8_t buffer_length;
int pos;
int len;
int i;
prefixlen = 0;
uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
memset(&dao_parent_addr, 0, 16);
buffer = UIP_ICMP_PAYLOAD;
buffer_length = uip_len - uip_l3_icmp_hdr_len;
pos = 0;
instance_id = buffer[pos++];
instance = rpl_get_instance(instance_id);
lifetime = instance->default_lifetime;
flags = buffer[pos++];
/* reserved */
pos++;
sequence = buffer[pos++];
dag = instance->current_dag;
/* Is the DAG ID present? */
if(flags & RPL_DAO_D_FLAG) {
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
return;
}
pos += 16;
}
/* Check if there are any RPL options present. */
for(i = pos; i < buffer_length; i += len) {
subopt_type = buffer[i];
if(subopt_type == RPL_OPTION_PAD1) {
len = 1;
} else {
/* The option consists of a two-byte header and a payload. */
len = 2 + buffer[i + 1];
}
switch(subopt_type) {
case RPL_OPTION_TARGET:
/* Handle the target option. */
prefixlen = buffer[i + 3];
memset(&prefix, 0, sizeof(prefix));
memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
break;
case RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
/* pathcontrol = buffer[i + 3];
pathsequence = buffer[i + 4];*/
lifetime = buffer[i + 5];
if(len >= 20) {
memcpy(&dao_parent_addr, buffer + i + 6, 16);
}
break;
}
}
PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
(unsigned)lifetime, (unsigned)prefixlen);
PRINT6ADDR(&prefix);
PRINTF(", parent: ");
PRINT6ADDR(&dao_parent_addr);
PRINTF(" \n");
if(lifetime == RPL_ZERO_LIFETIME) {
PRINTF("RPL: No-Path DAO received\n");
rpl_ns_expire_parent(dag, &prefix, &dao_parent_addr);
} else {
if(rpl_ns_update_node(dag, &prefix, &dao_parent_addr, RPL_LIFETIME(instance, lifetime)) == NULL) {
PRINTF("RPL: failed to add link\n");
return;
}
}
if(flags & RPL_DAO_K_FLAG) {
PRINTF("RPL: Sending DAO ACK\n");
uip_clear_buf();
dao_ack_output(instance, &dao_sender_addr, sequence,
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
#endif /* RPL_WITH_NON_STORING */
}
/*---------------------------------------------------------------------------*/
static void
dao_input(void)
{
rpl_instance_t *instance;
uint8_t instance_id;
/* Destination Advertisement Object */
PRINTF("RPL: Received a DAO from ");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
instance_id = UIP_ICMP_PAYLOAD[0];
instance = rpl_get_instance(instance_id);
if(instance == NULL) {
PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
instance_id);
goto discard;
}
if(instance->mop != RPL_MOP_NON_STORING) {
if(RPL_IS_STORING(instance)) {
dao_input_storing();
}
} else {
if(RPL_IS_NON_STORING(instance)) {
dao_input_nonstoring();
}
}
discard:
uip_clear_buf();
@ -1006,6 +1140,8 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
unsigned char *buffer;
uint8_t prefixlen;
int pos;
uip_ipaddr_t *parent_ipaddr = NULL;
uip_ipaddr_t *dest_ipaddr = NULL;
/* Destination Advertisement Object */
@ -1019,6 +1155,12 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
return;
}
parent_ipaddr = rpl_get_parent_ipaddr(parent);
if(parent_ipaddr == NULL) {
PRINTF("RPL dao_output_target error parent IP address NULL\n");
return;
}
dag = parent->dag;
if(dag == NULL) {
PRINTF("RPL dao_output_target error dag NULL\n");
@ -1071,21 +1213,37 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
/* Create a transit information sub-option. */
buffer[pos++] = RPL_OPTION_TRANSIT;
buffer[pos++] = 4;
buffer[pos++] = (instance->mop != RPL_MOP_NON_STORING) ? 4 : 20;
buffer[pos++] = 0; /* flags - ignored */
buffer[pos++] = 0; /* path control - ignored */
buffer[pos++] = 0; /* path seq - ignored */
buffer[pos++] = lifetime;
if(instance->mop != RPL_MOP_NON_STORING) {
/* Send DAO to parent */
dest_ipaddr = parent_ipaddr;
} else {
/* Include parent global IP address */
memcpy(buffer + pos, &parent->dag->dag_id, 8); /* Prefix */
pos += 8;
memcpy(buffer + pos, ((const unsigned char *)parent_ipaddr) + 8, 8); /* Interface identifier */
pos += 8;
/* Send DAO to root */
dest_ipaddr = &parent->dag->dag_id;
}
PRINTF("RPL: Sending a %sDAO with sequence number %u, lifetime %u, prefix ",
lifetime == RPL_ZERO_LIFETIME ? "No-Path " : "", seq_no, lifetime);
PRINT6ADDR(prefix);
PRINTF(" to ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINT6ADDR(dest_ipaddr);
PRINTF(" , parent ");
PRINT6ADDR(parent_ipaddr);
PRINTF("\n");
if(rpl_get_parent_ipaddr(parent) != NULL) {
uip_icmp6_send(rpl_get_parent_ipaddr(parent), ICMP6_RPL, RPL_CODE_DAO, pos);
if(dest_ipaddr != NULL) {
uip_icmp6_send(dest_ipaddr, ICMP6_RPL, RPL_CODE_DAO, pos);
}
}
/*---------------------------------------------------------------------------*/

211
core/net/rpl/rpl-ns.c Normal file
View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2016, Inria.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
/**
* \file
* RPL non-storing mode specific functions. Includes support for
* source routing.
*
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#include "net/rpl/rpl-conf.h"
#include "net/ip/uip.h"
#include "net/ip/tcpip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "lib/list.h"
#include "lib/memb.h"
#if RPL_WITH_NON_STORING
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
#include <limits.h>
#include <string.h>
/* Total number of nodes */
static int num_nodes;
/* Every known node in the network */
LIST(nodelist);
MEMB(nodememb, rpl_ns_node_t, RPL_NS_LINK_NUM);
/*---------------------------------------------------------------------------*/
int
rpl_ns_num_nodes()
{
return num_nodes;
}
/*---------------------------------------------------------------------------*/
static int
node_matches_address(const rpl_dag_t *dag, const rpl_ns_node_t *node, const uip_ipaddr_t *addr)
{
return addr != NULL
&& node != NULL
&& dag != NULL
&& dag == node->dag
&& !memcmp(addr, &node->dag->dag_id, 8)
&& !memcmp(((const unsigned char *)addr) + 8, node->link_identifier, 8);
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *
rpl_ns_get_node(const rpl_dag_t *dag, const uip_ipaddr_t *addr)
{
rpl_ns_node_t *l;
for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
/* Compare prefix and node identifier */
if(node_matches_address(dag, l, addr)) {
return l;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
int
rpl_ns_is_node_reachable(const rpl_dag_t *dag, const uip_ipaddr_t *addr)
{
int max_depth = RPL_NS_LINK_NUM;
rpl_ns_node_t *node = rpl_ns_get_node(dag, addr);
rpl_ns_node_t *root_node = rpl_ns_get_node(dag, dag != NULL ? &dag->dag_id : NULL);
while(node != NULL && node != root_node && max_depth > 0) {
node = node->parent;
max_depth--;
}
return node != NULL && node == root_node;
}
/*---------------------------------------------------------------------------*/
void
rpl_ns_expire_parent(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent)
{
rpl_ns_node_t *l = rpl_ns_get_node(dag, child);
/* Check if parent matches */
if(l != NULL && node_matches_address(dag, l->parent, parent)) {
l->lifetime = RPL_NOPATH_REMOVAL_DELAY;
}
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *
rpl_ns_update_node(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime)
{
rpl_ns_node_t *child_node = rpl_ns_get_node(dag, child);
rpl_ns_node_t *parent_node = rpl_ns_get_node(dag, parent);
if(parent != NULL) {
/* No node for the parent, add one with infinite lifetime */
if(parent_node == NULL) {
parent_node = rpl_ns_update_node(dag, parent, NULL, 0xffffffff);
if(parent_node == NULL) {
return NULL;
}
}
}
/* No node for this child, add one */
if(child_node == NULL) {
child_node = memb_alloc(&nodememb);
/* No space left, abort */
if(child_node == NULL) {
return NULL;
}
list_add(nodelist, child_node);
num_nodes++;
}
/* Initialize node */
child_node->dag = dag;
child_node->lifetime = lifetime;
child_node->parent = parent_node;
memcpy(child_node->link_identifier, ((const unsigned char *)child) + 8, 8);
return child_node;
}
/*---------------------------------------------------------------------------*/
void
rpl_ns_init()
{
num_nodes = 0;
memb_init(&nodememb);
list_init(nodelist);
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *rpl_ns_node_head()
{
return list_head(nodelist);
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *rpl_ns_node_next(rpl_ns_node_t *item)
{
return list_item_next(item);
}
/*---------------------------------------------------------------------------*/
void
rpl_ns_get_node_global_addr(uip_ipaddr_t *addr, rpl_ns_node_t *node)
{
if(addr != NULL && node != NULL && node->dag != NULL) {
memcpy(addr, &node->dag->dag_id, 8);
memcpy(((unsigned char *)addr) + 8, &node->link_identifier, 8);
}
}
/*---------------------------------------------------------------------------*/
void
rpl_ns_periodic()
{
rpl_ns_node_t *l;
/* First pass, decrement lifetime for all nodes with non-infinite lifetime */
for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
/* Don't touch infinite lifetime nodes */
if(l->lifetime != 0xffffffff && l->lifetime > 0) {
l->lifetime--;
}
}
/* Second pass, for all expire nodes, deallocate them iff no child points to them */
for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
if(l->lifetime == 0) {
rpl_ns_node_t *l2;
for(l2 = list_head(nodelist); l2 != NULL; l2 = list_item_next(l2)) {
if(l2->parent == l) {
break;
}
}
/* No child found, deallocate node */
list_remove(nodelist, l);
memb_free(&nodememb, l);
num_nodes--;
}
}
}
#endif /* RPL_WITH_NON_STORING */

72
core/net/rpl/rpl-ns.h Normal file
View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2016, Inria.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
/**
* \file
* RPL non-storing mode specific functions. Includes support for
* source routing.
*
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#ifndef RPL_NS_H
#define RPL_NS_H
#include "rpl-conf.h"
#ifdef RPL_NS_CONF_LINK_NUM
#define RPL_NS_LINK_NUM RPL_NS_CONF_LINK_NUM
#else /* RPL_NS_CONF_LINK_NUM */
#define RPL_NS_LINK_NUM 32
#endif /* RPL_NS_CONF_LINK_NUM */
typedef struct rpl_ns_node {
struct rpl_ns_node *next;
uint32_t lifetime;
rpl_dag_t *dag;
/* Store only IPv6 link identifiers as all nodes in the DAG share the same prefix */
unsigned char link_identifier[8];
struct rpl_ns_node *parent;
} rpl_ns_node_t;
int rpl_ns_num_nodes();
void rpl_ns_expire_parent(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent);
rpl_ns_node_t *rpl_ns_update_node(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime);
void rpl_ns_init();
rpl_ns_node_t *rpl_ns_node_head();
rpl_ns_node_t *rpl_ns_node_next(rpl_ns_node_t *item);
rpl_ns_node_t *rpl_ns_get_node(const rpl_dag_t *dag, const uip_ipaddr_t *addr);
int rpl_ns_is_node_reachable(const rpl_dag_t *dag, const uip_ipaddr_t *addr);
void rpl_ns_get_node_global_addr(uip_ipaddr_t *addr, rpl_ns_node_t *node);
void rpl_ns_periodic();
#endif /* RPL_NS_H */

View file

@ -102,6 +102,9 @@
/* RPL IPv6 extension header option. */
#define RPL_HDR_OPT_LEN 4
#define RPL_HOP_BY_HOP_LEN (RPL_HDR_OPT_LEN + 2 + 2)
#define RPL_RH_LEN 4
#define RPL_SRH_LEN 4
#define RPL_RH_TYPE_SRH 3
#define RPL_HDR_OPT_DOWN 0x80
#define RPL_HDR_OPT_DOWN_SHIFT 7
#define RPL_HDR_OPT_RANK_ERR 0x40

View file

@ -43,6 +43,7 @@
#include "contiki-conf.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "net/link-stats.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#include "lib/random.h"
@ -80,14 +81,21 @@ static uint8_t dio_send_ok;
static void
handle_periodic_timer(void *ptr)
{
rpl_dag_t *dag = rpl_get_any_dag();
rpl_purge_dags();
if(dag != NULL && RPL_IS_STORING(dag->instance)) {
rpl_purge_routes();
}
if(dag != NULL && RPL_IS_NON_STORING(dag->instance)) {
rpl_ns_periodic();
}
rpl_recalculate_ranks();
/* handle DIS */
#if RPL_DIS_SEND
next_dis++;
if(rpl_get_any_dag() == NULL && next_dis >= RPL_DIS_INTERVAL) {
if(dag == NULL && next_dis >= RPL_DIS_INTERVAL) {
next_dis = 0;
dis_output(NULL);
}

View file

@ -47,6 +47,7 @@
#include "net/ipv6/uip-ds6.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#define DEBUG DEBUG_NONE
@ -344,6 +345,10 @@ rpl_init(void)
#if RPL_CONF_STATS
memset(&rpl_stats, 0, sizeof(rpl_stats));
#endif
#if RPL_WITH_NON_STORING
rpl_ns_init();
#endif /* RPL_WITH_NON_STORING */
}
/*---------------------------------------------------------------------------*/

View file

@ -271,14 +271,14 @@ rpl_dag_t *rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id);
int rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len);
int rpl_repair_root(uint8_t instance_id);
int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from);
rpl_dag_t *rpl_get_dag(const uip_ipaddr_t *addr);
rpl_dag_t *rpl_get_any_dag(void);
rpl_instance_t *rpl_get_instance(uint8_t instance_id);
int rpl_update_header_empty(void);
int rpl_update_header_final(uip_ipaddr_t *addr);
int rpl_verify_header(int);
int rpl_update_header(void);
int rpl_finalize_header(uip_ipaddr_t *addr);
int rpl_verify_hbh_header(int);
void rpl_insert_header(void);
void rpl_remove_header(void);
uint8_t rpl_invert_header(void);
const struct link_stats *rpl_get_parent_link_stats(rpl_parent_t *p);
int rpl_parent_is_fresh(rpl_parent_t *p);
int rpl_parent_is_reachable(rpl_parent_t *p);
@ -291,6 +291,8 @@ rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr);
void rpl_dag_init(void);
uip_ds6_nbr_t *rpl_get_nbr(rpl_parent_t *parent);
void rpl_print_neighbor_list(void);
int rpl_process_srh_header(void);
int rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr);
/* Per-parent RPL information */
NBR_TABLE_DECLARE(rpl_parents);