Added RPL-lite, a lightweight implementation of RPL. This is the new default.

This commit is contained in:
Simon Duquennoy 2017-06-10 14:35:39 +02:00
parent ebd0196539
commit a6643a9835
145 changed files with 11754 additions and 7731 deletions

View File

@ -99,6 +99,7 @@ env:
- BUILD_TYPE='compile-nxp-ports' BUILD_CATEGORY='compile' BUILD_ARCH='jn516x'
- BUILD_TYPE='compile-nrf52-ports' BUILD_CATEGORY='compile' BUILD_ARCH='nrf52dk'
- BUILD_TYPE='compile-tools' BUILD_CATEGORY='compile'
- BUILD_TYPE='rpl-lite' BUILD_CATEGORY='sim'
- BUILD_TYPE='rpl' BUILD_CATEGORY='sim'
- BUILD_TYPE='ipv6' BUILD_CATEGORY='sim'
- BUILD_TYPE='base' BUILD_CATEGORY='sim'

View File

@ -80,15 +80,19 @@ endif
ifeq ($(CONTIKI_WITH_IPV6),1)
CFLAGS += -DNETSTACK_CONF_WITH_IPV6=1
ifneq ($(CONTIKI_WITH_RPL),0)
CONTIKI_WITH_RPL = 1
endif
CONTIKI_WITH_RPL ?= 1
CONTIKI_WITH_RPL_LITE ?= 1
MODULES += core/net/ipv6 core/net/ip
endif
ifeq ($(CONTIKI_WITH_RPL),1)
CFLAGS += -DUIP_CONF_IPV6_RPL=1
MODULES += core/net/rpl
ifeq ($(CONTIKI_WITH_RPL_LITE),1)
CFLAGS += -DUIP_CONF_IPV6_RPL_LITE=1
MODULES += core/net/rpl-lite
else
MODULES += core/net/rpl
endif
else
CFLAGS += -DUIP_CONF_IPV6_RPL=0
endif
@ -96,7 +100,7 @@ endif
CONTIKI_SOURCEFILES += $(CONTIKIFILES)
CONTIKIDIRS += ${addprefix $(CONTIKI)/core/,dev lib net net/mac \
net/rpl sys cfs . }
sys cfs . }
oname = ${patsubst %.c,%.o,${patsubst %.S,%.o,$(1)}}

View File

@ -48,7 +48,6 @@
#include "sys/ctimer.h"
#include "sys/etimer.h"
#include "sys/pt.h"
#include "net/rpl/rpl.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "dev/leds.h"

View File

@ -89,7 +89,6 @@
#include "lib/random.h"
#include "sys/ctimer.h"
#include "sys/etimer.h"
#include "net/rpl/rpl.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "dev/leds.h"

View File

@ -59,7 +59,7 @@
#include <inttypes.h>
#if UIP_CONF_IPV6_RPL
#include "net/rpl/rpl.h"
#include "rpl.h"
#endif /* UIP_CONF_IPV6_RPL */
#define DEBUG DEBUG_NONE

View File

@ -44,15 +44,17 @@
#include "orchestra.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/packetbuf.h"
#include "net/rpl/rpl-conf.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
/*
* The body of this rule should be compiled only when "nbr_routes" is available,
* otherwise a link error causes build failure. "nbr_routes" is compiled if
* UIP_CONF_MAX_ROUTES != 0. See uip-ds6-route.c.
* UIP_MAX_ROUTES != 0. See uip-ds6-route.c.
*/
#if UIP_CONF_MAX_ROUTES != 0
#if UIP_MAX_ROUTES != 0
#if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH
#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < (ORCHESTRA_MAX_HASH + 1)) ? LINK_OPTION_SHARED : 0)

View File

@ -40,7 +40,10 @@
#include "orchestra.h"
#include "net/packetbuf.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"

View File

@ -390,13 +390,6 @@ typedef uint32_t rtimer_clock_t;
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#define UIP_CONF_ND6_RETRANS_TIMER 10000
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 20
#endif
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 20
#endif
/* uIP */
#ifndef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 1300

View File

@ -89,16 +89,13 @@
#define UIP_CONF_ROUTER 1
/* configure number of neighbors and routes */
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 300
#endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 300
#endif /* UIP_CONF_MAX_ROUTES */
#ifndef RPL_NS_CONF_LINK_NUM
#define RPL_NS_CONF_LINK_NUM 300
#endif /* RPL_NS_CONF_LINK_NUM */
/* configure network size and density */
#ifndef CONTIKI_NETWORK_SIZE
#define CONTIKI_NETWORK_SIZE 300
#endif /* CONTIKI_NETWORK_SIZE */
#ifndef CONTIKI_NETWORK_DENSITY
#define CONTIKI_NETWORK_DENSITY 300
#endif /* CONTIKI_NETWORK_DENSITY */
#define TCPIP_CONF_ANNOTATE_TRANSMISSIONS 1

View File

@ -110,14 +110,6 @@
#define UIP_CONF_IPV6_RPL 1
#endif /* UIP_CONF_IPV6_RPL */
/* configure number of neighbors and routes */
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 20
#endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 20
#endif /* UIP_CONF_MAX_ROUTES */
#define UIP_CONF_ND6_SEND_RA 0
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#define UIP_CONF_ND6_RETRANS_TIMER 10000

View File

@ -104,14 +104,6 @@ typedef unsigned short uip_stats_t;
#define UIP_CONF_NETIF_MAX_ADDRESSES 3
#define UIP_CONF_ICMP6 1
/* configure number of neighbors and routes */
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 30
#endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 30
#endif /* UIP_CONF_MAX_ROUTES */
#define UIP_CONF_ND6_SEND_RA 0
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#define UIP_CONF_ND6_RETRANS_TIMER 10000

View File

@ -114,14 +114,6 @@
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#define UIP_CONF_ND6_RETRANS_TIMER 10000
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 20
#endif
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 20
#endif
#ifndef UIP_CONF_TCP
#define UIP_CONF_TCP 1
#endif

View File

@ -447,13 +447,6 @@ typedef uint32_t rtimer_clock_t;
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#define UIP_CONF_ND6_RETRANS_TIMER 10000
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 20
#endif
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 20
#endif
/* uIP */
#ifndef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 1300

View File

@ -76,14 +76,6 @@
#define UIP_CONF_ROUTER 1
/* configure number of neighbors and routes */
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 16
#endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 16
#endif /* UIP_CONF_MAX_ROUTES */
#define UIP_CONF_ND6_SEND_RA 0
#define UIP_CONF_ND6_SEND_NS 0
#define UIP_CONF_ND6_REACHABLE_TIME 600000

View File

@ -196,13 +196,6 @@
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#define UIP_CONF_ND6_RETRANS_TIMER 10000
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 20
#endif
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 20
#endif
#ifndef UIP_CONF_TCP
#define UIP_CONF_TCP 1
#endif

View File

@ -478,13 +478,6 @@ typedef uint32_t rtimer_clock_t;
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#define UIP_CONF_ND6_RETRANS_TIMER 10000
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 16
#endif
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 16
#endif
/* uIP */
#ifndef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 1300

View File

@ -90,6 +90,18 @@
* project-specific configuration to save memory.
*/
/* CONTIKI_NETWORK_DENSITY specifies the maximum number of neighbors
* a node will have to handle. Used to set NBR_TABLE_MAX_NEIGHBORS. */
#ifndef CONTIKI_NETWORK_DENSITY
#define CONTIKI_NETWORK_DENSITY 16
#endif /* CONTIKI_NETWORK_DENSITY */
/* CONTIKI_NETWORK_SIZE specifies the maximum number of nodes in
* a network. Used to set UIP_MAX_ROUTES or RPL_NS_LINK_NUM. */
#ifndef CONTIKI_NETWORK_SIZE
#define CONTIKI_NETWORK_SIZE 16
#endif /* CONTIKI_NETWORK_SIZE */
/* NETSTACK_CONF_WITH_IPV6 specifies whether or not IPv6 should be used. If IPv6
is not used, IPv4 is used instead. */
#ifndef NETSTACK_CONF_WITH_IPV6
@ -122,18 +134,6 @@
#endif /* NBR_TABLE_FIND_REMOVABLE */
#endif /* UIP_CONF_IPV6_RPL */
/* UIP_CONF_MAX_ROUTES specifies the maximum number of routes that each
node will be able to handle. */
#ifndef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 20
#endif /* UIP_CONF_MAX_ROUTES */
/* RPL_NS_CONF_LINK_NUM specifies the maximum number of links a RPL root
* will maintain in non-storing mode. */
#ifndef RPL_NS_CONF_LINK_NUM
#define RPL_NS_CONF_LINK_NUM 20
#endif /* RPL_NS_CONF_LINK_NUM */
/* UIP_CONF_UDP specifies if UDP support should be included or
not. Disabling UDP saves memory but breaks a lot of stuff. */
#ifndef UIP_CONF_UDP
@ -158,12 +158,6 @@
#define UIP_CONF_MAX_CONNECTIONS 8
#endif /* UIP_CONF_MAX_CONNECTIONS */
/* NBR_TABLE_CONF_MAX_NEIGHBORS specifies the maximum number of neighbors
that each node will be able to handle. */
#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 8
#endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */
/* UIP_CONF_ND6_SEND_RA enables standard IPv6 Router Advertisement.
* We enable it by default when IPv6 is used without RPL. */
#ifndef UIP_CONF_ND6_SEND_RA

View File

@ -45,8 +45,10 @@
#include "net/ipv6/uip-ds6.h"
#if UIP_CONF_IPV6_RPL
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#endif
#include <string.h>
@ -65,7 +67,7 @@ extern struct uip_fallback_interface UIP_FALLBACK_INTERFACE;
#endif
#if UIP_CONF_IPV6_RPL
#include "rpl/rpl.h"
#include "rpl.h"
#endif
process_event_t tcpip_event;
@ -103,7 +105,7 @@ enum {
};
#if UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING
#define NEXTHOP_NON_STORING(addr) rpl_srh_get_next_hop(addr)
#define NEXTHOP_NON_STORING(addr) rpl_ext_header_srh_get_next_hop(addr)
#else
#define NEXTHOP_NON_STORING(addr) 0
#endif
@ -464,28 +466,24 @@ output_fallback(void)
return;
}
#else
LOG_ERR("output: Destination off-link but no route\n");
LOG_ERR("output: destination off-link and no default route\n");
#endif /* !UIP_FALLBACK_INTERFACE */
}
/*---------------------------------------------------------------------------*/
static void
drop_route(uip_ds6_route_t *route)
{
#if UIP_CONF_IPV6_RPL
rpl_dag_t *dag;
rpl_instance_t *instance;
#if UIP_CONF_IPV6_RPL && (UIP_CONF_IPV6_RPL_LITE == 0)
/* If we are running RPL, and if we are the root of the
network, we'll trigger a global repair before we remove
the route. */
rpl_dag_t *dag;
dag = (rpl_dag_t *)route->state.dag;
if(dag != NULL) {
instance = dag->instance;
rpl_repair_root(instance->instance_id);
if(dag != NULL && dag->instance != NULL) {
rpl_repair_root(dag->instance->instance_id);
}
#endif /* UIP_CONF_IPV6_RPL */
#endif /* UIP_CONF_IPV6_RPL && (UIP_CONF_IPV6_RPL_LITE == 0) */
uip_ds6_route_rm(route);
}
/*---------------------------------------------------------------------------*/
@ -511,14 +509,22 @@ get_nexthop(uip_ipaddr_t *addr)
uip_ipaddr_t *nexthop;
uip_ds6_route_t *route;
LOG_INFO("tcpip_ipv6_output: looking for next hop for host ");
LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
LOG_INFO("\n");
if(NEXTHOP_NON_STORING(addr)) {
LOG_INFO("tcpip_ipv6_output: selected next hop from SRH: ");
LOG_INFO_6ADDR(nexthop);
LOG_INFO("\n");
return addr;
}
/* 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(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)) {
LOG_INFO("tcpip_ipv6_output: destination is on link\n");
return &UIP_IP_BUF->destipaddr;
}
@ -527,13 +533,18 @@ get_nexthop(uip_ipaddr_t *addr)
/* No route was found - we send to the default route instead. */
if(route == NULL) {
LOG_INFO("output: no route found, using default route\n");
LOG_INFO("tcpip_ipv6_output: no route found, using default route: ");
LOG_INFO_6ADDR(nexthop);
LOG_INFO("\n");
nexthop = uip_ds6_defrt_choose();
if(nexthop == NULL) {
output_fallback();
}
} else {
LOG_INFO("tcpip_ipv6_output: found next hop from routing table: ");
LOG_INFO_6ADDR(nexthop);
LOG_INFO("\n");
/* A route was found, so we look up the nexthop neighbor for
the route. */
nexthop = uip_ds6_route_nexthop(route);
@ -614,7 +625,9 @@ send_nd6_ns(uip_ipaddr_t *nexthop)
/* Send the first NS try from here (multicast destination IP address). */
}
#else
LOG_ERR("output: neighbor not in cache\n");
LOG_ERR("tcpip_ipv6_output: neighbor not in cache: ");
LOG_ERR_6ADDR(nexthop);
LOG_ERR("\n");
#endif
return err;
@ -643,7 +656,7 @@ tcpip_ipv6_output(void)
}
#if UIP_CONF_IPV6_RPL
if(!rpl_update_header()) {
if(!rpl_ext_header_update()) {
/* Packet can not be forwarded */
LOG_ERR("output: RPL header update error\n");
uip_clear_buf();

View File

@ -46,7 +46,7 @@
#include "net/ipv6/multicast/uip-mcast6-route.h"
#include "net/ipv6/multicast/uip-mcast6-stats.h"
#include "net/ipv6/multicast/esmrf.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "net/ip/uip.h"
#include "net/netstack.h"
#include "net/packetbuf.h"
@ -282,7 +282,7 @@ in()
}
/* Retrieve our preferred parent's LL address */
parent_ipaddr = rpl_get_parent_ipaddr(d->preferred_parent);
parent_ipaddr = rpl_parent_get_ipaddr(d->preferred_parent);
parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr);
if(parent_lladdr == NULL) {

View File

@ -47,7 +47,7 @@
#include "net/ipv6/multicast/uip-mcast6-route.h"
#include "net/ipv6/multicast/uip-mcast6-stats.h"
#include "net/ipv6/multicast/smrf.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "net/netstack.h"
#include "net/packetbuf.h"
#include <string.h>
@ -107,7 +107,7 @@ in()
}
/* Retrieve our preferred parent's LL address */
parent_ipaddr = rpl_get_parent_ipaddr(d->preferred_parent);
parent_ipaddr = rpl_parent_get_ipaddr(d->preferred_parent);
parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr);
if(parent_lladdr == NULL) {

View File

@ -39,6 +39,7 @@
* Routing table manipulation
*/
#include "net/ipv6/uip-ds6.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/ip/uip.h"
#include "lib/list.h"
@ -60,7 +61,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)
#if (UIP_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
@ -78,7 +79,7 @@ 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) */
#endif /* (UIP_MAX_ROUTES != 0) */
/* Default routes are held on the defaultrouterlist and their
structures are allocated from the defaultroutermemb memory block.*/
@ -109,12 +110,14 @@ assert_nbr_routes_list_sane(void)
printf("uip-ds6-route.c: assert_nbr_routes_list_sane route list is in infinite loop\n");
}
#if (UIP_MAX_ROUTES != 0)
/* Make sure that the route list has as many entries as the
num_routes vairable. */
if(count < num_routes) {
printf("uip-ds6-route.c: assert_nbr_routes_list_sane too few entries on route list: should be %d, is %d, max %d\n",
num_routes, count, UIP_CONF_MAX_ROUTES);
num_routes, count, UIP_MAX_ROUTES);
}
#endif /* (UIP_MAX_ROUTES != 0) */
}
#endif /* LOG_DBG_ENABLED */
/*---------------------------------------------------------------------------*/
@ -158,12 +161,12 @@ uip_ds6_notification_rm(struct uip_ds6_notification *n)
void
uip_ds6_route_init(void)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_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) */
#endif /* (UIP_MAX_ROUTES != 0) */
memb_init(&defaultroutermemb);
list_init(defaultrouterlist);
@ -172,7 +175,7 @@ uip_ds6_route_init(void)
list_init(notificationlist);
#endif
}
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
/*---------------------------------------------------------------------------*/
static uip_lladdr_t *
uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
@ -184,48 +187,48 @@ uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
return NULL;
}
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
/*---------------------------------------------------------------------------*/
uip_ipaddr_t *
uip_ds6_route_nexthop(uip_ds6_route_t *route)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_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) */
#else /* (UIP_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_head(void)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
return list_head(routelist);
#else /* (UIP_CONF_MAX_ROUTES != 0) */
#else /* (UIP_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_next(uip_ds6_route_t *r)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
if(r != NULL) {
uip_ds6_route_t *n = list_item_next(r);
return n;
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
return NULL;
}
/*---------------------------------------------------------------------------*/
int
uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
const uip_lladdr_t *lladdr;
lladdr = uip_ds6_nbr_lladdr_from_ipaddr(ipaddr);
@ -234,25 +237,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) */
#else /* (UIP_MAX_ROUTES != 0) */
return 0;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
int
uip_ds6_route_num_routes(void)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
return num_routes;
#else /* (UIP_CONF_MAX_ROUTES != 0) */
#else /* (UIP_MAX_ROUTES != 0) */
return 0;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_lookup(uip_ipaddr_t *addr)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
uip_ds6_route_t *r;
uip_ds6_route_t *found_route;
uint8_t longestmatch;
@ -261,6 +264,9 @@ uip_ds6_route_lookup(uip_ipaddr_t *addr)
LOG_INFO_6ADDR(addr);
LOG_INFO("\n");
if(addr == NULL) {
return NULL;
}
found_route = NULL;
longestmatch = 0;
@ -299,16 +305,16 @@ uip_ds6_route_lookup(uip_ipaddr_t *addr)
}
return found_route;
#else /* (UIP_CONF_MAX_ROUTES != 0) */
#else /* (UIP_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_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)
#if (UIP_MAX_ROUTES != 0)
uip_ds6_route_t *r;
struct uip_ds6_route_neighbor_route *nbrr;
@ -316,6 +322,10 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
assert_nbr_routes_list_sane();
#endif /* LOG_DBG_ENABLED */
if(ipaddr == NULL || nexthop == NULL) {
return NULL;
}
/* Get link-layer address of next hop, make sure it is in neighbor table */
const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop);
if(nexthop_lladdr == NULL) {
@ -456,16 +466,16 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
#endif /* LOG_DBG_ENABLED */
return r;
#else /* (UIP_CONF_MAX_ROUTES != 0) */
#else /* (UIP_MAX_ROUTES != 0) */
return NULL;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
void
uip_ds6_route_rm(uip_ds6_route_t *route)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
struct uip_ds6_route_neighbor_route *neighbor_route;
#if LOG_DBG_ENABLED
assert_nbr_routes_list_sane();
@ -523,10 +533,10 @@ uip_ds6_route_rm(uip_ds6_route_t *route)
assert_nbr_routes_list_sane();
#endif /* LOG_DBG_ENABLED */
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
return;
}
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
/*---------------------------------------------------------------------------*/
static void
rm_routelist(struct uip_ds6_route_neighbor_routes *routes)
@ -553,12 +563,12 @@ rm_routelist_callback(nbr_table_item_t *ptr)
{
rm_routelist((struct uip_ds6_route_neighbor_routes *)ptr);
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
/*---------------------------------------------------------------------------*/
void
uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
{
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
/* Get routing entry list of this neighbor */
const uip_lladdr_t *nexthop_lladdr;
struct uip_ds6_route_neighbor_routes *routes;
@ -567,7 +577,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) */
#endif /* (UIP_MAX_ROUTES != 0) */
}
/*---------------------------------------------------------------------------*/
uip_ds6_defrt_t *
@ -585,6 +595,10 @@ uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval)
assert_nbr_routes_list_sane();
#endif /* LOG_DBG_ENABLED */
if(ipaddr == NULL) {
return NULL;
}
LOG_INFO("Add default\n");
d = uip_ds6_defrt_lookup(ipaddr);
if(d == NULL) {
@ -659,6 +673,9 @@ uip_ds6_defrt_t *
uip_ds6_defrt_lookup(uip_ipaddr_t *ipaddr)
{
uip_ds6_defrt_t *d;
if(ipaddr == NULL) {
return NULL;
}
for(d = list_head(defaultrouterlist);
d != NULL;
d = list_item_next(d)) {

View File

@ -44,13 +44,26 @@
#include "net/nbr-table.h"
#include "sys/stimer.h"
#include "lib/list.h"
#if UIP_CONF_IPV6_RPL
#include "rpl-conf.h"
#endif
#ifdef UIP_CONF_MAX_ROUTES
#define UIP_MAX_ROUTES UIP_CONF_MAX_ROUTES
#else /* UIP_CONF_MAX_ROUTES */
#if RPL_WITH_STORING
#define UIP_MAX_ROUTES CONTIKI_NETWORK_SIZE
#else
#define UIP_MAX_ROUTES 0
#endif
#endif /* UIP_CONF_MAX_ROUTES */
NBR_TABLE_DECLARE(nbr_routes);
void uip_ds6_route_init(void);
#ifndef UIP_CONF_UIP_DS6_NOTIFICATIONS
#define UIP_DS6_NOTIFICATIONS (UIP_CONF_MAX_ROUTES != 0)
#define UIP_DS6_NOTIFICATIONS (UIP_MAX_ROUTES != 0)
#else
#define UIP_DS6_NOTIFICATIONS UIP_CONF_UIP_DS6_NOTIFICATIONS
#endif
@ -82,11 +95,11 @@ void uip_ds6_notification_rm(struct uip_ds6_notification *n);
#endif
/* Routing table */
#ifdef UIP_CONF_MAX_ROUTES
#define UIP_DS6_ROUTE_NB UIP_CONF_MAX_ROUTES
#else /* UIP_CONF_MAX_ROUTES */
#ifdef UIP_MAX_ROUTES
#define UIP_DS6_ROUTE_NB UIP_MAX_ROUTES
#else /* UIP_MAX_ROUTES */
#define UIP_DS6_ROUTE_NB 4
#endif /* UIP_CONF_MAX_ROUTES */
#endif /* UIP_MAX_ROUTES */
/** \brief define some additional RPL related route state and
* neighbor callback for RPL - if not a DS6_ROUTE_STATE is already set */

View File

@ -210,6 +210,10 @@ uip_ds6_list_loop(uip_ds6_element_t *list, uint8_t size,
{
uip_ds6_element_t *element;
if(list == NULL || ipaddr == NULL || out_element == NULL) {
return NOSPACE;
}
*out_element = NULL;
for(element = list;

View File

@ -227,7 +227,7 @@ typedef struct uip_ds6_maddr {
} uip_ds6_maddr_t;
/* only define the callback if RPL is active */
#if UIP_CONF_IPV6_RPL
#if UIP_CONF_IPV6_RPL && (UIP_CONF_IPV6_RPL_LITE == 0)
#ifndef UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED
#define UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED rpl_ipv6_neighbor_callback
#endif /* UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED */

View File

@ -59,7 +59,10 @@
#define UIP_FIRST_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[UIP_LLIPH_LEN])
#if UIP_CONF_IPV6_RPL
#include "rpl/rpl.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#endif /* UIP_CONF_IPV6_RPL */
/** \brief temporary IP address */
@ -189,7 +192,7 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) {
}
#if UIP_CONF_IPV6_RPL
rpl_remove_header();
rpl_ext_header_remove();
#else
uip_ext_len = 0;
#endif /* UIP_CONF_IPV6_RPL */

View File

@ -81,8 +81,10 @@
#include "net/ipv6/multicast/uip-mcast6.h"
#if UIP_CONF_IPV6_RPL
#include "rpl/rpl.h"
#include "rpl/rpl-private.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#endif
#if UIP_ND6_SEND_NS
@ -878,8 +880,8 @@ ext_hdr_options_process(void)
*/
#if UIP_CONF_IPV6_RPL
LOG_DBG("Processing RPL option\n");
if(!rpl_verify_hbh_header(uip_ext_opt_offset)) {
LOG_ERR("RPL Option Error: Dropping Packet\n");
if(!rpl_ext_header_hbh_update(uip_ext_opt_offset)) {
LOG_DBG("RPL Option Error: Dropping Packet\n");
return 1;
}
#endif /* UIP_CONF_IPV6_RPL */
@ -1357,7 +1359,7 @@ uip_process(uint8_t flag)
LOG_DBG("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()) {
if(rpl_ext_header_srh_update()) {
goto send; /* Proceed to forwarding */
}
#endif /* UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING */

View File

@ -36,7 +36,7 @@
* Output functions.
* \author
* Adam Dunkels <adam@sics.se>
* Simon Duquennoy <simon.duquennoy@ri.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#include "net/mac/csma/csma.h"

View File

@ -36,7 +36,7 @@
* Output functions.
* \author
* Simon Duquennoy <simon.duquennoy@ri.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#ifndef CSMA_OUTPUT_H_

View File

@ -35,7 +35,7 @@
* The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
* \author
* Adam Dunkels <adam@sics.se>
* Simon Duquennoy <simon.duquennoy@ri.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#include "net/mac/csma/csma.h"

View File

@ -35,7 +35,7 @@
* The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
* \author
* Adam Dunkels <adam@sics.se>
* Simon Duquennoy <simon.duquennoy@ri.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#ifndef CSMA_H_

View File

@ -74,7 +74,7 @@
#ifdef TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES
#define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES
#else
#define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES ((NBR_TABLE_CONF_MAX_NEIGHBORS) + 2)
#define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES ((CONTIKI_NETWORK_DENSITY) + 2)
#endif
/* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */

View File

@ -38,8 +38,10 @@
#if UIP_CONF_IPV6_RPL
#include "contiki.h"
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#include "net/mac/tsch/tsch.h"
#include "net/mac/tsch/tsch-private.h"
#include "net/mac/tsch/tsch-schedule.h"
@ -66,7 +68,11 @@ tsch_rpl_callback_leaving_network(void)
{
rpl_dag_t *dag = rpl_get_any_dag();
if(dag != NULL) {
#if UIP_CONF_IPV6_RPL_LITE
rpl_local_repair("TSCH leaving");
#else
rpl_local_repair(dag->instance);
#endif
}
}
/*---------------------------------------------------------------------------*/
@ -76,16 +82,31 @@ void
tsch_rpl_callback_new_dio_interval(uint8_t dio_interval)
{
/* Transmit EBs only if we have a valid rank as per 6TiSCH minimal */
rpl_dag_t *dag = rpl_get_any_dag();
if(dag != NULL && dag->rank != INFINITE_RANK) {
rpl_dag_t *dag;
rpl_instance_t *instance;
rpl_rank_t root_rank;
rpl_rank_t dag_rank;
#if UIP_CONF_IPV6_RPL_LITE
instance = &curr_instance;
dag = &curr_instance.dag;
root_rank = ROOT_RANK;
dag_rank = DAG_RANK(dag->rank);
#else
dag = rpl_get_any_dag();
instance = dag != NULL ? dag->instance : NULL;
root_rank = ROOT_RANK(instance);
dag_rank = DAG_RANK(dag->rank, instance);
#endif
if(dag != NULL && dag->rank != RPL_INFINITE_RANK) {
/* If we are root set TSCH as coordinator */
if(dag->rank == ROOT_RANK(dag->instance)) {
if(dag->rank == root_rank) {
tsch_set_coordinator(1);
}
/* Set EB period */
tsch_set_eb_period((CLOCK_SECOND * 1UL << dag->instance->dio_intcurrent) / 1000);
tsch_set_eb_period((CLOCK_SECOND * 1UL << instance->dag.dio_intcurrent) / 1000);
/* Set join priority based on RPL rank */
tsch_set_join_priority(DAG_RANK(dag->rank, dag->instance) - 1);
tsch_set_join_priority(dag_rank - 1);
} else {
tsch_set_eb_period(0);
}
@ -99,7 +120,7 @@ tsch_rpl_callback_parent_switch(rpl_parent_t *old, rpl_parent_t *new)
if(tsch_is_associated == 1) {
tsch_queue_update_time_source(
(const linkaddr_t *)uip_ds6_nbr_lladdr_from_ipaddr(
rpl_get_parent_ipaddr(new)));
rpl_parent_get_ipaddr(new)));
}
}
#endif /* UIP_CONF_IPV6_RPL */

View File

@ -34,7 +34,7 @@
/********** Includes **********/
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "net/mac/tsch/tsch-queue.h"
/********** Functions *********/

View File

@ -43,7 +43,7 @@
#ifdef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_MAX_NEIGHBORS NBR_TABLE_CONF_MAX_NEIGHBORS
#else /* NBR_TABLE_CONF_MAX_NEIGHBORS */
#define NBR_TABLE_MAX_NEIGHBORS 8
#define NBR_TABLE_MAX_NEIGHBORS CONTIKI_NETWORK_DENSITY
#endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */
/* An item in a neighbor table */

View File

@ -0,0 +1,375 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Public configuration and API declarations for ContikiRPL.
* \author
* Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon DUquennoy <simon.duquennoy@inria.fr>
*
*/
#ifndef RPL_CONF_H
#define RPL_CONF_H
#include "contiki-conf.h"
/******************************************************************************/
/*********************** Enabling/disabling features **************************/
/******************************************************************************/
/* RPL Mode of operation */
#ifdef RPL_CONF_MOP
#define RPL_MOP_DEFAULT RPL_CONF_MOP
#else /* RPL_CONF_MOP */
#define RPL_MOP_DEFAULT RPL_MOP_NON_STORING
#endif /* RPL_CONF_MOP */
/*
* We only support non-storing mode
*/
#define RPL_WITH_STORING 0
#define RPL_WITH_NON_STORING (RPL_MOP_DEFAULT == RPL_MOP_NON_STORING)
/* The number of non-storing nodes, i.e. the maximum netwrok size at the root */
#ifdef RPL_NS_CONF_LINK_NUM
#define RPL_NS_LINK_NUM RPL_NS_CONF_LINK_NUM
#else /* RPL_NS_CONF_LINK_NUM */
#if RPL_WITH_NON_STORING
#define RPL_NS_LINK_NUM CONTIKI_NETWORK_SIZE
#else
#define RPL_NS_LINK_NUM 0
#endif
#endif /* RPL_NS_CONF_LINK_NUM */
/*
* The objective function (OF) used by a RPL root is configurable through
* the RPL_CONF_OF_OCP parameter. This is defined as the objective code
* point (OCP) of the OF, RPL_OCP_OF0 or RPL_OCP_MRHOF. This flag is of
* no relevance to non-root nodes, which run the OF advertised in the
* instance they join.
* Make sure the selected of is inRPL_SUPPORTED_OFS.
*/
#ifdef RPL_CONF_OF_OCP
#define RPL_OF_OCP RPL_CONF_OF_OCP
#else /* RPL_CONF_OF_OCP */
#define RPL_OF_OCP RPL_OCP_MRHOF
#endif /* RPL_CONF_OF_OCP */
/*
* The set of objective functions supported at runtime. Nodes are only
* able to join instances that advertise an OF in this set. To include
* both OF0 and MRHOF, use {&rpl_of0, &rpl_mrhof}.
*/
#ifdef RPL_CONF_SUPPORTED_OFS
#define RPL_SUPPORTED_OFS RPL_CONF_SUPPORTED_OFS
#else /* RPL_CONF_SUPPORTED_OFS */
#define RPL_SUPPORTED_OFS {&rpl_mrhof}
#endif /* RPL_CONF_SUPPORTED_OFS */
/*
* Enable/disable RPL Metric Containers (MC). The actual MC in use
* for a given DODAG is decided at runtime, when joining. Note that
* OF0 (RFC6552) operates without MC, and so does MRHOF (RFC6719) when
* used with ETX as a metric (the rank is the metric). We disable MC
* by default, but note it must be enabled to support joining a DODAG
* that requires MC (e.g., MRHOF with a metric other than ETX).
*/
#ifdef RPL_CONF_WITH_MC
#define RPL_WITH_MC RPL_CONF_WITH_MC
#else /* RPL_CONF_WITH_MC */
#define RPL_WITH_MC 0
#endif /* RPL_CONF_WITH_MC */
/* The MC advertised in DIOs and propagating from the root */
#ifdef RPL_CONF_DAG_MC
#define RPL_DAG_MC RPL_CONF_DAG_MC
#else
#define RPL_DAG_MC RPL_DAG_MC_NONE
#endif /* RPL_CONF_DAG_MC */
/*
* RPL DAO-ACK support. When enabled, DAO-ACK will be sent and requested.
* This will also enable retransmission of DAO when no ack is received.
* */
#ifdef RPL_CONF_WITH_DAO_ACK
#define RPL_WITH_DAO_ACK RPL_CONF_WITH_DAO_ACK
#else
#define RPL_WITH_DAO_ACK 0
#endif /* RPL_CONF_WITH_DAO_ACK */
/*
* RPL REPAIR ON DAO NACK. When enabled, DAO NACK will trigger a local
* repair in order to quickly find a new parent to send DAO's to.
* NOTE: this is too agressive in some cases so use with care.
* */
#ifdef RPL_CONF_RPL_REPAIR_ON_DAO_NACK
#define RPL_REPAIR_ON_DAO_NACK RPL_CONF_RPL_REPAIR_ON_DAO_NACK
#else
#define RPL_REPAIR_ON_DAO_NACK 0
#endif /* RPL_CONF_RPL_REPAIR_ON_DAO_NACK */
/*
* Setting the RPL_TRICKLE_REFRESH_DAO_ROUTES will make the RPL root
* increase the DTSN (Destination Advertisement Trigger Sequence Number)
* from the DIO trickle timer. If set to 4, DTSN will be increased every 4th
* iteration. This is to get all children to re-register their DAO route.
* This is needed when DAO-ACK is not enabled to
* add reliability to route maintenance.
* */
#ifdef RPL_CONF_TRICKLE_REFRESH_DAO_ROUTES
#define RPL_TRICKLE_REFRESH_DAO_ROUTES RPL_CONF_TRICKLE_REFRESH_DAO_ROUTES
#else
#if RPL_WITH_DAO_ACK
#define RPL_TRICKLE_REFRESH_DAO_ROUTES 0
#else
#define RPL_TRICKLE_REFRESH_DAO_ROUTES 4
#endif
#endif /* RPL_CONF_TRICKLE_REFRESH_DAO_ROUTES */
/*
* RPL probing. When enabled, probes will be sent periodically to keep
* parent link estimates up to date. Further configurable
* via RPL_CONF_PROBING_* flags
*/
#ifdef RPL_CONF_WITH_PROBING
#define RPL_WITH_PROBING RPL_CONF_WITH_PROBING
#else
#define RPL_WITH_PROBING 1
#endif
/*
* Function used to select the next parent to be probed.
*/
#ifdef RPL_CONF_PROBING_SELECT_FUNC
#define RPL_PROBING_SELECT_FUNC RPL_CONF_PROBING_SELECT_FUNC
#else
#define RPL_PROBING_SELECT_FUNC get_probing_target
#endif
/*
* Function used to send RPL probes.
* To probe with DIO, use:
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) rpl_icmp6_dio_output((instance), (addr))
* To probe with DIS, use:
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) rpl_icmp6_dis_output((addr))
* Any other custom probing function is also acceptable.
*/
#ifdef RPL_CONF_PROBING_SEND_FUNC
#define RPL_PROBING_SEND_FUNC RPL_CONF_PROBING_SEND_FUNC
#else
#define RPL_PROBING_SEND_FUNC(addr) rpl_icmp6_dio_output((addr))
#endif
/*
* This value decides if this node must stay as a leaf or not
* as allowed by draft-ietf-roll-rpl-19#section-8.5
*/
#ifdef RPL_CONF_LEAF_ONLY
#define RPL_LEAF_ONLY RPL_CONF_LEAF_ONLY
#else
#define RPL_LEAF_ONLY 0
#endif
/******************************************************************************/
/********************************** Timing ************************************/
/******************************************************************************/
/*
* The DIO interval (n) represents 2^n ms.
*
* According to the specification, the default value is 3 which
* means 8 milliseconds. That is far too low when using duty cycling
* with wake-up intervals that are typically hundreds of milliseconds.
* ContikiRPL thus sets the default to 2^12 ms = 4.096 s.
*/
#ifdef RPL_CONF_DIO_INTERVAL_MIN
#define RPL_DIO_INTERVAL_MIN RPL_CONF_DIO_INTERVAL_MIN
#else
#define RPL_DIO_INTERVAL_MIN 12
#endif
/*
* Maximum amount of timer doublings.
*
* The maximum interval will by default be 2^(12+8) ms = 1048.576 s.
* RFC 6550 suggests a default value of 20, which of course would be
* unsuitable when we start with a minimum interval of 2^12.
*/
#ifdef RPL_CONF_DIO_INTERVAL_DOUBLINGS
#define RPL_DIO_INTERVAL_DOUBLINGS RPL_CONF_DIO_INTERVAL_DOUBLINGS
#else
#define RPL_DIO_INTERVAL_DOUBLINGS 8
#endif
/*
* DIO redundancy. To learn more about this, see RFC 6206.
*
* RFC 6550 suggests a default value of 10. We disable this mechanism by
* default, using a value of 0. This is to enable reliable DTSN increment
* propagation, and periodic rank dissemination without the need to increment
* version. Note that Trickle was originally designed for CTP, aiming to
* reduce broadcast traffic, which was particularly expensive done over an
* LPL MAC. In MAC layers such as non-beacon enabled or TSCH, broadcast is no
* more costly than unicast. Further, in this RPL implementation, DIOs are
* responsible for only a portion of the control traffic, compared to Link
* probing which is done at a period of minutes (RPL_PROBING_INTERVAL)
* for reliable parent selection.
*/
#ifdef RPL_CONF_DIO_REDUNDANCY
#define RPL_DIO_REDUNDANCY RPL_CONF_DIO_REDUNDANCY
#else
#define RPL_DIO_REDUNDANCY 0
#endif
/*
* Default route lifetime unit. This is the granularity of time
* used in RPL lifetime values, in seconds.
*/
#ifndef RPL_CONF_DEFAULT_LIFETIME_UNIT
#define RPL_DEFAULT_LIFETIME_UNIT 60
#else
#define RPL_DEFAULT_LIFETIME_UNIT RPL_CONF_DEFAULT_LIFETIME_UNIT
#endif
/*
* Default route lifetime as a multiple of the lifetime unit.
*/
#ifndef RPL_CONF_DEFAULT_LIFETIME
#define RPL_DEFAULT_LIFETIME 30
#else
#define RPL_DEFAULT_LIFETIME RPL_CONF_DEFAULT_LIFETIME
#endif
/*
* RPL probing interval.
*/
#ifdef RPL_CONF_PROBING_INTERVAL
#define RPL_PROBING_INTERVAL RPL_CONF_PROBING_INTERVAL
#else
#define RPL_PROBING_INTERVAL (60 * CLOCK_SECOND)
#endif
/*
* Function used to calculate next RPL probing interval
*/
#ifdef RPL_CONF_PROBING_DELAY_FUNC
#define RPL_PROBING_DELAY_FUNC RPL_CONF_PROBING_DELAY_FUNC
#else
#define RPL_PROBING_DELAY_FUNC get_probing_delay
#endif
/* Interval of DIS transmission */
#ifdef RPL_CONF_DIS_INTERVAL
#define RPL_DIS_INTERVAL RPL_CONF_DIS_INTERVAL
#else
#define RPL_DIS_INTERVAL (30 * CLOCK_SECOND)
#endif
/* DAO transmissions are always delayed by RPL_DAO_DELAY +/- RPL_DAO_DELAY/2 */
#ifdef RPL_CONF_DAO_DELAY
#define RPL_DAO_DELAY RPL_CONF_DAO_DELAY
#else /* RPL_CONF_DAO_DELAY */
#define RPL_DAO_DELAY (CLOCK_SECOND * 4)
#endif /* RPL_CONF_DAO_DELAY */
/* Delay between reception of a no-path DAO and actual route removal */
#ifdef RPL_CONF_NOPATH_REMOVAL_DELAY
#define RPL_NOPATH_REMOVAL_DELAY RPL_CONF_NOPATH_REMOVAL_DELAY
#else /* RPL_CONF_NOPATH_REMOVAL_DELAY */
#define RPL_NOPATH_REMOVAL_DELAY 60
#endif /* RPL_CONF_NOPATH_REMOVAL_DELAY */
#ifdef RPL_CONF_DAO_MAX_RETRANSMISSIONS
#define RPL_DAO_MAX_RETRANSMISSIONS RPL_CONF_DAO_MAX_RETRANSMISSIONS
#else
#define RPL_DAO_MAX_RETRANSMISSIONS 5
#endif /* RPL_CONF_DAO_MAX_RETRANSMISSIONS */
#ifdef RPL_CONF_DAO_RETRANSMISSION_TIMEOUT
#define RPL_DAO_RETRANSMISSION_TIMEOUT RPL_CONF_DAO_RETRANSMISSION_TIMEOUT
#else
#define RPL_DAO_RETRANSMISSION_TIMEOUT (5 * CLOCK_SECOND)
#endif /* RPL_CONF_DAO_RETRANSMISSION_TIMEOUT */
/******************************************************************************/
/************************** More parameterization *****************************/
/******************************************************************************/
#ifndef RPL_CONF_MIN_HOPRANKINC
/* RFC6550 defines the default MIN_HOPRANKINC as 256.
* However, we use MRHOF as a default Objective Function (RFC6719),
* which recommends setting MIN_HOPRANKINC with care, in particular
* when used with ETX as a metric. ETX is computed as a fixed point
* real with a divisor of 128 (RFC6719, RFC6551). We choose to also
* use 128 for RPL_MIN_HOPRANKINC, resulting in a rank equal to the
* ETX path cost. Larger values may also be desirable, as discussed
* in section 6.1 of RFC6719. */
#if RPL_OF_OCP == RPL_OCP_MRHOF
#define RPL_MIN_HOPRANKINC 128
#else /* RPL_OF_OCP == RPL_OCP_MRHOF */
#define RPL_MIN_HOPRANKINC 256
#endif /* RPL_OF_OCP == RPL_OCP_MRHOF */
#else /* RPL_CONF_MIN_HOPRANKINC */
#define RPL_MIN_HOPRANKINC RPL_CONF_MIN_HOPRANKINC
#endif /* RPL_CONF_MIN_HOPRANKINC */
#ifndef RPL_CONF_MAX_RANKINC
#define RPL_MAX_RANKINC (7 * RPL_MIN_HOPRANKINC)
#else /* RPL_CONF_MAX_RANKINC */
#define RPL_MAX_RANKINC RPL_CONF_MAX_RANKINC
#endif /* RPL_CONF_MAX_RANKINC */
/* This value decides which DAG instance we should participate in by default. */
#ifdef RPL_CONF_DEFAULT_INSTANCE
#define RPL_DEFAULT_INSTANCE RPL_CONF_DEFAULT_INSTANCE
#else
#define RPL_DEFAULT_INSTANCE 0x1e
#endif /* RPL_CONF_DEFAULT_INSTANCE */
/* Set to have the root advertise a grounded DAG */
#ifndef RPL_CONF_GROUNDED
#define RPL_GROUNDED 0
#else
#define RPL_GROUNDED RPL_CONF_GROUNDED
#endif /* !RPL_CONF_GROUNDED */
/*
* DAG preference field
*/
#ifdef RPL_CONF_PREFERENCE
#define RPL_PREFERENCE RPL_CONF_PREFERENCE
#else
#define RPL_PREFERENCE 0
#endif
#endif /* RPL_CONF_H */

View File

@ -0,0 +1,156 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Constants for RPL
* \author
* Joakim Eriksson <joakime@sics.se> & Nicolas Tsiftes <nvt@sics.se>,
* Simon Duquennoy <simon.duquennoy@inria.fr>
*
*/
#ifndef RPL_CONST_H
#define RPL_CONST_H
/**
* \addtogroup uip6
* @{
*/
/********** Constants **********/
/* Special value indicating infinite lifetime. */
#define RPL_INFINITE_LIFETIME 0xFF
#define RPL_ROUTE_INFINITE_LIFETIME 0xFFFFFFFF
#define RPL_INFINITE_RANK 0xffff
/*---------------------------------------------------------------------------*/
/* IANA Routing Metric/Constraint Type as defined in RFC6551 */
#define RPL_DAG_MC_NONE 0 /* Local identifier for empty MC */
#define RPL_DAG_MC_NSA 1 /* Node State and Attributes */
#define RPL_DAG_MC_ENERGY 2 /* Node Energy */
#define RPL_DAG_MC_HOPCOUNT 3 /* Hop Count */
#define RPL_DAG_MC_THROUGHPUT 4 /* Throughput */
#define RPL_DAG_MC_LATENCY 5 /* Latency */
#define RPL_DAG_MC_LQL 6 /* Link Quality Level */
#define RPL_DAG_MC_ETX 7 /* Expected Transmission Count */
#define RPL_DAG_MC_LC 8 /* Link Color */
/* IANA Routing Metric/Constraint Common Header Flag field as defined in RFC6551 (bit indexes) */
#define RPL_DAG_MC_FLAG_P 5
#define RPL_DAG_MC_FLAG_C 6
#define RPL_DAG_MC_FLAG_O 7
#define RPL_DAG_MC_FLAG_R 8
/* IANA Routing Metric/Constraint Common Header A Field as defined in RFC6551 */
#define RPL_DAG_MC_AGGR_ADDITIVE 0
#define RPL_DAG_MC_AGGR_MAXIMUM 1
#define RPL_DAG_MC_AGGR_MINIMUM 2
#define RPL_DAG_MC_AGGR_MULTIPLICATIVE 3
/* The bit index within the flags field of the rpl_metric_object_energy structure. */
#define RPL_DAG_MC_ENERGY_INCLUDED 3
#define RPL_DAG_MC_ENERGY_TYPE 1
#define RPL_DAG_MC_ENERGY_ESTIMATION 0
/* IANA Node Type Field as defined in RFC6551 */
#define RPL_DAG_MC_ENERGY_TYPE_MAINS 0
#define RPL_DAG_MC_ENERGY_TYPE_BATTERY 1
#define RPL_DAG_MC_ENERGY_TYPE_SCAVENGING 2
/* IANA Objective Code Point as defined in RFC6550 */
#define RPL_OCP_OF0 0
#define RPL_OCP_MRHOF 1
/*---------------------------------------------------------------------------*/
/* RPL message types */
#define RPL_CODE_DIS 0x00 /* DAG Information Solicitation */
#define RPL_CODE_DIO 0x01 /* DAG Information Option */
#define RPL_CODE_DAO 0x02 /* Destination Advertisement Option */
#define RPL_CODE_DAO_ACK 0x03 /* DAO acknowledgment */
#define RPL_CODE_SEC_DIS 0x80 /* Secure DIS */
#define RPL_CODE_SEC_DIO 0x81 /* Secure DIO */
#define RPL_CODE_SEC_DAO 0x82 /* Secure DAO */
#define RPL_CODE_SEC_DAO_ACK 0x83 /* Secure DAO-ACK */
/* RPL control message options. */
#define RPL_OPTION_PAD1 0
#define RPL_OPTION_PADN 1
#define RPL_OPTION_DAG_METRIC_CONTAINER 2
#define RPL_OPTION_ROUTE_INFO 3
#define RPL_OPTION_DAG_CONF 4
#define RPL_OPTION_TARGET 5
#define RPL_OPTION_TRANSIT 6
#define RPL_OPTION_SOLICITED_INFO 7
#define RPL_OPTION_PREFIX_INFO 8
#define RPL_OPTION_TARGET_DESC 9
#define RPL_DAO_K_FLAG 0x80 /* DAO-ACK requested */
#define RPL_DAO_D_FLAG 0x40 /* DODAG ID present */
#define RPL_DAO_ACK_UNCONDITIONAL_ACCEPT 0
#define RPL_DAO_ACK_ACCEPT 1 /* 1 - 127 is OK but not good */
#define RPL_DAO_ACK_UNABLE_TO_ACCEPT 128 /* >127 is fail */
#define RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT 255 /* root can not accept */
#define RPL_DAO_ACK_TIMEOUT -1
/*---------------------------------------------------------------------------*/
/* 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
#define RPL_HDR_OPT_RANK_ERR_SHIFT 6
#define RPL_HDR_OPT_FWD_ERR 0x20
#define RPL_HDR_OPT_FWD_ERR_SHIFT 5
/*---------------------------------------------------------------------------*/
#define RPL_INSTANCE_LOCAL_FLAG 0x80
#define RPL_INSTANCE_D_FLAG 0x40
/* Values that tell where a route came from. */
#define RPL_ROUTE_FROM_INTERNAL 0
#define RPL_ROUTE_FROM_UNICAST_DAO 1
#define RPL_ROUTE_FROM_MULTICAST_DAO 2
#define RPL_ROUTE_FROM_DIO 3
/* DAG Mode of Operation */
#define RPL_MOP_NO_DOWNWARD_ROUTES 0
#define RPL_MOP_NON_STORING 1
#define RPL_MOP_STORING_NO_MULTICAST 2
#define RPL_MOP_STORING_MULTICAST 3
/** @} */
#endif /* RPL_CONST_H */

View File

@ -0,0 +1,185 @@
/*
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
* COPYRIGHT HOLDER 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.
*
*/
#include "contiki.h"
#include "contiki-net.h"
#include "rpl.h"
#include "net/ipv6/uip-ds6-route.h"
#include <string.h>
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
#define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1)
static uint8_t to_become_root;
static struct ctimer c;
/*---------------------------------------------------------------------------*/
static void
create_dag_callback(void *ptr)
{
const uip_ipaddr_t *root, *ipaddr;
root = curr_instance.used ? &curr_instance.dag.dag_id : NULL;
ipaddr = rpl_get_global_address();
if(root == NULL || uip_ipaddr_cmp(root, ipaddr)) {
/* The RPL network we are joining is one that we created, so we
become root. */
if(to_become_root) {
rpl_dag_root_init_dag_immediately();
to_become_root = 0;
}
} else {
#if DEBUG
printf("Found a network we did not create\n");
printf("version %d grounded %d preference %d rank %d\n",
curr_instance.dag.version, curr_instance.dag.grounded,
curr_instance.dag.preference, curr_instance.dag.rank);
#endif /* DEBUG */
/* We found a RPL network that we did not create so we just join
it without becoming root. But if the network has an infinite
rank, we assume the network has broken, and we become the new
root of the network. */
if(curr_instance.dag.rank == RPL_INFINITE_RANK) {
if(to_become_root) {
rpl_dag_root_init_dag_immediately();
to_become_root = 0;
}
}
/* Try again after the grace period */
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
}
}
/*---------------------------------------------------------------------------*/
static void
set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid)
{
static uip_ipaddr_t root_ipaddr;
int i;
uint8_t state;
/* Assign a unique local address (RFC4193,
http://tools.ietf.org/html/rfc4193). */
if(prefix == NULL) {
uip_ip6addr(&root_ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
} else {
memcpy(&root_ipaddr, prefix, 8);
}
if(iid == NULL) {
uip_ds6_set_addr_iid(&root_ipaddr, &uip_lladdr);
} else {
memcpy(((uint8_t*)&root_ipaddr) + 8, ((uint8_t*)iid) + 8, 8);
}
uip_ds6_addr_add(&root_ipaddr, 0, ADDR_AUTOCONF);
printf("IPv6 addresses: ");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
(state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
printf("\n");
}
}
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_root_init(uip_ipaddr_t *prefix, uip_ipaddr_t *iid)
{
static uint8_t initialized = 0;
if(!initialized) {
to_become_root = 0;
set_global_address(prefix, iid);
initialized = 1;
}
}
/*---------------------------------------------------------------------------*/
int
rpl_dag_root_init_dag_immediately(void)
{
struct uip_ds6_addr *root_if;
int i;
uint8_t state;
uip_ipaddr_t *ipaddr = NULL;
rpl_dag_root_init(NULL, NULL);
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
state == ADDR_PREFERRED &&
!uip_is_addr_linklocal(&uip_ds6_if.addr_list[i].ipaddr)) {
ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
}
}
root_if = uip_ds6_addr_lookup(ipaddr);
if(ipaddr != NULL || root_if != NULL) {
rpl_dag_init_root(RPL_DEFAULT_INSTANCE, ipaddr,
(uip_ipaddr_t *)rpl_get_global_address(), 64, UIP_ND6_RA_FLAG_AUTONOMOUS);
rpl_dag_update_state();
PRINTF("rpl_dag_root_init_dag: created a new RPL dag\n");
return 0;
} else {
PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG\n");
return -1;
}
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_root_init_dag_delay(void)
{
rpl_dag_root_init(NULL, NULL);
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
to_become_root = 1;
/* Send a DIS packet to request RPL info from neighbors. */
rpl_icmp6_dis_output(NULL);
}
/*---------------------------------------------------------------------------*/
int
rpl_dag_root_is_root(void)
{
return curr_instance.used && curr_instance.dag.rank == ROOT_RANK;
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
* COPYRIGHT HOLDER 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.
*
*/
#ifndef RPL_DAG_ROOT_H_
#define RPL_DAG_ROOT_H_
/**
* \addtogroup uip6
* @{
*/
/********** Public functions **********/
/**
* Initialize dag-root module and sets a prefix in case the node is later
* set as dag root.
*
* \param prefix The prefix. If NULL, UIP_DS6_DEFAULT_PREFIX is used instead
* \param iid The IID. If NULL, it will be built from uip_ds6_set_addr_iid.
*/
void rpl_dag_root_init(uip_ipaddr_t *prefix, uip_ipaddr_t *iid);
/**
* Initializes the node as DAG root after a delay. Until the delay, the node
* gets a chance to hear another DAG and join it instead.
*/
void rpl_dag_root_init_dag_delay(void);
/**
* Initializes the node as DAG root immediatly.
*
* \return 0 in case of success, -1 otherwise
*/
int rpl_dag_root_init_dag_immediately(void);
/**
* Tells whether we are DAG root or not
*
* \return 1 if we are dag root, 0 otherwise
*/
int rpl_dag_root_is_root(void);
/** @} */
#endif /* RPL_DAG_ROOT_H_ */

592
core/net/rpl-lite/rpl-dag.c Normal file
View File

@ -0,0 +1,592 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Logic for Directed Acyclic Graphs in RPL.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon Duquennoy <simon.duquennoy@inria.fr>
* Contributors: George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
*/
/**
* \addtogroup uip6
* @{
*/
#include "rpl.h"
#include "net/nbr-table.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/*---------------------------------------------------------------------------*/
extern rpl_of_t rpl_of0, rpl_mrhof;
static rpl_of_t * const objective_functions[] = RPL_SUPPORTED_OFS;
static int init_dag_from_dio(rpl_dio_t *dio);
static void leave_dag(void);
/*---------------------------------------------------------------------------*/
/* Allocate instance table. */
rpl_instance_t curr_instance;
/*---------------------------------------------------------------------------*/
void
rpl_dag_periodic(unsigned seconds)
{
if(curr_instance.used) {
if(curr_instance.dag.lifetime != RPL_LIFETIME(RPL_INFINITE_LIFETIME)) {
curr_instance.dag.lifetime =
curr_instance.dag.lifetime > seconds ? curr_instance.dag.lifetime - seconds : 0;
if(curr_instance.dag.lifetime == 0) {
leave_dag();
}
}
}
}
/*---------------------------------------------------------------------------*/
static void
leave_dag(void)
{
PRINTF("RPL: leaving DAG \n");
PRINT6ADDR(&curr_instance.dag.dag_id);
PRINTF(", instance %u\n", curr_instance.instance_id);
/* Issue a no-path DAO */
RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
rpl_icmp6_dao_output(0);
/* Remove all parents/neighbors */
rpl_parent_remove_all();
rpl_timers_stop_dag_timers();
/* Remove autoconfigured address */
if((curr_instance.dag.prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
rpl_reset_prefix(&curr_instance.dag.prefix_info);
}
/* Mark instance as unused */
curr_instance.used = 0;
}
/*---------------------------------------------------------------------------*/
int
rpl_is_addr_in_our_dag(const uip_ipaddr_t *addr)
{
return curr_instance.used
&& uip_ipaddr_prefixcmp(&curr_instance.dag.dag_id, addr, curr_instance.dag.prefix_info.length);
}
/*---------------------------------------------------------------------------*/
rpl_instance_t *
rpl_get_default_instance(void)
{
return curr_instance.used ? &curr_instance : NULL;
}
/*---------------------------------------------------------------------------*/
rpl_dag_t *
rpl_get_any_dag(void)
{
return curr_instance.used ? &curr_instance.dag : NULL;
}
/*---------------------------------------------------------------------------*/
static rpl_of_t *
find_objective_function(rpl_ocp_t ocp)
{
unsigned int i;
for(i = 0; i < sizeof(objective_functions) / sizeof(objective_functions[0]); i++) {
if(objective_functions[i]->ocp == ocp) {
return objective_functions[i];
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void
rpl_global_repair(void)
{
if(rpl_dag_root_is_root()) {
PRINTF("RPL: initiating global repair (version=%u, rank=%u)\n",
curr_instance.dag.version, curr_instance.dag.rank);
#if DEBUG
rpl_parent_print_list("Global repair");
#endif
/* Initiate global repair */
RPL_LOLLIPOP_INCREMENT(curr_instance.dag.version); /* New DAG version */
RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); /* Request new DAOs */
rpl_local_repair("Global repair");
}
}
/*---------------------------------------------------------------------------*/
static void
global_repair_non_root(rpl_dio_t *dio)
{
if(!rpl_dag_root_is_root()) {
PRINTF("RPL: participating in global repair (version=%u, rank=%u)\n",
curr_instance.dag.version, curr_instance.dag.rank);
#if DEBUG
rpl_parent_print_list("Global repair");
#endif
/* Re-initialize configuration from DIO */
init_dag_from_dio(dio);
rpl_local_repair("Global repair");
}
}
/*---------------------------------------------------------------------------*/
void
rpl_local_repair(const char *str)
{
if(curr_instance.used) { /* Check needed because this is a public function */
PRINTF("RPL: local repair (%s)\n", str);
curr_instance.of->reset(); /* Reset OF */
rpl_parent_remove_all(); /* Remove all neighbors/parents */
rpl_timers_dio_reset("Local repair"); /* Reset Trickle timer */
rpl_timers_schedule_state_update();
}
}
/*---------------------------------------------------------------------------*/
/* Updates rank and parent */
void
rpl_dag_update_state(void)
{
if(curr_instance.used) {
if(!rpl_dag_root_is_root()) {
rpl_parent_t *old_parent = curr_instance.dag.preferred_parent;
rpl_rank_t old_rank = curr_instance.dag.rank;
/* Any scheduled state update is no longer needed */
rpl_timers_unschedule_state_update();
/* Select and set preferred parent */
rpl_parent_set_preferred(rpl_parent_select_best());
/* Update rank */
curr_instance.dag.rank = rpl_parent_rank_via_parent(curr_instance.dag.preferred_parent);
if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) {
/* This is a slight departure from RFC6550: if we had no preferred parent before,
* reset lowest_rank. This helps recovering from temporary bad link conditions. */
curr_instance.dag.lowest_rank = curr_instance.dag.rank;
}
/* if new parent, schedule DAO */
if(curr_instance.dag.preferred_parent != old_parent) {
rpl_timers_schedule_dao();
#if DEBUG
rpl_parent_print_list("Parent switch");
#endif
}
if(curr_instance.dag.rank != old_rank && curr_instance.dag.rank == RPL_INFINITE_RANK) {
PRINTF("RPL: intinite rank, trigger local repair\n");
rpl_local_repair("Infinite rank");
}
}
/* Finally, update metric container */
curr_instance.of->update_metric_container();
}
}
/*---------------------------------------------------------------------------*/
static rpl_parent_t *
update_nbr_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
{
rpl_parent_t *p = NULL;
const uip_lladdr_t *lladdr;
p = rpl_parent_get_from_ipaddr(from);
/* Neighbor not in RPL parent table, add it */
if(p == NULL) {
/* Is the parent known by ds6? Drop this request if not.
* Typically, the parent is added upon receiving a DIO. */
lladdr = uip_ds6_nbr_lladdr_from_ipaddr(from);
if(lladdr == NULL) {
return NULL;
}
/* Add neighbor to RPL table */
p = nbr_table_add_lladdr(rpl_parents, (linkaddr_t *)lladdr,
NBR_TABLE_REASON_RPL_DIO, dio);
if(p == NULL) {
PRINTF("RPL: failed to add parent\n");
return NULL;
}
}
/* Update parent info from DIO */
p->rank = dio->rank;
p->dtsn = dio->dtsn;
#if RPL_WITH_MC
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
#endif /* RPL_WITH_MC */
return p;
}
/*---------------------------------------------------------------------------*/
static void
process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
{
rpl_parent_t *p;
uint8_t last_dtsn;
/* Does the rank make sense at all? */
if(dio->rank < ROOT_RANK) {
return;
}
/* If the DIO sender is on an older version of the DAG, ignore it. The node
will eventually hear the global repair and catch up. */
if(rpl_lollipop_greater_than(curr_instance.dag.version, dio->version)) {
return;
}
/* The DIO is valid, proceed further */
/* Update DIO counter for redundancy mngt */
if(dio->rank != RPL_INFINITE_RANK) {
curr_instance.dag.dio_counter++;
}
/* The DIO has a newer version: global repair.
* Must come first, as it might remove all parents, and we then need
* to re-add this source of the DIO to the parent table */
if(rpl_lollipop_greater_than(dio->version, curr_instance.dag.version)) {
if(curr_instance.dag.rank == ROOT_RANK) { /* The root should not hear newer versions */
PRINTF("RPL: inconsistent DIO version (current: %u, received: %u), initiate global repair\n",
curr_instance.dag.version, dio->version);
curr_instance.dag.version = dio->version; /* Update version and trigger global repair */
rpl_global_repair();
} else {
PRINTF("RPL: new DIO version (current: %u, received: %u), apply global repair\n",
curr_instance.dag.version, dio->version);
global_repair_non_root(dio);
}
}
/* Update IPv6 neighbor cache */
if(!rpl_icmp6_update_nbr_table(from, NBR_TABLE_REASON_RPL_DIO, dio)) {
PRINTF("RPL: IPv6 cache full, dropping DIO\n");
return;
}
/* Add neighbor to RPL parent table */
p = rpl_parent_get_from_ipaddr(from);
last_dtsn = p != NULL ? p->dtsn : RPL_LOLLIPOP_INIT;
if(!update_nbr_from_dio(from, dio)) {
PRINTF("RPL: parent table full, dropping DIO\n");
return;
}
/* Refresh lifetime at every DIO from preferred parent. Use same lifetime as for routes */
if(p != NULL && p == curr_instance.dag.preferred_parent) {
curr_instance.dag.lifetime =
RPL_LIFETIME(dio->default_lifetime);
}
/* If the source is our preferred parent and it increased DTSN, we increment
* our DTSN in turn and schedule a DAO (see RFC6550 section 9.6.) */
if(curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
if(p != NULL && p == curr_instance.dag.preferred_parent && rpl_lollipop_greater_than(dio->dtsn, last_dtsn)) {
RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
rpl_timers_schedule_dao();
}
}
}
/*---------------------------------------------------------------------------*/
static int
init_dag(uint8_t instance_id, uip_ipaddr_t *dag_id, rpl_ocp_t ocp,
uip_ipaddr_t *prefix, unsigned prefix_len, uint8_t prefix_flags)
{
rpl_of_t *of;
memset(&curr_instance, 0, sizeof(curr_instance));
/* OF */
of = find_objective_function(ocp);
if(of == NULL) {
PRINTF("RPL: ignoring DIO with an unsupported OF: %u\n", ocp);
return 0;
}
/* Prefix */
if(!rpl_set_prefix_from_addr(prefix, prefix_len, prefix_flags)) {
PRINTF("RPL: failed to set prefix");
return 0;
}
/* Instnace */
curr_instance.instance_id = instance_id;
curr_instance.of = of;
curr_instance.dtsn_out = RPL_LOLLIPOP_INIT;
curr_instance.used = 1;
/* DAG */
curr_instance.dag.rank = RPL_INFINITE_RANK;
curr_instance.dag.lowest_rank = RPL_INFINITE_RANK;
curr_instance.dag.dao_last_seqno = RPL_LOLLIPOP_INIT;
curr_instance.dag.dao_last_acked_seqno = RPL_LOLLIPOP_INIT;
curr_instance.dag.dao_curr_seqno = RPL_LOLLIPOP_INIT;
memcpy(&curr_instance.dag.dag_id, dag_id, sizeof(curr_instance.dag.dag_id));
return 1;
}
/*---------------------------------------------------------------------------*/
static int
init_dag_from_dio(rpl_dio_t *dio)
{
if(!init_dag(dio->instance_id, &dio->dag_id, dio->ocp,
&dio->prefix_info.prefix, dio->prefix_info.length, dio->prefix_info.flags)) {
return 0;
}
/* Instnace */
curr_instance.mop = dio->mop;
curr_instance.mc.type = dio->mc.type;
curr_instance.mc.flags = dio->mc.flags;
curr_instance.mc.aggr = dio->mc.aggr;
curr_instance.mc.prec = dio->mc.prec;
curr_instance.max_rankinc = dio->dag_max_rankinc;
curr_instance.min_hoprankinc = dio->dag_min_hoprankinc;
curr_instance.dio_intdoubl = dio->dag_intdoubl;
curr_instance.dio_intmin = dio->dag_intmin;
curr_instance.dio_redundancy = dio->dag_redund;
curr_instance.default_lifetime = dio->default_lifetime;
curr_instance.lifetime_unit = dio->lifetime_unit;
/* DAG */
curr_instance.dag.preference = dio->preference;
curr_instance.dag.grounded = dio->grounded;
curr_instance.dag.version = dio->version;
curr_instance.dag.dio_intcurrent = dio->dag_intmin;
return 1;
}
/*---------------------------------------------------------------------------*/
static int
process_dio_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
{
/* Check MOP */
if(dio->mop != RPL_MOP_NO_DOWNWARD_ROUTES && dio->mop != RPL_MOP_NON_STORING) {
PRINTF("RPL: ignoring DIO with an unsupported MOP: %d\n", dio->mop);
return 0;
}
/* Initialize instance and DAG data structures */
if(!init_dag_from_dio(dio)) {
PRINTF("RPL: failed to initialize DAG\n");
return 0;
}
/* Init OF and timers */
curr_instance.of->reset();
rpl_timers_dio_reset("Join");
#if RPL_WITH_PROBING
rpl_schedule_probing();
#endif /* RPL_WITH_PROBING */
PRINTF("RPL: joined DAG with instance ID %u, DAG ID ",
curr_instance.instance_id);
PRINT6ADDR(&curr_instance.dag.dag_id);
PRINTF(", rank %u\n", curr_instance.dag.rank);
ANNOTATE("#A join=%u\n", curr_instance.dag.dag_id.u8[sizeof(curr_instance.dag.dag_id) - 1]);
return 1;
}
/*---------------------------------------------------------------------------*/
void
rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
{
if(!curr_instance.used && !rpl_dag_root_is_root()) {
/* Attempt to join on this DIO */
if(!process_dio_join_dag(from, dio)) {
PRINTF("RPL: failed to join DAG");
return;
}
}
if(curr_instance.used
&& curr_instance.instance_id == dio->instance_id
&& uip_ipaddr_cmp(&curr_instance.dag.dag_id, &dio->dag_id)) {
process_dio_from_current_dag(from, dio);
rpl_dag_update_state();
}
}
/*---------------------------------------------------------------------------*/
void
rpl_process_dis(uip_ipaddr_t *from, int is_multicast)
{
if(is_multicast) {
rpl_timers_dio_reset("Multicast DIS");
} else {
/* Add neighbor to cache and reply to the unicast DIS with a unicast DIO*/
if(rpl_icmp6_update_nbr_table(from, NBR_TABLE_REASON_RPL_DIS, NULL) != NULL) {
PRINTF("RPL: unicast DIS, reply to sender\n");
rpl_icmp6_dio_output(from);
}
}
}
/*---------------------------------------------------------------------------*/
void
rpl_process_dao(uip_ipaddr_t *from, rpl_dao_t *dao)
{
if(dao->lifetime == 0) {
rpl_ns_expire_parent(from, &dao->parent_addr);
} else {
if(!rpl_ns_update_node(from, &dao->parent_addr, RPL_LIFETIME(dao->lifetime))) {
PRINTF("RPL: failed to add link on incoming DAO\n");
return;
}
}
#if RPL_WITH_DAO_ACK
if(dao->flags & RPL_DAO_K_FLAG) {
rpl_timers_schedule_dao_ack(from, dao->sequence);
}
#endif /* RPL_WITH_DAO_ACK */
}
/*---------------------------------------------------------------------------*/
#if RPL_WITH_DAO_ACK
void
rpl_process_dao_ack(uint8_t sequence, uint8_t status)
{
/* Update dao_last_acked_seqno */
if(rpl_lollipop_greater_than(sequence, curr_instance.dag.dao_last_acked_seqno)) {
curr_instance.dag.dao_last_acked_seqno = sequence;
}
/* Is this an ACK for our last DAO? */
if(sequence == curr_instance.dag.dao_last_seqno) {
/* stop the retransmit timer when the ACK arrived */
curr_instance.dag.is_reachable = status < RPL_DAO_ACK_UNABLE_TO_ACCEPT;
#if RPL_REPAIR_ON_DAO_NACK
if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) {
/*
* Failed the DAO transmission - need to remove the default route.
* Trigger a local repair since we can not get our DAO in.
*/
rpl_local_repair("DAO NACK");
}
#endif
}
}
#endif /* RPL_WITH_DAO_ACK */
/*---------------------------------------------------------------------------*/
int
rpl_process_hbh(rpl_parent_t *sender, uint16_t sender_rank, int loop_detected, int rank_error_signaled)
{
int drop = 0;
if(loop_detected) {
if(rank_error_signaled) {
#if RPL_LOOP_ERROR_DROP
/* Drop packet and reset trickle timer, as per RFC6550 - 11.2.2.2 */
rpl_timers_dio_reset("HBH error");
PRINTF("RPL: rank error and loop detected, dropping\n");
drop = 1;
#endif /* RPL_LOOP_ERROR_DROP */
}
/* Attempt to repair the loop by sending a unicast DIO back to the sender
* so that it gets a fresh update of our rank. */
rpl_timers_schedule_unicast_dio(sender);
}
if(rank_error_signaled) {
/* A rank error was signalled, attempt to repair it by updating
* the sender's rank from ext header */
if(sender != NULL) {
sender->rank = sender_rank;
/* Select DAG and preferred parent. In case of a parent switch,
the new parent will be used to forward the current packet. */
rpl_dag_update_state();
}
}
return !drop;
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_init_root(uint8_t instance_id, uip_ipaddr_t *dag_id,
uip_ipaddr_t *prefix, unsigned prefix_len, uint8_t prefix_flags)
{
uint8_t version = RPL_LOLLIPOP_INIT;
/* If we're in an instance, first leave it */
if(curr_instance.used) {
/* We were already root. Increment version */
if(uip_ipaddr_cmp(&curr_instance.dag.dag_id, dag_id)) {
version = curr_instance.dag.version;
RPL_LOLLIPOP_INCREMENT(version);
}
leave_dag();
}
/* Init DAG and instance */
init_dag(instance_id, dag_id, RPL_OF_OCP, prefix, prefix_len, prefix_flags);
/* Instance */
curr_instance.mop = RPL_MOP_DEFAULT;
curr_instance.max_rankinc = RPL_MAX_RANKINC;
curr_instance.min_hoprankinc = RPL_MIN_HOPRANKINC;
curr_instance.dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
curr_instance.dio_intmin = RPL_DIO_INTERVAL_MIN;
curr_instance.dio_redundancy = RPL_DIO_REDUNDANCY;
curr_instance.default_lifetime = RPL_DEFAULT_LIFETIME;
curr_instance.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
/* DAG */
curr_instance.dag.preference = RPL_PREFERENCE;
curr_instance.dag.grounded = RPL_GROUNDED;
curr_instance.dag.version = version;
curr_instance.dag.rank = ROOT_RANK;
curr_instance.dag.lifetime = RPL_LIFETIME(RPL_INFINITE_LIFETIME);
curr_instance.dag.dio_intcurrent = RPL_DIO_INTERVAL_MIN;
rpl_timers_dio_reset("Init root");
PRINTF("RPL: created DAG with instance ID %u, DAG ID ",
curr_instance.instance_id);
PRINT6ADDR(&curr_instance.dag.dag_id);
PRINTF(", rank %u\n", curr_instance.dag.rank);
ANNOTATE("#A root=%u\n", curr_instance.dag.dag_id.u8[sizeof(curr_instance.dag.dag_id) - 1]);
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_init(void)
{
memset(&curr_instance, 0, sizeof(curr_instance));
rpl_parent_init();
}
/*---------------------------------------------------------------------------*/
/** @} */

165
core/net/rpl-lite/rpl-dag.h Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Header file for rpl-dag module
* \author
* Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon DUquennoy <simon.duquennoy@inria.fr>
*
*/
#ifndef RPL_DAG_H
#define RPL_DAG_H
/********** Includes **********/
#include "uip.h"
/**
* \addtogroup uip6
* @{
*/
/********** Public functions **********/
/**
* A function called periodically. Used to age the DAG (decrease lifetime
* and expire DAG accordingly)
*
* \param seconds The number of seconds elapsted since last call
*/
void rpl_dag_periodic(unsigned seconds);
/**
* Triggers a RPL global repair
*/
void rpl_global_repair(void);
/**
* Triggers a RPL local repair
*
* \param str A textual description of the cause for triggering a repair
*/
void rpl_local_repair(const char *str);
/**
* Tells whether a given global IPv6 address is in our current DAG
*
* \param addr The global IPv6 address to be tested
* \return 1 if addr is in our current DAG, 0 otherwise
*/
int rpl_is_addr_in_our_dag(const uip_ipaddr_t *addr);
/**
* Initializes DAG internal structure for a root node
*
* \param instance_id The instance ID
* \param dag_id The DAG ID
* \param prefix The prefix
* \param prefix_len The prefix length
* \param flags The prefix flags (from DIO)
*/
void rpl_dag_init_root(uint8_t instance_id, uip_ipaddr_t *dag_id,
uip_ipaddr_t *prefix, unsigned prefix_len, uint8_t flags);
/**
* Returns pointer to the default instance (for compatibility with legagy RPL code)
*
* \return A pointer to the only supported instance
*/
rpl_instance_t *rpl_get_default_instance(void);
/**
* Returns pointer to any DAG (for compatibility with legagy RPL code)
*
* \return A pointer to the only supported DAG
*/
rpl_dag_t *rpl_get_any_dag(void);
/**
* Processes Hop-by-Hop (HBH) Extension Header of a packet currently being forwrded.
*
* \param sender The IPv6 address of the originator
* \param sender_rank The rank advertised by the sender in the HBH header
* \param loop_detected 1 if we could detect a loop while forwarding, 0 otherwise
* \param rank_error_signaled 1 if the HBH header advertises a rank error, 0 otherwise
* \return 1 if the packet is to be forwarded, 0 if it is to be dropped
*/
int rpl_process_hbh(rpl_parent_t *sender, uint16_t sender_rank, int loop_detected, int rank_error_signaled);
/**
* Processes incoming DIS
*
* \param from The IPv6 address of the originator
* \param is_multicast Set to 1 for multicast DIS, 0 for unicast DIS
*/
void rpl_process_dis(uip_ipaddr_t *from, int is_multicast);
/**
* Processes incoming DIO
*
* \param from The IPv6 address of the originator
* \param dio A pointer to a parsed DIO
*/
void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio);
/**
* Processes incoming DAO
*
* \param from The IPv6 address of the originator
* \param dao A pointer to a parsed DAO
*/
void rpl_process_dao(uip_ipaddr_t *from, rpl_dao_t *dao);
/**
* Processes incoming DAO-ACK
*
* \param sequence The DAO-ACK sequence number
* \param status The DAO-ACK status (see RPL_DAO_ACK_* defines)
*/
void rpl_process_dao_ack(uint8_t sequence, uint8_t status);
/**
* Updates RPL interl state from neighbor/parent tables:
* selects preferred parent, updated rank & metreic container,
* triggers control traffic accordingly and updates uIP6 internal state.
*/
void rpl_dag_update_state(void);
/**
* Initializes rpl-dag module
*/
void rpl_dag_init(void);
/** @} */
#endif /* RPL_DAG_H */

View File

@ -0,0 +1,579 @@
/*
* Copyright (c) 2009, Swedish Institute of Computer Science.
* 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
* Management of extension headers for ContikiRPL.
*
* \author Vincent Brillault <vincent.brillault@imag.fr>,
* Joakim Eriksson <joakime@sics.se>,
* Niclas Finne <nfi@sics.se>,
* Nicolas Tsiftes <nvt@sics.se>,
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
/**
* \addtogroup uip6
* @{
*/
#include "rpl.h"
#include "net/packetbuf.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/*---------------------------------------------------------------------------*/
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#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_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr)
{
uint8_t *uip_next_hdr;
int last_uip_ext_len = uip_ext_len;
rpl_ns_node_t *dest_node;
rpl_ns_node_t *root_node;
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_HBHO:
case UIP_PROTO_DESTO:
/*
* As per RFC 2460, only the Hop-by-Hop Options header and
* Destination Options header can appear before the Routing header.
*/
uip_next_hdr = &UIP_EXT_BUF->next;
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
break;
default:
uip_next_hdr = NULL;
break;
}
}
if(!rpl_is_addr_in_our_dag(&UIP_IP_BUF->destipaddr)) {
return 0;
}
root_node = rpl_ns_get_node(&curr_instance.dag.dag_id);
dest_node = rpl_ns_get_node(&UIP_IP_BUF->destipaddr);
if((uip_next_hdr != NULL && *uip_next_hdr == UIP_PROTO_ROUTING
&& UIP_RH_BUF->routing_type == RPL_RH_TYPE_SRH) ||
(dest_node != NULL && root_node != NULL &&
dest_node->parent == root_node)) {
/* Routing header found or the packet destined for a direct child of the root.
* The next hop should be already copied as the IPv6 destination
* address, via rpl_ext_header_srh_update. 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;
}
PRINTF("RPL: packet needs multi-hop downward routing but SRH not found\n");
uip_ext_len = last_uip_ext_len;
return 0;
}
/*---------------------------------------------------------------------------*/
int
rpl_ext_header_srh_update(void)
{
uint8_t *uip_next_hdr;
int last_uip_ext_len = uip_ext_len;
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;
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_HBHO:
case UIP_PROTO_DESTO:
/*
* As per RFC 2460, only the Hop-by-Hop Options header and
* Destination Options header can appear before the Routing header.
*/
uip_next_hdr = &UIP_EXT_BUF->next;
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
break;
default:
uip_next_hdr = NULL;
break;
}
}
if(uip_next_hdr == NULL || *uip_next_hdr != UIP_PROTO_ROUTING
|| UIP_RH_BUF->routing_type != RPL_RH_TYPE_SRH) {
PRINTF("RPL: SRH not found\n");
uip_ext_len = last_uip_ext_len;
return 0;
}
/* Parse SRH */
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);
/* Update SRH in-place */
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 with 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;
}
/*---------------------------------------------------------------------------*/
/* Utility function for SRH. Counts the number of bytes in common between
* two addresses at p1 and p2. */
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;
}
/*---------------------------------------------------------------------------*/
/* Used by rpl_ext_header_update to insert a RPL SRH extension header. This
* is used at the root, to initiate downward routing. Returns 1 on success,
* 0 on failure.
*/
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;
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 */
if(!rpl_is_addr_in_our_dag(&UIP_IP_BUF->destipaddr)) {
PRINTF("RPL: SRH DAG not found\n");
return 0;
}
dest_node = rpl_ns_get_node(&UIP_IP_BUF->destipaddr);
if(dest_node == NULL) {
/* The destination is not found, skip SRH insertion */
return 1;
}
root_node = rpl_ns_get_node(&curr_instance.dag.dag_id);
if(root_node == NULL) {
PRINTF("RPL: SRH root node not found\n");
return 0;
}
if(!rpl_ns_is_addr_reachable(&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;
if(node == root_node) {
PRINTF("RPL: SRH no need to insert SRH\n");
return 1;
}
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++;
}
/* 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;
}
/*---------------------------------------------------------------------------*/
int
rpl_ext_header_hbh_update(int uip_ext_opt_offset)
{
int down;
int rank_error_signaled;
int loop_detected;
uint16_t sender_rank;
uint8_t sender_closer;
rpl_parent_t *sender;
if(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) {
PRINTF("RPL: hop-by-hop extension header has wrong size or type (%u %u %u)\n",
UIP_HBHO_BUF->len, UIP_EXT_HDR_OPT_RPL_BUF->opt_type,
UIP_EXT_HDR_OPT_RPL_BUF->opt_len);
return 0; /* Drop */
}
if(!curr_instance.used || curr_instance.instance_id != UIP_EXT_HDR_OPT_RPL_BUF->instance) {
PRINTF("RPL: unknown instance: %u\n",
UIP_EXT_HDR_OPT_RPL_BUF->instance);
return 0; /* Drop */
}
if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
PRINTF("RPL: forward error!\n");
return 0; /* Drop */
}
down = (UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) ? 1 : 0;
sender_rank = UIP_HTONS(UIP_EXT_HDR_OPT_RPL_BUF->senderrank);
sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER));
rank_error_signaled = (UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) ? 1 : 0;
sender_closer = sender_rank < curr_instance.dag.rank;
loop_detected = (down && !sender_closer) || (!down && sender_closer);
PRINTF("RPL: packet going %s, sender closer %d (%d < %d), rank error %u, loop detected %u\n",
down == 1 ? "down" : "up", sender_closer, sender_rank,
curr_instance.dag.rank, rank_error_signaled, loop_detected);
if(loop_detected) {
/* Set forward error flag */
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR;
}
return rpl_process_hbh(sender, sender_rank, loop_detected, rank_error_signaled);
}
/*---------------------------------------------------------------------------*/
/* In-place update of the RPL HBH extension header, when already present
* in the uIP packet. Used by insert_hbh_header and rpl_ext_header_update.
* Returns 1 on success, 0 on failure. */
static int
update_hbh_header(void)
{
int uip_ext_opt_offset;
int last_uip_ext_len;
last_uip_ext_len = uip_ext_len;
uip_ext_len = 0;
uip_ext_opt_offset = 2;
if(UIP_IP_BUF->proto == UIP_PROTO_HBHO && UIP_EXT_HDR_OPT_RPL_BUF->opt_type == UIP_EXT_HDR_OPT_RPL) {
if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
|| UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
PRINTF("RPL: hop-by-hop extension header has wrong size (%u %u)\n",
UIP_EXT_HDR_OPT_RPL_BUF->opt_len, uip_ext_len);
return 0; /* Drop */
}
if(!curr_instance.used || curr_instance.instance_id != UIP_EXT_HDR_OPT_RPL_BUF->instance) {
PRINTF("RPL: unable to add/update hop-by-hop extension header: incorrect instance\n");
uip_ext_len = last_uip_ext_len;
return 0; /* Drop */
}
/* Update sender rank and instance, will update flags next */
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(curr_instance.dag.rank);
UIP_EXT_HDR_OPT_RPL_BUF->instance = curr_instance.instance_id;
}
uip_ext_len = last_uip_ext_len;
return 1;
}
/*---------------------------------------------------------------------------*/
/* Used by rpl_ext_header_update on packets without an HBH extension header,
* for packets initated by non-root nodes.
* Inserts and initalizes (via update_hbh_header) a RPL HBH ext header.
* Returns 1 on success, 0 on failure. */
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->senderrank = UIP_HTONS(curr_instance.dag.rank);
UIP_EXT_HDR_OPT_RPL_BUF->instance = curr_instance.instance_id;
uip_len += RPL_HOP_BY_HOP_LEN;
temp_len = UIP_IP_BUF->len[1];
UIP_IP_BUF->len[1] += RPL_HOP_BY_HOP_LEN;
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;
/* Update header before returning */
return update_hbh_header();
}
/*---------------------------------------------------------------------------*/
int
rpl_ext_header_update(void)
{
if(!curr_instance.used
|| uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr)
|| uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
return 1;
}
if(rpl_dag_root_is_root()) {
/* At the root, remove headers if any, and insert SRH or HBH
* (SRH is inserted only if the destination is in the DODAG) */
rpl_ext_header_remove();
if(rpl_is_addr_in_our_dag(&UIP_IP_BUF->destipaddr)) {
/* dest is in a DODAG; the packet is going down. */
if(curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
return insert_srh_header();
} else {
PRINTF("RPL: packet going down at root, but no support for downward routing\n");
return 0; /* No support for downward routes */
}
} else {
/* dest is outside of DODAGs; no ext header is needed. */
return 1;
}
} else {
if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)
&& UIP_IP_BUF->ttl == uip_ds6_if.cur_hop_limit) {
/* Insert HBH option at source. Checking the address is not sufficient because
* in non-storing mode, a packet may go up and then down the same path again */
return insert_hbh_header();
} else {
/* Update HBH option at forwarders */
return update_hbh_header();
}
}
}
/*---------------------------------------------------------------------------*/
void
rpl_ext_header_remove(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;
/* Look for hop-by-hop and routing headers */
while(uip_next_hdr != NULL) {
switch(*uip_next_hdr) {
case UIP_PROTO_HBHO:
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 -= 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]--;
}
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;
case UIP_PROTO_DESTO:
/*
* As per RFC 2460, any header other than the Destination
* Options header does not appear between the Hop-by-Hop
* Options header and the Routing header.
*
* We're moving to the next header only if uip_next_hdr has
* UIP_PROTO_DESTO. Otherwise, we'll return.
*/
/* Move to next header */
uip_next_hdr = &UIP_EXT_BUF->next;
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
default:
return;
}
}
}
/** @}*/

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2017, 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
* Header file for rpl-ext-header
*
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#ifndef RPL_EXT_HEADER_H_
#define RPL_EXT_HEADER_H_
/**
* \addtogroup uip6
* @{
*/
/********** Public functions **********/
/**
* Look for next hop from SRH of current uIP packet.
*
* \param ipaddr A pointer to the address where to store the next hop.
* \return 1 if a next hop was found, 0 otherwise
*/
int rpl_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr);
/**
* Process and update SRH in-place,
* i.e. internal address swapping as per RFC6554
* \return 1 if SRH found, 0 otherwise
*/
int rpl_ext_header_srh_update(void);
/**
* Process and update the RPL extension headers of the current uIP packet.
*
* \param uip_ext_opt_offset The offset within the uIP packet where
* extension headers start
* \return 1 in case the packet is valid and to be processed further,
* 0 in case the packet must be dropped.
*/
int rpl_ext_header_hbh_update(int uip_ext_opt_offset);
/**
* Adds/updates RPL extension headers to current uIP packet.
*
* \return 1 in case of success, 0 otherwise
*/
int rpl_ext_header_update(void);
/**
* Removes all RPL extension headers.
*/
void rpl_ext_header_remove(void);
/** @} */
#endif /* RPL_EXT_HEADER_H_ */

View File

@ -0,0 +1,689 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* ICMP6 I/O for RPL control messages.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon Duquennoy <simon.duquennoy@inria.fr>
* Contributors: Niclas Finne <nfi@sics.se>, Joel Hoglund <joel@sics.se>,
* Mathieu Pouillot <m.pouillot@watteco.com>,
* George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
*/
/**
* \addtogroup uip6
* @{
*/
#include "rpl.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/packetbuf.h"
#include "lib/random.h"
#include <limits.h>
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/*---------------------------------------------------------------------------*/
#define RPL_DIO_GROUNDED 0x80
#define RPL_DIO_MOP_SHIFT 3
#define RPL_DIO_MOP_MASK 0x38
#define RPL_DIO_PREFERENCE_MASK 0x07
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
#define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len])
/*---------------------------------------------------------------------------*/
static void dis_input(void);
static void dio_input(void);
static void dao_input(void);
/*---------------------------------------------------------------------------*/
/* Initialize RPL ICMPv6 message handlers */
UIP_ICMP6_HANDLER(dis_handler, ICMP6_RPL, RPL_CODE_DIS, dis_input);
UIP_ICMP6_HANDLER(dio_handler, ICMP6_RPL, RPL_CODE_DIO, dio_input);
UIP_ICMP6_HANDLER(dao_handler, ICMP6_RPL, RPL_CODE_DAO, dao_input);
#if RPL_WITH_DAO_ACK
static void dao_ack_input(void);
UIP_ICMP6_HANDLER(dao_ack_handler, ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_input);
#endif /* RPL_WITH_DAO_ACK */
/*---------------------------------------------------------------------------*/
static uint32_t
get32(uint8_t *buffer, int pos)
{
return ((uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
(uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3]);
}
/*---------------------------------------------------------------------------*/
static void
set32(uint8_t *buffer, int pos, uint32_t value)
{
buffer[pos++] = value >> 24;
buffer[pos++] = (value >> 16) & 0xff;
buffer[pos++] = (value >> 8) & 0xff;
buffer[pos++] = value & 0xff;
}
/*---------------------------------------------------------------------------*/
static uint16_t
get16(uint8_t *buffer, int pos)
{
return (uint16_t)buffer[pos] << 8 | buffer[pos + 1];
}
/*---------------------------------------------------------------------------*/
static void
set16(uint8_t *buffer, int pos, uint16_t value)
{
buffer[pos++] = value >> 8;
buffer[pos++] = value & 0xff;
}
/*---------------------------------------------------------------------------*/
uip_ds6_nbr_t *
rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void *data)
{
uip_ds6_nbr_t *nbr;
if((nbr = uip_ds6_nbr_lookup(from)) == NULL) {
if((nbr = uip_ds6_nbr_add(from, (uip_lladdr_t *)
packetbuf_addr(PACKETBUF_ADDR_SENDER),
0, NBR_REACHABLE, reason, data)) == NULL) {
PRINTF("RPL: could not add neighbor to cache ");
PRINT6ADDR(from);
PRINTF(", ");
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
PRINTF("\n");
}
}
return nbr;
}
/*---------------------------------------------------------------------------*/
static void
dis_input(void)
{
if(!curr_instance.used) {
PRINTF("RPL: dis_input: not in an instance yet, discard\n");
goto discard;
}
PRINTF("RPL: received a DIS from ");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
rpl_process_dis(&UIP_IP_BUF->srcipaddr, uip_is_addr_mcast(&UIP_IP_BUF->destipaddr));
discard:
uip_clear_buf();
}
/*---------------------------------------------------------------------------*/
void
rpl_icmp6_dis_output(uip_ipaddr_t *addr)
{
unsigned char *buffer;
/* Make sure we're up-to-date before sending data out */
rpl_dag_update_state();
buffer = UIP_ICMP_PAYLOAD;
buffer[0] = buffer[1] = 0;
if(addr == NULL) {
addr = &rpl_multicast_addr;
}
PRINTF("RPL: sending a DIS to ");
PRINT6ADDR(addr);
PRINTF("\n");
uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIS, 2);
}
/*---------------------------------------------------------------------------*/
static void
dio_input(void)
{
unsigned char *buffer;
uint8_t buffer_length;
rpl_dio_t dio;
uint8_t subopt_type;
int i;
int len;
uip_ipaddr_t from;
memset(&dio, 0, sizeof(dio));
/* Set default values in case the DIO configuration option is missing. */
dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
dio.dag_redund = RPL_DIO_REDUNDANCY;
dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
dio.dag_max_rankinc = RPL_MAX_RANKINC;
dio.ocp = RPL_OF_OCP;
dio.default_lifetime = RPL_DEFAULT_LIFETIME;
dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);
buffer_length = uip_len - uip_l3_icmp_hdr_len;
/* Process the DIO base option. */
i = 0;
buffer = UIP_ICMP_PAYLOAD;
dio.instance_id = buffer[i++];
dio.version = buffer[i++];
dio.rank = get16(buffer, i);
i += 2;
dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;
dio.dtsn = buffer[i++];
/* two reserved bytes */
i += 2;
memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
i += sizeof(dio.dag_id);
/* Check if there are any DIO suboptions. */
for(; i < buffer_length; i += len) {
subopt_type = buffer[i];
if(subopt_type == RPL_OPTION_PAD1) {
len = 1;
} else {
/* Suboption with a two-byte header + payload */
len = 2 + buffer[i + 1];
}
if(len + i > buffer_length) {
PRINTF("RPL: dio_input: malformed packet, discard\n");
goto discard;
}
switch(subopt_type) {
case RPL_OPTION_DAG_METRIC_CONTAINER:
if(len < 6) {
PRINTF("RPL: dio_input: invalid DAG MC, len %u, discard\n", len);
goto discard;
}
dio.mc.type = buffer[i + 2];
dio.mc.flags = buffer[i + 3] << 1;
dio.mc.flags |= buffer[i + 4] >> 7;
dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
dio.mc.prec = buffer[i + 4] & 0xf;
dio.mc.length = buffer[i + 5];
if(dio.mc.type == RPL_DAG_MC_NONE) {
/* No metric container: do nothing */
} else if(dio.mc.type == RPL_DAG_MC_ETX) {
dio.mc.obj.etx = get16(buffer, i + 6);
} else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
dio.mc.obj.energy.flags = buffer[i + 6];
dio.mc.obj.energy.energy_est = buffer[i + 7];
} else {
PRINTF("RPL: dio_input: unsupported DAG MC type %u, discard\n", (unsigned)dio.mc.type);
goto discard;
}
break;
case RPL_OPTION_ROUTE_INFO:
if(len < 9) {
PRINTF("RPL: dio_input: invalid destination prefix option, len %u, discard\n", len);
goto discard;
}
/* The flags field includes the preference value. */
dio.destination_prefix.length = buffer[i + 2];
dio.destination_prefix.flags = buffer[i + 3];
dio.destination_prefix.lifetime = get32(buffer, i + 4);
if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
dio.destination_prefix.length <= 128) {
memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
(dio.destination_prefix.length + 7) / 8);
} else {
PRINTF("RPL: dio_input: invalid route info option, len %u, discard\n", len);
goto discard;
}
break;
case RPL_OPTION_DAG_CONF:
if(len != 16) {
PRINTF("RPL: dio_input: invalid DAG configuration option, len %u, discard\n", len);
goto discard;
}
/* Path control field not yet implemented - at i + 2 */
dio.dag_intdoubl = buffer[i + 3];
dio.dag_intmin = buffer[i + 4];
dio.dag_redund = buffer[i + 5];
dio.dag_max_rankinc = get16(buffer, i + 6);
dio.dag_min_hoprankinc = get16(buffer, i + 8);
dio.ocp = get16(buffer, i + 10);
/* buffer + 12 is reserved */
dio.default_lifetime = buffer[i + 13];
dio.lifetime_unit = get16(buffer, i + 14);
break;
case RPL_OPTION_PREFIX_INFO:
if(len != 32) {
PRINTF("RPL: dio_input: invalid DAG prefix info, len %u, discard\n", len);
goto discard;
}
dio.prefix_info.length = buffer[i + 2];
dio.prefix_info.flags = buffer[i + 3];
/* valid lifetime is ingnored for now - at i + 4 */
/* preferred lifetime stored in lifetime */
dio.prefix_info.lifetime = get32(buffer, i + 8);
/* 32-bit reserved at i + 12 */
memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
break;
default:
PRINTF("RPL: dio_input: unsupported suboption type in DIO: %u, discard\n", (unsigned)subopt_type);
goto discard;
}
}
PRINTF("RPL: received a %s-DIO from ",
uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) ? "multicast" : "unicast");
PRINT6ADDR(&from);
PRINTF(", instance_id %u, DAG ID ", (unsigned)dio.instance_id);
PRINT6ADDR(&dio.dag_id);
PRINTF(", version %u, rank %u\n",
(unsigned)dio.version,
(unsigned)dio.rank);
rpl_process_dio(&from, &dio);
discard:
uip_clear_buf();
}
/*---------------------------------------------------------------------------*/
void
rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr)
{
unsigned char *buffer;
int pos;
uip_ipaddr_t *addr = uc_addr;
/* Make sure we're up-to-date before sending data out */
rpl_dag_update_state();
#if RPL_LEAF_ONLY
/* In leaf mode, we only send DIO messages as unicasts in response to
unicast DIS messages. */
if(uc_addr == NULL) {
PRINTF("RPL: leaf-only mode: will not send multicast DIO\n");
return;
}
#endif /* RPL_LEAF_ONLY */
/* DAG Information Object */
pos = 0;
buffer = UIP_ICMP_PAYLOAD;
buffer[pos++] = curr_instance.instance_id;
buffer[pos++] = curr_instance.dag.version;
#if RPL_LEAF_ONLY
set16(buffer, pos, RPL_INFINITE_RANK);
#else /* RPL_LEAF_ONLY */
set16(buffer, pos, curr_instance.dag.rank);
#endif /* RPL_LEAF_ONLY */
pos += 2;
buffer[pos] = 0;
if(curr_instance.dag.grounded) {
buffer[pos] |= RPL_DIO_GROUNDED;
}
buffer[pos] |= curr_instance.mop << RPL_DIO_MOP_SHIFT;
buffer[pos] |= curr_instance.dag.preference & RPL_DIO_PREFERENCE_MASK;
pos++;
buffer[pos++] = curr_instance.dtsn_out;
/* reserved 2 bytes */
buffer[pos++] = 0; /* flags */
buffer[pos++] = 0; /* reserved */
memcpy(buffer + pos, &curr_instance.dag.dag_id, sizeof(curr_instance.dag.dag_id));
pos += 16;
#if !RPL_LEAF_ONLY
if(curr_instance.mc.type != RPL_DAG_MC_NONE) {
buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
buffer[pos++] = 6;
buffer[pos++] = curr_instance.mc.type;
buffer[pos++] = curr_instance.mc.flags >> 1;
buffer[pos] = (curr_instance.mc.flags & 1) << 7;
buffer[pos++] |= (curr_instance.mc.aggr << 4) | curr_instance.mc.prec;
if(curr_instance.mc.type == RPL_DAG_MC_ETX) {
buffer[pos++] = 2;
set16(buffer, pos, curr_instance.mc.obj.etx);
pos += 2;
} else if(curr_instance.mc.type == RPL_DAG_MC_ENERGY) {
buffer[pos++] = 2;
buffer[pos++] = curr_instance.mc.obj.energy.flags;
buffer[pos++] = curr_instance.mc.obj.energy.energy_est;
} else {
PRINTF("RPL: unable to send DIO because of unsupported DAG MC type %u\n",
(unsigned)curr_instance.mc.type);
return;
}
}
#endif /* !RPL_LEAF_ONLY */
/* Always add a DAG configuration option. */
buffer[pos++] = RPL_OPTION_DAG_CONF;
buffer[pos++] = 14;
buffer[pos++] = 0; /* No Auth, PCS = 0 */
buffer[pos++] = curr_instance.dio_intdoubl;
buffer[pos++] = curr_instance.dio_intmin;
buffer[pos++] = curr_instance.dio_redundancy;
set16(buffer, pos, curr_instance.max_rankinc);
pos += 2;
set16(buffer, pos, curr_instance.min_hoprankinc);
pos += 2;
/* OCP is in the DAG_CONF option */
set16(buffer, pos, curr_instance.of->ocp);
pos += 2;
buffer[pos++] = 0; /* reserved */
buffer[pos++] = curr_instance.default_lifetime;
set16(buffer, pos, curr_instance.lifetime_unit);
pos += 2;
/* Check if we have a prefix to send also. */
if(curr_instance.dag.prefix_info.length > 0) {
buffer[pos++] = RPL_OPTION_PREFIX_INFO;
buffer[pos++] = 30; /* always 30 bytes + 2 long */
buffer[pos++] = curr_instance.dag.prefix_info.length;
buffer[pos++] = curr_instance.dag.prefix_info.flags;
set32(buffer, pos, curr_instance.dag.prefix_info.lifetime);
pos += 4;
set32(buffer, pos, curr_instance.dag.prefix_info.lifetime);
pos += 4;
memset(&buffer[pos], 0, 4);
pos += 4;
memcpy(&buffer[pos], &curr_instance.dag.prefix_info.prefix, 16);
pos += 16;
}
#if !RPL_LEAF_ONLY
addr = addr != NULL ? addr : &rpl_multicast_addr;
#endif /* RPL_LEAF_ONLY */
PRINTF("RPL: sending a %s-DIO with rank %u to ",
uc_addr != NULL ? "unicast" : "multicast",
(unsigned)curr_instance.dag.rank);
PRINT6ADDR(addr);
PRINTF("\n");
uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIO, pos);
}
/*---------------------------------------------------------------------------*/
static void
dao_input(void)
{
struct rpl_dao dao;
uint8_t subopt_type;
unsigned char *buffer;
uint8_t buffer_length;
int pos;
int len;
int i;
uip_ipaddr_t from;
memset(&dao, 0, sizeof(dao));
dao.instance_id = UIP_ICMP_PAYLOAD[0];
if(!curr_instance.used || curr_instance.instance_id != dao.instance_id) {
PRINTF("RPL: dao_input: unknown RPL instance %u, discard\n", dao.instance_id);
goto discard;
}
uip_ipaddr_copy(&from, &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;
pos++; /* instance ID */
dao.lifetime = curr_instance.default_lifetime;
dao.flags = buffer[pos++];
pos++; /* reserved */
dao.sequence = buffer[pos++];
/* Is the DAG ID present? */
if(dao.flags & RPL_DAO_D_FLAG) {
if(memcmp(&curr_instance.dag.dag_id, &buffer[pos], sizeof(curr_instance.dag.dag_id))) {
PRINTF("RPL: dao_input: different DAG ID ");
PRINT6ADDR((uip_ipaddr_t *)&buffer[pos]);
PRINTF(", discard\n");
goto discard;
}
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. */
dao.prefixlen = buffer[i + 3];
memset(&dao.prefix, 0, sizeof(dao.prefix));
memcpy(&dao.prefix, buffer + i + 4, (dao.prefixlen + 7) / CHAR_BIT);
break;
case RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
/* pathcontrol = buffer[i + 3];
pathsequence = buffer[i + 4];*/
dao.lifetime = buffer[i + 5];
if(len >= 20) {
memcpy(&dao.parent_addr, buffer + i + 6, 16);
}
break;
}
}
/* Destination Advertisement Object */
PRINTF("RPL: received a %sDAO from ", dao.lifetime == 0 ? "No-path " : "");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF(", lifetime %u, prefix ", dao.lifetime);
PRINT6ADDR(&dao.prefix);
PRINTF(", prefix length %u, parent ", dao.prefixlen);
PRINT6ADDR(&dao.parent_addr);
PRINTF(" \n");
rpl_process_dao(&from, &dao);
discard:
uip_clear_buf();
}
/*---------------------------------------------------------------------------*/
void
rpl_icmp6_dao_output(uint8_t lifetime)
{
unsigned char *buffer;
uint8_t prefixlen;
int pos;
uip_ipaddr_t *dest_ipaddr = NULL;
const uip_ipaddr_t *prefix = rpl_get_global_address();
uip_ipaddr_t *parent_ipaddr = rpl_parent_get_ipaddr(curr_instance.dag.preferred_parent);
/* Make sure we're up-to-date before sending data out */
rpl_dag_update_state();
if(!curr_instance.used || curr_instance.dag.preferred_parent == NULL
|| prefix == NULL || parent_ipaddr == NULL) {
PRINTF("RPL: rpl_icmp6_dao_output: node not ready to send a DAO (used %u, pref parent %p, prefix %p, parent_ipaddr %p)\n",
curr_instance.used, curr_instance.dag.preferred_parent, prefix, parent_ipaddr);
return;
}
buffer = UIP_ICMP_PAYLOAD;
pos = 0;
buffer[pos++] = curr_instance.instance_id;
buffer[pos] = 0;
#if RPL_WITH_DAO_ACK
if(lifetime != 0) {
buffer[pos] |= RPL_DAO_K_FLAG;
}
#endif /* RPL_WITH_DAO_ACK */
++pos;
buffer[pos++] = 0; /* reserved */
buffer[pos++] = curr_instance.dag.dao_curr_seqno;
/* create target subopt */
prefixlen = sizeof(*prefix) * CHAR_BIT;
buffer[pos++] = RPL_OPTION_TARGET;
buffer[pos++] = 2 + ((prefixlen + 7) / CHAR_BIT);
buffer[pos++] = 0; /* reserved */
buffer[pos++] = prefixlen;
memcpy(buffer + pos, prefix, (prefixlen + 7) / CHAR_BIT);
pos += ((prefixlen + 7) / CHAR_BIT);
/* Create a transit information sub-option. */
buffer[pos++] = RPL_OPTION_TRANSIT;
buffer[pos++] = (curr_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(curr_instance.mop != RPL_MOP_NON_STORING) {
/* Send DAO to parent */
dest_ipaddr = parent_ipaddr;
} else {
/* Include parent global IP address */
memcpy(buffer + pos, &curr_instance.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 = &curr_instance.dag.dag_id;
}
PRINTF("RPL: sending a %sDAO seqno %u, tx count %u, lifetime %u, prefix ",
lifetime == 0 ? "No-path " : "",
curr_instance.dag.dao_curr_seqno, curr_instance.dag.dao_transmissions, lifetime);
PRINT6ADDR(prefix);
PRINTF(" to ");
PRINT6ADDR(dest_ipaddr);
PRINTF(" , parent ");
PRINT6ADDR(parent_ipaddr);
PRINTF("\n");
uip_icmp6_send(dest_ipaddr, ICMP6_RPL, RPL_CODE_DAO, pos);
}
#if RPL_WITH_DAO_ACK
/*---------------------------------------------------------------------------*/
static void
dao_ack_input(void)
{
uint8_t *buffer;
uint8_t instance_id;
uint8_t sequence;
uint8_t status;
buffer = UIP_ICMP_PAYLOAD;
instance_id = buffer[0];
sequence = buffer[2];
status = buffer[3];
if(!curr_instance.used || curr_instance.instance_id != instance_id) {
PRINTF("RPL: dao_ack_input: unknown instance, discard\n");
goto discard;
}
PRINTF("RPL: received a DAO-%s with seqno %d (%d %d) and status %d from ",
status < RPL_DAO_ACK_UNABLE_TO_ACCEPT ? "ACK" : "NACK", sequence,
curr_instance.dag.dao_curr_seqno, curr_instance.dag.dao_curr_seqno, status);
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
rpl_process_dao_ack(sequence, status);
discard:
uip_clear_buf();
}
/*---------------------------------------------------------------------------*/
void
rpl_icmp6_dao_ack_output(uip_ipaddr_t *dest, uint8_t sequence, uint8_t status)
{
unsigned char *buffer;
/* Make sure we're up-to-date before sending data out */
rpl_dag_update_state();
buffer = UIP_ICMP_PAYLOAD;
buffer[0] = curr_instance.instance_id;
buffer[1] = 0;
buffer[2] = sequence;
buffer[3] = status;
PRINTF("RPL: sending a DAO-%s seqno %d to ",
status < RPL_DAO_ACK_UNABLE_TO_ACCEPT ? "ACK" : "NACK", sequence);
PRINT6ADDR(dest);
PRINTF(" with status %d\n", status);
uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
}
#endif /* RPL_WITH_DAO_ACK */
/*---------------------------------------------------------------------------*/
void
rpl_icmp6_init()
{
uip_icmp6_register_input_handler(&dis_handler);
uip_icmp6_register_input_handler(&dio_handler);
uip_icmp6_register_input_handler(&dao_handler);
#if RPL_WITH_DAO_ACK
uip_icmp6_register_input_handler(&dao_ack_handler);
#endif /* RPL_WITH_DAO_ACK */
}
/*---------------------------------------------------------------------------*/
/** @}*/

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2017, 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
* Header file for rpl-ext-header
*
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#ifndef RPL_ICMP6_H_
#define RPL_ICMP6_H_
#include "uip.h"
#include "uip-ds6.h"
/**
* \addtogroup uip6
* @{
*/
/********** Data structures **********/
/* Logical representation of a DAG Information Object (DIO.) */
struct rpl_dio {
uip_ipaddr_t dag_id;
rpl_ocp_t ocp;
rpl_rank_t rank;
uint8_t grounded;
uint8_t mop;
uint8_t preference;
uint8_t version;
uint8_t instance_id;
uint8_t dtsn;
uint8_t dag_intdoubl;
uint8_t dag_intmin;
uint8_t dag_redund;
uint8_t default_lifetime;
uint16_t lifetime_unit;
rpl_rank_t dag_max_rankinc;
rpl_rank_t dag_min_hoprankinc;
rpl_prefix_t destination_prefix;
rpl_prefix_t prefix_info;
struct rpl_metric_container mc;
};
typedef struct rpl_dio rpl_dio_t;
/* Logical representation of a Destination Advertisement Object (DAO.) */
struct rpl_dao {
uip_ipaddr_t parent_addr;
uip_ipaddr_t prefix;
uint16_t sequence;
uint8_t instance_id;
uint8_t lifetime;
uint8_t prefixlen;
uint8_t flags;
};
typedef struct rpl_dao rpl_dao_t;
/********** Public functions **********/
/**
* Updates IPv6 neighbor cache on incoming link-local RPL ICMPv6 messages.
*
* \param from The source link-local IPv6 address
* \param reason What triggered the update (maps to RPL packet types)
* \param data Generic pointer, used for instance to store parsed DIO data
* \return A pointer to the new neighbor cache entry, NULL if there was no space left.
*/
uip_ds6_nbr_t *rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void *data);
/**
* Creates an ICMPv6 DIS packet and sends it. Can be unicast or multicast.
*
* \param addr The link-local address of the target host, if any.
* Else, a multicast DIS will be sent.
*/
void rpl_icmp6_dis_output(uip_ipaddr_t *addr);
/**
* Creates an ICMPv6 DIO packet and sends it. Can be unicast or multicast
*
* \param uc_addr The link-local address of the target host, if any.
* Else, a multicast DIO will be sent.
*/
void rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr);
/**
* Creates an ICMPv6 DAO packet and sends it to the root via the
* current preferred parent, advertising the current preferred parent,
* and with our global address as prefix.
*
* \param lifetime The DAO lifetime. Use 0 to send a No-path DAO
*/
void rpl_icmp6_dao_output(uint8_t lifetime);
/**
* Creates an ICMPv6 DAO-ACK packet and sends it to the originator
* of the ACK.
*
* \param dest The DAO-ACK destination (was source of the DAO)
* \param sequence The sequence number of the DAO being ACKed
* \param status The status of the DAO-ACK (see RPL_DAO_ACK_* defines)
*/
void rpl_icmp6_dao_ack_output(uip_ipaddr_t *dest, uint8_t sequence, uint8_t status);
/**
* Initializes rpl-icmp6 module, registers ICMPv6 handlers for all
* RPL ICMPv6 messages: DIO, DIS, DAO and DAO-ACK
*/
void rpl_icmp6_init(void);
/** @} */
#endif /* RPL_ICMP6_H_ */

View File

@ -0,0 +1,276 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* The Minimum Rank with Hysteresis Objective Function (MRHOF), RFC6719
*
* This implementation uses the estimated number of
* transmissions (ETX) as the additive routing metric,
* and also provides stubs for the energy metric.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
/**
* \addtogroup uip6
* @{
*/
#include "rpl.h"
#include "net/nbr-table.h"
#include "net/link-stats.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/* RFC6551 and RFC6719 do not mandate the use of a specific formula to
* compute the ETX value. This MRHOF implementation relies on the value
* computed by the link-stats module. It has an optional feature,
* RPL_MRHOF_CONF_SQUARED_ETX, that consists in squaring this value.
* This basically penalizes bad links while preserving the semantics of ETX
* (1 = perfect link, more = worse link). As a result, MRHOF will favor
* good links over short paths. Recommended when reliability is a priority.
* Without this feature, a hop with 50% PRR (ETX=2) is equivalent to two
* perfect hops with 100% PRR (ETX=1+1=2). With this feature, the former
* path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. */
#ifdef RPL_MRHOF_CONF_SQUARED_ETX
#define RPL_MRHOF_SQUARED_ETX RPL_MRHOF_CONF_SQUARED_ETX
#else /* RPL_MRHOF_CONF_SQUARED_ETX */
#define RPL_MRHOF_SQUARED_ETX 0
#endif /* RPL_MRHOF_CONF_SQUARED_ETX */
#if !RPL_MRHOF_SQUARED_ETX
/* Configuration parameters of RFC6719. Reject parents that have a higher
* link metric than the following. The default value is 512 but we use 1024. */
#define MAX_LINK_METRIC 1024 /* Eq ETX of 8 */
/* Hysteresis of MRHOF: the rank must differ more than PARENT_SWITCH_THRESHOLD_DIV
* in order to switch preferred parent. Default in RFC6719: 192, eq ETX of 1.5.
* We use a more aggressive setting: 96, eq ETX of 0.75.
*/
#define PARENT_SWITCH_THRESHOLD 96 /* Eq ETX of 0.75 */
#else /* !RPL_MRHOF_SQUARED_ETX */
#define MAX_LINK_METRIC 2048 /* Eq ETX of 4 */
#define PARENT_SWITCH_THRESHOLD 160 /* Eq ETX of 1.25 (results in a churn comparable
to the threshold of 96 in the non-squared case) */
#endif /* !RPL_MRHOF_SQUARED_ETX */
/* Reject parents that have a higher path cost than the following. */
#define MAX_PATH_COST 32768 /* Eq path ETX of 256 */
/*---------------------------------------------------------------------------*/
static void
reset(void)
{
PRINTF("RPL: Reset MRHOF\n");
}
/*---------------------------------------------------------------------------*/
static uint16_t
parent_link_metric(rpl_parent_t *p)
{
const struct link_stats *stats = rpl_parent_get_link_stats(p);
if(stats != NULL) {
#if RPL_MRHOF_SQUARED_ETX
uint32_t squared_etx = ((uint32_t)stats->etx * stats->etx) / LINK_STATS_ETX_DIVISOR;
return (uint16_t)MIN(squared_etx, 0xffff);
#else /* RPL_MRHOF_SQUARED_ETX */
return stats->etx;
#endif /* RPL_MRHOF_SQUARED_ETX */
}
return 0xffff;
}
/*---------------------------------------------------------------------------*/
static uint16_t
parent_path_cost(rpl_parent_t *p)
{
uint16_t base;
if(p == NULL) {
return 0xffff;
}
#if RPL_WITH_MC
/* Handle the different MC types */
switch(curr_instance.mc.type) {
case RPL_DAG_MC_ETX:
base = p->mc.obj.etx;
break;
case RPL_DAG_MC_ENERGY:
base = p->mc.obj.energy.energy_est << 8;
break;
default:
base = p->rank;
break;
}
#else /* RPL_WITH_MC */
base = p->rank;
#endif /* RPL_WITH_MC */
/* path cost upper bound: 0xffff */
return MIN((uint32_t)base + parent_link_metric(p), 0xffff);
}
/*---------------------------------------------------------------------------*/
static rpl_rank_t
rank_via_parent(rpl_parent_t *p)
{
uint16_t min_hoprankinc;
uint16_t path_cost;
if(p == NULL) {
return RPL_INFINITE_RANK;
}
min_hoprankinc = curr_instance.min_hoprankinc;
path_cost = parent_path_cost(p);
/* Rank lower-bound: parent rank + min_hoprankinc */
return MAX(MIN((uint32_t)p->rank + min_hoprankinc, RPL_INFINITE_RANK), path_cost);
}
/*---------------------------------------------------------------------------*/
static int
parent_is_acceptable(rpl_parent_t *p)
{
uint16_t link_metric = parent_link_metric(p);
uint16_t path_cost = parent_path_cost(p);
/* Exclude links with too high link metrics or path cost (RFC6719, 3.2.2) */
return link_metric <= MAX_LINK_METRIC && path_cost <= MAX_PATH_COST;
}
/*---------------------------------------------------------------------------*/
static int
parent_has_usable_link(rpl_parent_t *p)
{
uint16_t link_metric = parent_link_metric(p);
/* Exclude links with too high link metrics */
return link_metric <= MAX_LINK_METRIC;
}
/*---------------------------------------------------------------------------*/
static rpl_parent_t *
best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
{
uint16_t p1_cost;
uint16_t p2_cost;
int p1_is_acceptable;
int p2_is_acceptable;
p1_is_acceptable = p1 != NULL && parent_is_acceptable(p1);
p2_is_acceptable = p2 != NULL && parent_is_acceptable(p2);
if(!p1_is_acceptable) {
return p2_is_acceptable ? p2 : NULL;
}
if(!p2_is_acceptable) {
return p1_is_acceptable ? p1 : NULL;
}
p1_cost = parent_path_cost(p1);
p2_cost = parent_path_cost(p2);
/* Maintain stability of the preferred parent in case of similar ranks. */
if(p1 == curr_instance.dag.preferred_parent || p2 == curr_instance.dag.preferred_parent) {
if(p1_cost < p2_cost + PARENT_SWITCH_THRESHOLD &&
p1_cost > p2_cost - PARENT_SWITCH_THRESHOLD) {
return curr_instance.dag.preferred_parent;
}
}
return p1_cost < p2_cost ? p1 : p2;
}
/*---------------------------------------------------------------------------*/
#if !RPL_WITH_MC
static void
update_metric_container(void)
{
curr_instance.mc.type = RPL_DAG_MC_NONE;
}
#else /* RPL_WITH_MC */
static void
update_metric_container(void)
{
uint16_t path_cost;
uint8_t type;
if(curr_instance.used) {
PRINTF("RPL: cannot update the metric container when not joined\n");
return;
}
if(curr_instance.dag.rank == ROOT_RANK) {
/* Configure MC at root only, other nodes are auto-configured when joining */
curr_instance.mc.type = RPL_DAG_MC;
curr_instance.mc.flags = 0;
curr_instance.mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE;
curr_instance.mc.prec = 0;
path_cost = curr_instance.dag.rank;
} else {
path_cost = parent_path_cost(curr_instance.dag.preferred_parent);
}
/* Handle the different MC types */
switch(curr_instance.mc.type) {
case RPL_DAG_MC_NONE:
break;
case RPL_DAG_MC_ETX:
curr_instance.mc.length = sizeof(curr_instance.mc.obj.etx);
curr_instance.mc.obj.etx = path_cost;
break;
case RPL_DAG_MC_ENERGY:
curr_instance.mc.length = sizeof(curr_instance.mc.obj.energy);
if(curr_instance.dag.rank == ROOT_RANK) {
type = RPL_DAG_MC_ENERGY_TYPE_MAINS;
} else {
type = RPL_DAG_MC_ENERGY_TYPE_BATTERY;
}
curr_instance.mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE;
/* Energy_est is only one byte, use the least significant byte of the path metric. */
curr_instance.mc.obj.energy.energy_est = path_cost >> 8;
break;
default:
PRINTF("RPL: MRHOF, non-supported MC %u\n", curr_instance.mc.type);
break;
}
}
#endif /* RPL_WITH_MC */
/*---------------------------------------------------------------------------*/
rpl_of_t rpl_mrhof = {
reset,
parent_link_metric,
parent_has_usable_link,
parent_is_acceptable,
parent_path_cost,
rank_via_parent,
best_parent,
update_metric_container,
RPL_OCP_MRHOF
};
/** @}*/

View File

@ -0,0 +1,221 @@
/*
* Copyright (c) 2014-2015, Yanzi Networks AB.
* 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 copyright holders 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 COPYRIGHT HOLDERS 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
* COPYRIGHT HOLDERS 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.
*
*/
/**
* \addtogroup uip6
* @{
*/
/**
* \file
*
* Default RPL NBR policy
* decides when to add a new discovered node to the nbr table from RPL.
*
* \author Joakim Eriksson <joakime@sics.se>
* Contributors: Niclas Finne <nfi@sics.se>, Oriol Piñol <oriol@yanzi.se>,
*
*/
#include "rpl.h"
#include "net/nbr-table.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/*
* Policy for neighbor adds
* - one node is locked (default route)
* - max X children (nexthops)
* - max Y "best parents"
* => at least MAX_NBRS - (Y + X + 1) free slots for other.
*
* NOTE: this policy assumes that all neighbors end up being IPv6
* neighbors and are not only MAC neighbors.
*/
#define MAX_CHILDREN (NBR_TABLE_MAX_NEIGHBORS - 2)
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
static int num_parents; /* all nodes that are possible parents */
static int num_children; /* all children that we have as nexthop */
static int num_free;
static linkaddr_t *worst_rank_nbr; /* the parent that has the worst rank */
static rpl_rank_t worst_rank;
/*---------------------------------------------------------------------------*/
#if DEBUG == DEBUG_FULL
/*
* This create a periodic call of the update_nbr function that will print
* useful debugging information when in DEBUG_FULL mode
*/
static void update_nbr(void);
static struct ctimer periodic_timer;
static int timer_init = 0;
static void
handle_periodic_timer(void *ptr)
{
update_nbr();
ctimer_restart(&periodic_timer);
}
#endif /* DEBUG == DEBUG_FULL */
/*---------------------------------------------------------------------------*/
static int
node_is_child(uip_ipaddr_t *addr) {
/* in storing mode this was possible to figure out with uip_ds6_route_is_nexthop.
* Need some replacement mechanism in non-storing context */
return 0;
}
/*---------------------------------------------------------------------------*/
static void
update_nbr(void)
{
uip_ds6_nbr_t *nbr;
rpl_parent_t *parent;
int num_used;
int is_used;
rpl_rank_t rank;
#if DEBUG == DEBUG_FULL
if(!timer_init) {
timer_init = 1;
ctimer_set(&periodic_timer, 60 * CLOCK_SECOND,
&handle_periodic_timer, NULL);
}
#endif /* DEBUG == DEBUG_FULL */
worst_rank = 0;
worst_rank_nbr = NULL;
num_used = 0;
num_parents = 0;
num_children = 0;
nbr = nbr_table_head(ds6_neighbors);
while(nbr != NULL) {
linkaddr_t *lladdr = nbr_table_get_lladdr(ds6_neighbors, nbr);
is_used = 0;
/*
* Check if this neighbor is used as nexthop and therefore being a
* RPL child.
*/
if(node_is_child(&nbr->ipaddr) != 0) {
is_used++;
num_children++;
}
parent = rpl_parent_get_from_lladdr((uip_lladdr_t *)lladdr);
if(parent != NULL) {
num_parents++;
if(curr_instance.dag.preferred_parent == parent) {
/*
* This is the preferred parent for the DAG and must not be removed
* Note: this assumes that only RPL adds default routes.
*/
} else if(is_used == 0 && worst_rank < RPL_INFINITE_RANK &&
parent->rank > 0 &&
(rank = curr_instance.of->rank_via_parent(parent)) > worst_rank) {
/* This is the worst-rank neighbor - this is a good candidate for removal */
worst_rank = rank;
worst_rank_nbr = lladdr;
}
/* add to is_used after evaluation of is_used above */
is_used++;
}
if(is_used == 0) {
/* This neighbor is neither parent or child and can be safely removed */
worst_rank_nbr = lladdr;
worst_rank = RPL_INFINITE_RANK;
}
nbr = nbr_table_next(ds6_neighbors, nbr);
num_used++;
}
/* how many more IP neighbors can be have? */
num_free = NBR_TABLE_MAX_NEIGHBORS - num_used;
PRINTF("RPL nbr-policy: free: %d, children: %d, parents: %d routes: %d\n",
num_free, num_children, num_parents, uip_ds6_route_num_routes());
}
/*---------------------------------------------------------------------------*/
/* Called whenever we get a unicast DIS - e.g. someone that already
have this node in its table - since it is a unicast */
static const linkaddr_t *
find_removable_dis(uip_ipaddr_t *from)
{
update_nbr();
if(num_children < MAX_CHILDREN) {
return worst_rank_nbr;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
static const linkaddr_t *
find_removable_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
{
update_nbr();
if(!curr_instance.used || curr_instance.instance_id != dio->instance_id) {
PRINTF("RPL nbr-policy: did not find instance id: %d\n", dio->instance_id);
return NULL;
}
/* Add the new neighbor only if it is better than the worst parent. */
if(dio->rank + curr_instance.min_hoprankinc < worst_rank - curr_instance.min_hoprankinc / 2) {
/* Found *great* neighbor - add! */
PRINTF("RPL nbr-policy: DIO rank %u, worse_rank %u -- add to cache\n",
dio->rank, worst_rank);
return worst_rank_nbr;
}
PRINTF("RPL nbr-policy: DIO rank %u, worse_rank %u -- do not add to cache\n",
dio->rank, worst_rank);
return NULL;
}
/*---------------------------------------------------------------------------*/
const linkaddr_t *
rpl_nbr_policy_find_removable(nbr_table_reason_t reason, void *data)
{
/* When we get the DIO/DAO/DIS we know that UIP contains the
incoming packet */
switch(reason) {
case NBR_TABLE_REASON_RPL_DIO:
return find_removable_dio(&UIP_IP_BUF->srcipaddr, data);
case NBR_TABLE_REASON_RPL_DAO:
return NULL; /* DAOs are end-to-end in non-storing, this
nbr-policy reason is unused */
case NBR_TABLE_REASON_RPL_DIS:
return find_removable_dis(&UIP_IP_BUF->srcipaddr);
default:
return NULL;
}
}
/*---------------------------------------------------------------------------*/
/** @}*/

233
core/net/rpl-lite/rpl-ns.c Normal file
View File

@ -0,0 +1,233 @@
/*
* 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 "rpl.h"
#include "lib/list.h"
#include "lib/memb.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.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(void)
{
return num_nodes;
}
/*---------------------------------------------------------------------------*/
static int
node_matches_address(const rpl_ns_node_t *node, const uip_ipaddr_t *addr)
{
return addr != NULL
&& node != NULL
&& !memcmp(addr, &curr_instance.dag.dag_id, 8)
&& !memcmp(((const unsigned char *)addr) + 8, node->link_identifier, 8);
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *
rpl_ns_get_node(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(l, addr)) {
return l;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
int
rpl_ns_is_addr_reachable(const uip_ipaddr_t *addr)
{
int max_depth = RPL_NS_LINK_NUM;
rpl_ns_node_t *node = rpl_ns_get_node(addr);
rpl_ns_node_t *root_node = rpl_ns_get_node(&curr_instance.dag.dag_id);
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(const uip_ipaddr_t *child, const uip_ipaddr_t *parent)
{
rpl_ns_node_t *l = rpl_ns_get_node(child);
/* Check if parent matches */
if(l != NULL && node_matches_address(l->parent, parent)) {
l->lifetime = RPL_NOPATH_REMOVAL_DELAY;
}
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *
rpl_ns_update_node(const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime)
{
rpl_ns_node_t *child_node = rpl_ns_get_node(child);
rpl_ns_node_t *parent_node = rpl_ns_get_node(parent);
rpl_ns_node_t *old_parent_node;
if(parent != NULL) {
/* No node for the parent, add one with infinite lifetime */
if(parent_node == NULL) {
parent_node = rpl_ns_update_node(parent, NULL, RPL_ROUTE_INFINITE_LIFETIME);
if(parent_node == NULL) {
PRINTF("RPL NS: no space left for root node!\n");
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) {
PRINTF("RPL NS: no space left for child ");
PRINT6ADDR(child);
PRINTF("\n");
return NULL;
}
child_node->parent = NULL;
list_add(nodelist, child_node);
num_nodes++;
}
/* Initialize node */
child_node->lifetime = lifetime;
memcpy(child_node->link_identifier, ((const unsigned char *)child) + 8, 8);
/* Is the node reachable before the update? */
if(rpl_ns_is_addr_reachable(child)) {
old_parent_node = child_node->parent;
/* Update node */
child_node->parent = parent_node;
/* Has the node become unreachable? May happen if we create a loop. */
if(!rpl_ns_is_addr_reachable(child)) {
/* The new parent makes the node unreachable, restore old parent.
* We will take the update next time, with chances we know more of
* the topology and the loop is gone. */
child_node->parent = old_parent_node;
}
} else {
child_node->parent = parent_node;
}
PRINTF("RPL NS: updating link, child ");
PRINT6ADDR(child);
PRINTF(", parent ");
PRINT6ADDR(parent);
PRINTF(", lifetime %u, num_nodes %u\n", (unsigned)lifetime, num_nodes);
return child_node;
}
/*---------------------------------------------------------------------------*/
void
rpl_ns_init(void)
{
num_nodes = 0;
memb_init(&nodememb);
list_init(nodelist);
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *
rpl_ns_node_head(void)
{
return list_head(nodelist);
}
/*---------------------------------------------------------------------------*/
rpl_ns_node_t *
rpl_ns_node_next(rpl_ns_node_t *item)
{
return list_item_next(item);
}
/*---------------------------------------------------------------------------*/
int
rpl_ns_get_node_global_addr(uip_ipaddr_t *addr, rpl_ns_node_t *node)
{
if(addr != NULL && node != NULL) {
memcpy(addr, &curr_instance.dag.dag_id, 8);
memcpy(((unsigned char *)addr) + 8, &node->link_identifier, 8);
return 1;
} else {
return 0;
}
}
/*---------------------------------------------------------------------------*/
void
rpl_ns_periodic(unsigned seconds)
{
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 != RPL_ROUTE_INFINITE_LIFETIME) {
l->lifetime = l->lifetime > seconds ? l->lifetime - seconds : 0;
}
}
/* Second pass, for all expired 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;
}
}
#if DEBUG
uip_ipaddr_t node_addr;
rpl_ns_get_node_global_addr(&node_addr, l);
PRINTF("RPL NS: removing expired node ");
PRINT6ADDR(&node_addr);
PRINTF("\n");
#endif
/* No child found, deallocate node */
list_remove(nodelist, l);
memb_free(&nodememb, l);
num_nodes--;
}
}
}

149
core/net/rpl-lite/rpl-ns.h Normal file
View File

@ -0,0 +1,149 @@
/*
* 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
/********** Includes **********/
#include "uip.h"
#include "rpl.h"
/**
* \addtogroup uip6
* @{
*/
/********** Data Structures **********/
/* A node in a RPL Non-storing graph, stored at the root and representing
* all child-parent relationship. Used to build source routes */
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;
/********** Public functions **********/
/**
* Tells how many nodes are currently stored in the graph
*
* \return The number of nodes
*/
int rpl_ns_num_nodes(void);
/**
* Expires a given child-parent link
*
* \param child The IPv6 address of the child
* \param parent The IPv6 address of the parent
*/
void rpl_ns_expire_parent(const uip_ipaddr_t *child, const uip_ipaddr_t *parent);
/**
* Updates a child-parent link
*
* \param child The IPv6 address of the child
* \param parent The IPv6 address of the parent
* \param lifetime The link lifetime in seconds
*/
rpl_ns_node_t *rpl_ns_update_node(const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime);
/**
* Returns the head of the non-storing node list
*
* \return The head of the list
*/
rpl_ns_node_t *rpl_ns_node_head(void);
/**
* Returns the next element of the non-storing node list
*
* \param item The current element in the list
* \return The next element of the list
*/
rpl_ns_node_t *rpl_ns_node_next(rpl_ns_node_t *item);
/**
* Looks up for a RPL NS node from its IPv6 global address
*
* \param addr The target address
* \return A pointer to the node
*/
rpl_ns_node_t *rpl_ns_get_node(const uip_ipaddr_t *addr);
/**
* Telle whether an address is reachable, i.e. if there exists a path from
* the root to the node in the current RPL NS graph
*
* \param addr The target IPv6 global address
* \return 1 if the node is reachable, 0 otherwise
*/
int rpl_ns_is_addr_reachable(const uip_ipaddr_t *addr);
/**
* Finds the global address of a given node
*
* \param addr A pointer to the address to be written
* \param node The target node
* \return 1 if success, 0 otherwise
*/
int rpl_ns_get_node_global_addr(uip_ipaddr_t *addr, rpl_ns_node_t *node);
/**
* A function called periodically. Used to age the links (decrease lifetime
* and expire links accordingly)
*
* \param seconds The number of seconds elapsted since last call
*/
void rpl_ns_periodic(unsigned seconds);
/**
* Initialize rpl-ns module
*/
void rpl_ns_init(void);
/** @} */
#endif /* RPL_NS_H */

200
core/net/rpl-lite/rpl-of0.c Normal file
View File

@ -0,0 +1,200 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* An implementation of RPL's objective function 0, RFC6552
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
/**
* \addtogroup uip6
* @{
*/
#include "rpl.h"
#include "net/nbr-table.h"
#include "net/link-stats.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/* Constants from RFC6552. We use the default values. */
#define RANK_STRETCH 0 /* Must be in the range [0;5] */
#define RANK_FACTOR 1 /* Must be in the range [1;4] */
#define MIN_STEP_OF_RANK 1
#define MAX_STEP_OF_RANK 9
/* OF0 computes rank increase as follows:
* rank_increase = (RANK_FACTOR * STEP_OF_RANK + RANK_STRETCH) * min_hop_rank_increase
* STEP_OF_RANK is an implementation-specific scalar value in the range [1;9].
* RFC6552 provides a default value of 3 but recommends to use a dynamic link metric
* such as ETX.
* */
#define RPL_OF0_FIXED_SR 0
#define RPL_OF0_ETX_BASED_SR 1
/* Select RPL_OF0_FIXED_SR or RPL_OF0_ETX_BASED_SR */
#ifdef RPL_OF0_CONF_SR
#define RPL_OF0_SR RPL_OF0_CONF_SR
#else /* RPL_OF0_CONF_SR */
#define RPL_OF0_SR RPL_OF0_ETX_BASED_SR
#endif /* RPL_OF0_CONF_SR */
#if RPL_OF0_FIXED_SR
#define STEP_OF_RANK(p) (3)
#endif /* RPL_OF0_FIXED_SR */
#if RPL_OF0_ETX_BASED_SR
/* Numbers suggested by P. Thubert for in the 6TiSCH WG. Anything that maps ETX to
* a step between 1 and 9 works. */
#define STEP_OF_RANK(p) (((3 * parent_link_metric(p)) / LINK_STATS_ETX_DIVISOR) - 2)
#endif /* RPL_OF0_ETX_BASED_SR */
/*---------------------------------------------------------------------------*/
static void
reset(void)
{
PRINTF("RPL: Reset OF0\n");
}
/*---------------------------------------------------------------------------*/
static uint16_t
parent_link_metric(rpl_parent_t *p)
{
/* OF0 operates without metric container; the only metric we have is ETX */
const struct link_stats *stats = rpl_parent_get_link_stats(p);
return stats != NULL ? stats->etx : 0xffff;
}
/*---------------------------------------------------------------------------*/
static uint16_t
parent_rank_increase(rpl_parent_t *p)
{
uint16_t min_hoprankinc;
if(p == NULL) {
return RPL_INFINITE_RANK;
}
min_hoprankinc = curr_instance.min_hoprankinc;
return (RANK_FACTOR * STEP_OF_RANK(p) + RANK_STRETCH) * min_hoprankinc;
}
/*---------------------------------------------------------------------------*/
static uint16_t
parent_path_cost(rpl_parent_t *p)
{
if(p == NULL) {
return 0xffff;
}
/* path cost upper bound: 0xffff */
return MIN((uint32_t)p->rank + parent_link_metric(p), 0xffff);
}
/*---------------------------------------------------------------------------*/
static rpl_rank_t
rank_via_parent(rpl_parent_t *p)
{
if(p == NULL) {
return RPL_INFINITE_RANK;
} else {
return MIN((uint32_t)p->rank + parent_rank_increase(p), RPL_INFINITE_RANK);
}
}
/*---------------------------------------------------------------------------*/
static int
parent_is_acceptable(rpl_parent_t *p)
{
return STEP_OF_RANK(p) >= MIN_STEP_OF_RANK
&& STEP_OF_RANK(p) <= MAX_STEP_OF_RANK;
}
/*---------------------------------------------------------------------------*/
static int
parent_has_usable_link(rpl_parent_t *p)
{
return parent_is_acceptable(p);
}
/*---------------------------------------------------------------------------*/
static rpl_parent_t *
best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
{
uint16_t p1_cost;
uint16_t p2_cost;
int p1_is_acceptable;
int p2_is_acceptable;
p1_is_acceptable = p1 != NULL && parent_is_acceptable(p1);
p2_is_acceptable = p2 != NULL && parent_is_acceptable(p2);
if(!p1_is_acceptable) {
return p2_is_acceptable ? p2 : NULL;
}
if(!p2_is_acceptable) {
return p1_is_acceptable ? p1 : NULL;
}
p1_cost = parent_path_cost(p1);
p2_cost = parent_path_cost(p2);
/* Paths costs coarse-grained (multiple of min_hoprankinc), we operate without hysteresis */
if(p1_cost != p2_cost) {
/* Pick parent with lowest path cost */
return p1_cost < p2_cost ? p1 : p2;
} else {
/* We have a tie! */
/* Stik to current preferred parent if possible */
if(p1 == curr_instance.dag.preferred_parent || p2 == curr_instance.dag.preferred_parent) {
return curr_instance.dag.preferred_parent;
}
/* None of the nodes is the current preferred parent,
* choose parent with best link metric */
return parent_link_metric(p1) < parent_link_metric(p2) ? p1 : p2;
}
}
/*---------------------------------------------------------------------------*/
static void
update_metric_container(void)
{
curr_instance.mc.type = RPL_DAG_MC_NONE;
}
/*---------------------------------------------------------------------------*/
rpl_of_t rpl_of0 = {
reset,
parent_link_metric,
parent_has_usable_link,
parent_is_acceptable,
parent_path_cost,
rank_via_parent,
best_parent,
update_metric_container,
RPL_OCP_OF0
};
/** @}*/

View File

@ -0,0 +1,351 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Logic for DAG parents in RPL.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon Duquennoy <simon.duquennoy@inria.fr>
* Contributors: George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
*/
/**
* \addtogroup uip6
* @{
*/
#include "contiki.h"
#include "rpl.h"
#include "net/link-stats.h"
#include "net/nbr-table.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/* A configurable function called after every RPL parent switch */
#ifdef RPL_CALLBACK_PARENT_SWITCH
void RPL_CALLBACK_PARENT_SWITCH(rpl_parent_t *old, rpl_parent_t *new);
#endif /* RPL_CALLBACK_PARENT_SWITCH */
/*---------------------------------------------------------------------------*/
/* Per-parent RPL information */
NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents);
/*---------------------------------------------------------------------------*/
static int
acceptable_rank(rpl_rank_t rank)
{
return rank != RPL_INFINITE_RANK
&& rank >= ROOT_RANK
&& ((curr_instance.max_rankinc == 0) ||
DAG_RANK(rank) <=
DAG_RANK(curr_instance.dag.lowest_rank + curr_instance.max_rankinc));
}
/*---------------------------------------------------------------------------*/
void
rpl_parent_print_list(const char *str)
{
if(curr_instance.used) {
int curr_dio_interval = curr_instance.dag.dio_intcurrent;
int curr_rank = curr_instance.dag.rank;
rpl_parent_t *p = nbr_table_head(rpl_parents);
clock_time_t clock_now = clock_time();
printf("RPL nbr: MOP %u OCP %u rank %u dioint %u, DS6 nbr count %u (%s)\n",
curr_instance.mop, curr_instance.of->ocp, curr_rank,
curr_dio_interval, uip_ds6_nbr_num(), str);
while(p != NULL) {
const struct link_stats *stats = rpl_parent_get_link_stats(p);
printf("RPL nbr: %3u %5u, %5u => %5u -- %2u %c%c%c (last tx %u min ago)\n",
rpl_parent_get_ipaddr(p)->u8[15],
p->rank,
rpl_parent_get_link_metric(p),
rpl_parent_rank_via_parent(p),
stats != NULL ? stats->freshness : 0,
(acceptable_rank(rpl_parent_rank_via_parent(p)) && curr_instance.of->parent_is_acceptable(p)) ? 'a' : ' ',
link_stats_is_fresh(stats) ? 'f' : ' ',
p == curr_instance.dag.preferred_parent ? 'p' : ' ',
(unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND))
);
p = nbr_table_next(rpl_parents, p);
}
printf("RPL nbr: end of list\n");
}
}
/*---------------------------------------------------------------------------*/
#if UIP_ND6_SEND_NS
static uip_ds6_nbr_t *
rpl_get_ds6_nbr(rpl_parent_t *parent)
{
const linkaddr_t *lladdr = rpl_parent_get_lladdr(parent);
if(lladdr != NULL) {
return nbr_table_get_from_lladdr(ds6_neighbors, lladdr);
} else {
return NULL;
}
}
#endif /* UIP_ND6_SEND_NS */
/*---------------------------------------------------------------------------*/
static void
remove_parent(rpl_parent_t *parent)
{
/* Make sure we don't point to a removed parent. Note that we do not need
to worry about preferred_parent here, as it is locked in the the table
and will never be removed by external modules. */
if(parent == curr_instance.dag.urgent_probing_target) {
curr_instance.dag.urgent_probing_target = NULL;
}
if(parent == curr_instance.dag.unicast_dio_target) {
curr_instance.dag.unicast_dio_target = NULL;
}
nbr_table_remove(rpl_parents, parent);
rpl_timers_schedule_state_update(); /* Updating from here is unsafe; postpone */
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
rpl_parent_get_from_lladdr(uip_lladdr_t *addr)
{
return nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)addr);
}
/*---------------------------------------------------------------------------*/
uint16_t
rpl_parent_get_link_metric(rpl_parent_t *p)
{
if(p != NULL && curr_instance.of->parent_link_metric != NULL) {
return curr_instance.of->parent_link_metric(p);
}
return 0xffff;
}
/*---------------------------------------------------------------------------*/
rpl_rank_t
rpl_parent_rank_via_parent(rpl_parent_t *p)
{
if(p != NULL && curr_instance.of->rank_via_parent != NULL) {
return curr_instance.of->rank_via_parent(p);
}
return RPL_INFINITE_RANK;
}
/*---------------------------------------------------------------------------*/
const linkaddr_t *
rpl_parent_get_lladdr(rpl_parent_t *p)
{
return nbr_table_get_lladdr(rpl_parents, p);
}
/*---------------------------------------------------------------------------*/
uip_ipaddr_t *
rpl_parent_get_ipaddr(rpl_parent_t *p)
{
const linkaddr_t *lladdr = rpl_parent_get_lladdr(p);
return uip_ds6_nbr_ipaddr_from_lladdr((uip_lladdr_t *)lladdr);
}
/*---------------------------------------------------------------------------*/
const struct link_stats *
rpl_parent_get_link_stats(rpl_parent_t *p)
{
const linkaddr_t *lladdr = rpl_parent_get_lladdr(p);
return link_stats_from_lladdr(lladdr);
}
/*---------------------------------------------------------------------------*/
int
rpl_parent_is_fresh(rpl_parent_t *p)
{
const struct link_stats *stats = rpl_parent_get_link_stats(p);
return link_stats_is_fresh(stats);
}
/*---------------------------------------------------------------------------*/
int
rpl_parent_is_reachable(rpl_parent_t *p) {
if(p == NULL) {
return 0;
} else {
#if UIP_ND6_SEND_NS
uip_ds6_nbr_t *nbr = rpl_get_ds6_nbr(p);
/* Exclude links to a neighbor that is not reachable at a NUD level */
if(nbr == NULL || nbr->state != NBR_REACHABLE) {
return 0;
}
#endif /* UIP_ND6_SEND_NS */
/* If we don't have fresh link information, assume the parent is reachable. */
return !rpl_parent_is_fresh(p) || curr_instance.of->parent_has_usable_link(p);
}
}
/*---------------------------------------------------------------------------*/
void
rpl_parent_set_preferred(rpl_parent_t *p)
{
if(curr_instance.dag.preferred_parent != p) {
PRINTF("RPL: parent switch ");
if(p != NULL) {
PRINT6ADDR(rpl_parent_get_ipaddr(p));
} else {
PRINTF("NULL");
}
PRINTF(" used to be ");
if(curr_instance.dag.preferred_parent != NULL) {
PRINT6ADDR(rpl_parent_get_ipaddr(curr_instance.dag.preferred_parent));
} else {
PRINTF("NULL");
}
PRINTF("\n");
#ifdef RPL_CALLBACK_PARENT_SWITCH
RPL_CALLBACK_PARENT_SWITCH(curr_instance.dag.preferred_parent, p);
#endif /* RPL_CALLBACK_PARENT_SWITCH */
/* Always keep the preferred parent locked, so it remains in the
* neighbor table. */
nbr_table_unlock(rpl_parents, curr_instance.dag.preferred_parent);
nbr_table_lock(rpl_parents, p);
/* Update DS6 default route. Use an infinite lifetime */
uip_ds6_defrt_rm(uip_ds6_defrt_lookup(
rpl_parent_get_ipaddr(curr_instance.dag.preferred_parent)));
uip_ds6_defrt_add(rpl_parent_get_ipaddr(p), 0);
curr_instance.dag.preferred_parent = p;
}
}
/*---------------------------------------------------------------------------*/
/* Remove DAG parents with a rank that is at least the same as minimum_rank. */
void
rpl_parent_remove_all(void)
{
rpl_parent_t *p;
PRINTF("RPL: removing all parents\n");
p = nbr_table_head(rpl_parents);
while(p != NULL) {
remove_parent(p);
p = nbr_table_next(rpl_parents, p);
}
/* Update needed immediately so as to ensure preferred_parent becomes NULL,
* and no longer points to a de-allocated parent. */
rpl_dag_update_state();
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
rpl_parent_get_from_ipaddr(uip_ipaddr_t *addr)
{
uip_ds6_nbr_t *ds6_nbr = uip_ds6_nbr_lookup(addr);
const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_nbr);
return nbr_table_get_from_lladdr(rpl_parents, (linkaddr_t *)lladdr);
}
/*---------------------------------------------------------------------------*/
static rpl_parent_t *
best_parent(int fresh_only)
{
rpl_parent_t *p;
rpl_parent_t *best = NULL;
if(curr_instance.used == 0) {
return NULL;
}
/* Search for the best parent according to the OF */
for(p = nbr_table_head(rpl_parents); p != NULL; p = nbr_table_next(rpl_parents, p)) {
if(!acceptable_rank(p->rank) || !curr_instance.of->parent_is_acceptable(p)) {
/* Exclude parents with a rank that is not acceptable) */
continue;
}
if(fresh_only && !rpl_parent_is_fresh(p)) {
/* Filter out non-fresh parents if fresh_only is set */
continue;
}
#if UIP_ND6_SEND_NS
{
uip_ds6_nbr_t *nbr = rpl_get_ds6_nbr(p);
/* Exclude links to a neighbor that is not reachable at a NUD level */
if(nbr == NULL || nbr->state != NBR_REACHABLE) {
continue;
}
}
#endif /* UIP_ND6_SEND_NS */
/* Now we have an acceptable parent, check if it is the new best */
best = curr_instance.of->best_parent(best, p);
}
return best;
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
rpl_parent_select_best(void)
{
rpl_parent_t *best;
if(rpl_dag_root_is_root()) {
return NULL; /* The root has no parent */
}
/* Look for best parent (regardless of freshness) */
best = best_parent(0);
#if RPL_WITH_PROBING
if(best != NULL) {
if(rpl_parent_is_fresh(best)) {
return best;
} else {
/* The best is not fresh. Look for the best fresh now. */
rpl_parent_t *best_fresh = best_parent(1);
if(best_fresh == NULL) {
/* No fresh parent around, select best (non-fresh) */
return best;
} else {
/* Select best fresh */
return best_fresh;
}
/* Probe the best parent shortly in order to get a fresh estimate */
curr_instance.dag.urgent_probing_target = best;
rpl_schedule_probing();
/* Stick to current preferred parent until a better one is fresh */
return curr_instance.dag.preferred_parent;
}
} else {
return NULL;
}
#else /* RPL_WITH_PROBING */
return best;
#endif /* RPL_WITH_PROBING */
}
/*---------------------------------------------------------------------------*/
void
rpl_parent_init(void)
{
nbr_table_register(rpl_parents, (nbr_table_callback *)remove_parent);
}
/** @} */

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Header file for rpl-parent module
* \author
* Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon DUquennoy <simon.duquennoy@inria.fr>
*
*/
#ifndef RPL_PARENT_H
#define RPL_PARENT_H
/********** Includes **********/
#include "rpl.h"
#include "lib/list.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "sys/ctimer.h"
/**
* \addtogroup uip6
* @{
*/
/********** Public symbols **********/
/* Per-parent RPL information */
NBR_TABLE_DECLARE(rpl_parents);
/********** Public functions **********/
/**
* Initialize rpl-dag-parent module
*/
void rpl_parent_init(void);
/**
* Set current RPL preferred parent and update DS6 default route accordingly
*
* \param p The new preferred parent
*/
void rpl_parent_set_preferred(rpl_parent_t *p);
/**
* Tells wether we have fresh link information towards a given parent
*
* \param p The parent
* \return 1 if we have fresh link information, 0 otherwise
*/
int rpl_parent_is_fresh(rpl_parent_t *p);
/**
* Tells wether we a given parent is reachable
*
* \param p The parent
* \return 1 if the parent is reachable, 0 otherwise
*/
int rpl_parent_is_reachable(rpl_parent_t *p);
/**
* Returns a parent's link metric
*
* \param p The parent
* \return The link metric if any, 0xffff otherwise
*/
uint16_t rpl_parent_get_link_metric(rpl_parent_t *p);
/**
* Returns our rank if selecting a given parent as preferred parent
*
* \param p The parent
* \return The resulting rank if any, RPL_INFINITE_RANK otherwise
*/
rpl_rank_t rpl_parent_rank_via_parent(rpl_parent_t *p);
/**
* Returns a parent's link-layer address
*
* \param p The parent
* \return The link-layer address if any, NULL otherwise
*/
const linkaddr_t *rpl_parent_get_lladdr(rpl_parent_t *p);
/**
* Returns a parent's link statistics
*
* \param p The parent
* \return The link_stats structure address if any, NULL otherwise
*/
const struct link_stats *rpl_parent_get_link_stats(rpl_parent_t *p);
/**
* Returns a parent's (link-local) IPv6 address
*
* \param p The parent
* \return The link-local IPv6 address if any, NULL otherwise
*/
uip_ipaddr_t *rpl_parent_get_ipaddr(rpl_parent_t *p);
/**
* Returns a parent from its link-layer address
*
* \param addr The link-layer address
* \return The parent if found, NULL otherwise
*/
rpl_parent_t *rpl_parent_get_from_lladdr(uip_lladdr_t *addr);
/**
* Returns a parent from its link-local IPv6 address
*
* \param addr The link-local IPv6 address
* \return The parent if found, NULL otherwise
*/
rpl_parent_t *rpl_parent_get_from_ipaddr(uip_ipaddr_t *addr);
/**
* Prints a summary of all RPL neighbors and their properties
*
* \param str A descriptive text on the caller
*/
void rpl_parent_print_list(const char *str);
/**
* Empty the RPL parent table
*/
void rpl_parent_remove_all(void);
/**
* Returns the best candidate for preferred parent
*
* \return The best candidate, NULL if no usable parent is found
*/
rpl_parent_t *rpl_parent_select_best(void);
/** @} */
#endif /* RPL_PARENT_H */

View File

@ -0,0 +1,506 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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 timer management.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
/**
* \addtogroup uip6
* @{
*/
#include "contiki-conf.h"
#include "rpl.h"
#include "net/link-stats.h"
#include "lib/random.h"
#include "sys/ctimer.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/* A configurable function called after update of the RPL DIO interval */
#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
void RPL_CALLBACK_NEW_DIO_INTERVAL(uint8_t dio_interval);
#endif /* RPL_CALLBACK_NEW_DIO_INTERVAL */
#ifdef RPL_PROBING_SELECT_FUNC
rpl_parent_t *RPL_PROBING_SELECT_FUNC(void);
#endif /* RPL_PROBING_SELECT_FUNC */
#ifdef RPL_PROBING_DELAY_FUNC
clock_time_t RPL_PROBING_DELAY_FUNC(void);
#endif /* RPL_PROBING_DELAY_FUNC */
#define PERIODIC_DELAY_SECONDS 60
#define PERIODIC_DELAY (60 * CLOCK_SECOND)
static void handle_dis_timer(void *ptr);
static void handle_dio_timer(void *ptr);
static void handle_unicast_dio_timer(void *ptr);
static void handle_dao_timer(void *ptr);
#if RPL_WITH_DAO_ACK
static void handle_dao_ack_timer(void *ptr);
#endif /* RPL_WITH_DAO_ACK */
#if RPL_WITH_PROBING
static void handle_probing_timer(void *ptr);
#endif /* RPL_WITH_PROBING */
static void handle_periodic_timer(void *ptr);
static void handle_state_update(void *ptr);
/*---------------------------------------------------------------------------*/
static struct ctimer dis_timer; /* Not part of a DAG because when not joined */
static struct ctimer periodic_timer; /* Not part of a DAG because used for general state maintenance */
/*---------------------------------------------------------------------------*/
/*------------------------------- DIS -------------------------------------- */
/*---------------------------------------------------------------------------*/
void
rpl_timers_schedule_periodic_dis(void)
{
clock_time_t expiration_time = RPL_DIS_INTERVAL / 2 + (random_rand() % (RPL_DIS_INTERVAL));
ctimer_set(&dis_timer, expiration_time, handle_dis_timer, NULL);
}
/*---------------------------------------------------------------------------*/
static void
handle_dis_timer(void *ptr)
{
if(!rpl_dag_root_is_root() &&
(!curr_instance.used || curr_instance.dag.preferred_parent == NULL)) {
/* Send DIS and schedule next */
rpl_icmp6_dis_output(NULL);
rpl_timers_schedule_periodic_dis();
}
}
/*---------------------------------------------------------------------------*/
/*------------------------------- DIO -------------------------------------- */
/*---------------------------------------------------------------------------*/
static void
new_dio_interval(void)
{
uint32_t time;
clock_time_t ticks;
time = 1UL << curr_instance.dag.dio_intcurrent;
/* Convert from milliseconds to CLOCK_TICKS. */
ticks = (time * CLOCK_SECOND) / 1000;
curr_instance.dag.dio_next_delay = ticks;
/* random number between I/2 and I */
ticks = ticks / 2 + (ticks / 2 * (uint32_t)random_rand()) / RANDOM_RAND_MAX;
/*
* The intervals must be equally long among the nodes for Trickle to
* operate efficiently. Therefore we need to calculate the delay between
* the randomized time and the start time of the next interval.
*/
curr_instance.dag.dio_next_delay -= ticks;
curr_instance.dag.dio_send = 1;
/* reset the redundancy counter */
curr_instance.dag.dio_counter = 0;
/* schedule the timer */
ctimer_set(&curr_instance.dag.dio_timer, ticks, &handle_dio_timer, NULL);
#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
RPL_CALLBACK_NEW_DIO_INTERVAL(curr_instance.dag.dio_intcurrent);
#endif /* RPL_CALLBACK_NEW_DIO_INTERVAL */
}
/*---------------------------------------------------------------------------*/
void
rpl_timers_dio_reset(const char *str)
{
if(curr_instance.used) {
PRINTF("RPL: reset DIO timer (%s)\n", str);
#if !RPL_LEAF_ONLY
curr_instance.dag.dio_counter = 0;
curr_instance.dag.dio_intcurrent = curr_instance.dio_intmin;
new_dio_interval();
#endif /* RPL_LEAF_ONLY */
}
}
/*---------------------------------------------------------------------------*/
static void
handle_dio_timer(void *ptr)
{
if(!curr_instance.used) {
return; /* We will be scheduled again at join time */
}
if(curr_instance.dag.dio_send) {
/* send DIO if counter is less than desired redundancy, or if dio_redundancy
is set to 0, or if we are the root */
if(rpl_dag_root_is_root() || curr_instance.dio_redundancy == 0 ||
curr_instance.dag.dio_counter < curr_instance.dio_redundancy) {
#if RPL_TRICKLE_REFRESH_DAO_ROUTES
if(rpl_dag_root_is_root()) {
static int count = 0;
if((count++ % RPL_TRICKLE_REFRESH_DAO_ROUTES) == 0) {
/* Request new DAO to refresh route. */
RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
}
}
#endif /* RPL_TRICKLE_REFRESH_DAO_ROUTES */
rpl_icmp6_dio_output(NULL);
}
curr_instance.dag.dio_send = 0;
ctimer_set(&curr_instance.dag.dio_timer, curr_instance.dag.dio_next_delay, handle_dio_timer, NULL);
} else {
/* check if we need to double interval */
if(curr_instance.dag.dio_intcurrent < curr_instance.dio_intmin + curr_instance.dio_intdoubl) {
curr_instance.dag.dio_intcurrent++;
}
new_dio_interval();
}
}
/*---------------------------------------------------------------------------*/
/*------------------------------- Unicast DIO ------------------------------ */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
rpl_timers_schedule_unicast_dio(rpl_parent_t *target)
{
if(curr_instance.used) {
curr_instance.dag.unicast_dio_target = target;
ctimer_set(&curr_instance.dag.unicast_dio_timer, 0,
handle_unicast_dio_timer, NULL);
}
}
static void
handle_unicast_dio_timer(void *ptr)
{
uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(curr_instance.dag.unicast_dio_target);
if(target_ipaddr != NULL) {
rpl_icmp6_dio_output(target_ipaddr);
}
}
/*---------------------------------------------------------------------------*/
/*------------------------------- DAO -------------------------------------- */
/*---------------------------------------------------------------------------*/
#if RPL_WITH_DAO_ACK
/*---------------------------------------------------------------------------*/
static void
schedule_dao_retransmission(void)
{
clock_time_t expiration_time = RPL_DAO_RETRANSMISSION_TIMEOUT / 2 + (random_rand() % (RPL_DAO_RETRANSMISSION_TIMEOUT));
ctimer_set(&curr_instance.dag.dao_timer, expiration_time, handle_dao_timer, NULL);
}
#endif /* RPL_WITH_DAO_ACK */
/*---------------------------------------------------------------------------*/
static void
schedule_dao_refresh(void)
{
if(curr_instance.used && curr_instance.default_lifetime != RPL_INFINITE_LIFETIME) {
#if RPL_WITH_DAO_ACK
/* DAO-ACK enabled: the last DAO was ACKed, wait until expiration before refresh */
clock_time_t target_refresh = CLOCK_SECOND * RPL_LIFETIME(curr_instance.default_lifetime);
#else /* RPL_WITH_DAO_ACK */
/* DAO-ACK disabled: use half the expiration time to get two chances to refresh per lifetime */
clock_time_t target_refresh = (CLOCK_SECOND * RPL_LIFETIME(curr_instance.default_lifetime) / 2);
#endif /* RPL_WITH_DAO_ACK */
/* Send between 60 and 120 seconds before target refresh */
clock_time_t safety_margin = (60 * CLOCK_SECOND) + (random_rand() % (60 * CLOCK_SECOND));
if(target_refresh > safety_margin) {
target_refresh -= safety_margin;
}
/* Increment next sequno */
RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
ctimer_set(&curr_instance.dag.dao_timer, target_refresh, handle_dao_timer, NULL);
}
}
/*---------------------------------------------------------------------------*/
void
rpl_timers_schedule_dao(void)
{
if(curr_instance.used) {
/* No need for aggregation delay as per RFC 6550 section 9.5, as this only
* serves storing mode. Use simply delay instead, with the only PURPOSE
* to reduce congestion. */
clock_time_t expiration_time = RPL_DAO_DELAY / 2 + (random_rand() % (RPL_DAO_DELAY));
/* Increment next seqno */
RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
ctimer_set(&curr_instance.dag.dao_timer, expiration_time, handle_dao_timer, NULL);
}
}
/*---------------------------------------------------------------------------*/
static void
handle_dao_timer(void *ptr)
{
#if RPL_WITH_DAO_ACK
if(rpl_lollipop_greater_than(curr_instance.dag.dao_curr_seqno,
curr_instance.dag.dao_last_seqno)) {
/* We are sending a new DAO here. Prepare retransmissions */
curr_instance.dag.dao_transmissions = 0;
} else {
/* We are called for the same DAO again */
if(curr_instance.dag.dao_last_acked_seqno == curr_instance.dag.dao_last_seqno) {
/* The last seqno sent is ACKed! Schedule refresh to avoid route expiration */
schedule_dao_refresh();
return;
}
/* We need to re-send the last DAO */
if(curr_instance.dag.dao_transmissions >= RPL_DAO_MAX_RETRANSMISSIONS) {
/* No more retransmissions. Perform local repair and hope to find another parent. */
rpl_local_repair("DAO max rtx");
return;
}
}
/* Increment transmission counter before sending */
curr_instance.dag.dao_transmissions++;
/* Schedule next retransmission */
schedule_dao_retransmission();
#endif /* RPL_WITH_DAO_ACK */
curr_instance.dag.dao_last_seqno = curr_instance.dag.dao_curr_seqno;
/* Send a DAO with own prefix as target and default lifetime */
rpl_icmp6_dao_output(curr_instance.default_lifetime);
#if !RPL_WITH_DAO_ACK
/* There is DAO-ACK, schedule a refresh. Must be done after rpl_icmp6_dao_output,
because we increment curr_instance.dag.dao_curr_seqno for the next DAO (refresh) */
schedule_dao_refresh();
#endif /* !RPL_WITH_DAO_ACK */
}
#if RPL_WITH_DAO_ACK
/*---------------------------------------------------------------------------*/
/*------------------------------- DAO-ACK ---------------------------------- */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
rpl_timers_schedule_dao_ack(uip_ipaddr_t *target, uint16_t sequence)
{
if(curr_instance.used) {
uip_ipaddr_copy(&curr_instance.dag.dao_ack_target, target);
curr_instance.dag.dao_ack_sequence = sequence;
ctimer_set(&curr_instance.dag.dao_ack_timer, 0, handle_dao_ack_timer, NULL);
}
}
static void
handle_dao_ack_timer(void *ptr)
{
rpl_icmp6_dao_ack_output(&curr_instance.dag.dao_ack_target,
curr_instance.dag.dao_ack_sequence, RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
#endif /* RPL_WITH_DAO_ACK */
/*---------------------------------------------------------------------------*/
/*------------------------------- Probing----------------------------------- */
/*---------------------------------------------------------------------------*/
#if RPL_WITH_PROBING
clock_time_t
get_probing_delay(void)
{
if(curr_instance.used && curr_instance.dag.urgent_probing_target != NULL) {
/* Urgent probing needed (to find out if a neighbor may become preferred parent) */
return random_rand() % (CLOCK_SECOND * 10);
} else {
/* Else, use normal probing interval */
return ((RPL_PROBING_INTERVAL) / 2) + random_rand() % (RPL_PROBING_INTERVAL);
}
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
get_probing_target(void)
{
/* Returns the next probing target. The current implementation probes the urgent
* probing target if any, or the preferred parent if its link statistics need refresh.
* Otherwise, it picks at random between:
* (1) selecting the best parent with non-fresh link statistics
* (2) selecting the least recently updated parent
*/
rpl_parent_t *p;
rpl_parent_t *probing_target = NULL;
rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
clock_time_t probing_target_age = 0;
clock_time_t clock_now = clock_time();
if(curr_instance.used == 0) {
return NULL;
}
/* There is an urgent probing target */
if(curr_instance.dag.urgent_probing_target != NULL) {
return curr_instance.dag.urgent_probing_target;
}
/* The preferred parent needs probing */
if(curr_instance.dag.preferred_parent != NULL && !rpl_parent_is_fresh(curr_instance.dag.preferred_parent)) {
return curr_instance.dag.preferred_parent;
}
/* With 50% probability: probe best non-fresh parent */
if(random_rand() % 2 == 0) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(!rpl_parent_is_fresh(p)) {
/* p is in our dag and needs probing */
rpl_rank_t p_rank = rpl_parent_rank_via_parent(p);
if(probing_target == NULL
|| p_rank < probing_target_rank) {
probing_target = p;
probing_target_rank = p_rank;
}
}
p = nbr_table_next(rpl_parents, p);
}
}
/* If we still do not have a probing target: pick the least recently updated parent */
if(probing_target == NULL) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
const struct link_stats *stats =rpl_parent_get_link_stats(p);
if(stats != NULL) {
if(probing_target == NULL
|| clock_now - stats->last_tx_time > probing_target_age) {
probing_target = p;
probing_target_age = clock_now - stats->last_tx_time;
}
}
p = nbr_table_next(rpl_parents, p);
}
}
return probing_target;
}
/*---------------------------------------------------------------------------*/
static void
handle_probing_timer(void *ptr)
{
rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC();
uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
/* Perform probing */
if(target_ipaddr != NULL) {
const struct link_stats *stats = rpl_parent_get_link_stats(probing_target);
(void)stats;
PRINTF("RPL: probing %u %s last tx %u min ago\n",
rpl_parent_get_lladdr(probing_target)->u8[7],
curr_instance.dag.urgent_probing_target != NULL ? "(urgent)" : "",
probing_target != NULL ?
(unsigned)((clock_time() - stats->last_tx_time) / (60 * CLOCK_SECOND)) : 0
);
/* Send probe, e.g. unicast DIO or DIS */
RPL_PROBING_SEND_FUNC(target_ipaddr);
curr_instance.dag.urgent_probing_target = NULL;
}
/* Schedule next probing */
rpl_schedule_probing();
}
/*---------------------------------------------------------------------------*/
void
rpl_schedule_probing(void)
{
if(curr_instance.used) {
ctimer_set(&curr_instance.dag.probing_timer, RPL_PROBING_DELAY_FUNC(),
handle_probing_timer, NULL);
}
}
#endif /* RPL_WITH_PROBING */
/*---------------------------------------------------------------------------*/
/*------------------------------- Periodic---------------------------------- */
/*---------------------------------------------------------------------------*/
void
rpl_timers_init(void)
{
ctimer_set(&periodic_timer, PERIODIC_DELAY, handle_periodic_timer, NULL);
rpl_timers_schedule_periodic_dis();
}
/*---------------------------------------------------------------------------*/
static void
handle_periodic_timer(void *ptr)
{
if(curr_instance.used) {
rpl_dag_periodic(PERIODIC_DELAY_SECONDS);
rpl_ns_periodic(PERIODIC_DELAY_SECONDS);
}
if(!curr_instance.used || curr_instance.dag.preferred_parent == NULL) {
if(etimer_expired(&dis_timer.etimer)) {
rpl_timers_schedule_periodic_dis(); /* Schedule DIS if needed */
}
}
ctimer_reset(&periodic_timer);
#if DEBUG
rpl_parent_print_list("Periodic");
#endif
}
/*---------------------------------------------------------------------------*/
void
rpl_timers_stop_dag_timers(void)
{
/* Stop all timers related to the DAG */
ctimer_stop(&curr_instance.dag.state_update);
ctimer_stop(&curr_instance.dag.dio_timer);
ctimer_stop(&curr_instance.dag.unicast_dio_timer);
ctimer_stop(&curr_instance.dag.dao_timer);
#if RPL_WITH_PROBING
ctimer_stop(&curr_instance.dag.probing_timer);
#endif /* RPL_WITH_PROBING */
#if RPL_WITH_DAO_ACK
ctimer_stop(&curr_instance.dag.dao_ack_timer);
#endif /* RPL_WITH_DAO_ACK */
}
/*---------------------------------------------------------------------------*/
void
rpl_timers_unschedule_state_update(void)
{
if(curr_instance.used) {
ctimer_stop(&curr_instance.dag.state_update);
}
}
/*---------------------------------------------------------------------------*/
void
rpl_timers_schedule_state_update(void)
{
if(curr_instance.used) {
ctimer_set(&curr_instance.dag.state_update, 0, handle_state_update, NULL);
}
}
/*---------------------------------------------------------------------------*/
static void
handle_state_update(void *ptr)
{
rpl_dag_update_state();
}
/** @}*/

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Header file for rpl-timers module
* \author
* Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
* Simon DUquennoy <simon.duquennoy@inria.fr>
*
*/
#ifndef RPL_TIMERS_H
#define RPL_TIMERS_H
/********** Includes **********/
#include "rpl.h"
/**
* \addtogroup uip6
* @{
*/
/********** Public functions **********/
/**
* Schedule periodic DIS with a random delay based on RPL_DIS_INTERVAL, until
* we join a DAG.
*/
void rpl_timers_schedule_periodic_dis(void);
/**
* Initialize rpl-timers module
*/
void rpl_timers_init(void);
/**
* Stop all timers related to the DAG
*/
void rpl_timers_stop_dag_timers(void);
/**
* Reset DIO Trickle timer
*
* \param str A textual description of caused the DIO timer reset
*/
void rpl_timers_dio_reset(const char *str);
/**
* Schedule unicast DIO with no delay
*/
void rpl_timers_schedule_unicast_dio(rpl_parent_t *target);
/**
* Schedule a DAO with random delay based on RPL_DAO_DELAY
*/
void rpl_timers_schedule_dao(void);
/**
* Schedule a DAO-ACK with no delay
*/
void rpl_timers_schedule_dao_ack(uip_ipaddr_t *target, uint16_t sequence);
/**
* Schedule probing with delay RPL_PROBING_DELAY_FUNC()
*/
void rpl_schedule_probing(void);
/**
* Schedule a state update ASAP. Useful to force an update from a context
* where updating directly would be unsafe.
*/
void rpl_timers_schedule_state_update(void);
/**
* Cancelled any scheduled state update.
*/
void rpl_timers_unschedule_state_update(void);
/** @} */
#endif /* RPL_TIMERS_H */

View File

@ -0,0 +1,233 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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 types and macros
* \author
* Joakim Eriksson <joakime@sics.se> & Nicolas Tsiftes <nvt@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*
*/
#ifndef RPL_TYPES_H
#define RPL_TYPES_H
/**
* \addtogroup uip6
* @{
*/
/********** Macros **********/
/* Multicast address: create and compare */
/** \brief Set IP address addr to the link-local, all-rpl-nodes
multicast address. */
#define uip_create_linklocal_rplnodes_mcast(addr) \
uip_ip6addr((addr), 0xff02, 0, 0, 0, 0, 0, 0, 0x001a)
/** \brief Is IPv6 address addr the link-local, all-RPL-nodes
multicast address? */
#define uip_is_addr_linklocal_rplnodes_mcast(addr) \
((addr)->u8[0] == 0xff) && \
((addr)->u8[1] == 0x02) && \
((addr)->u16[1] == 0) && \
((addr)->u16[2] == 0) && \
((addr)->u16[3] == 0) && \
((addr)->u16[4] == 0) && \
((addr)->u16[5] == 0) && \
((addr)->u16[6] == 0) && \
((addr)->u8[14] == 0) && \
((addr)->u8[15] == 0x1a))
/* Compute lifetime, accounting for the lifetime unit */
#define RPL_LIFETIME(lifetime) \
(((lifetime) == RPL_INFINITE_LIFETIME) ? \
RPL_ROUTE_INFINITE_LIFETIME : \
(unsigned long)curr_instance.lifetime_unit * (lifetime))
/* Rank of a root node. */
#define ROOT_RANK curr_instance.min_hoprankinc
/* Return DAG RANK as per RFC 6550 (rank divided by min_hoprankinc) */
#define DAG_RANK(fixpt_rank) ((fixpt_rank) / curr_instance.min_hoprankinc)
/* Lollipop counters */
#define RPL_LOLLIPOP_MAX_VALUE 255
#define RPL_LOLLIPOP_CIRCULAR_REGION 127
#define RPL_LOLLIPOP_SEQUENCE_WINDOWS 16
#define RPL_LOLLIPOP_INIT (RPL_LOLLIPOP_MAX_VALUE - RPL_LOLLIPOP_SEQUENCE_WINDOWS + 1)
#define RPL_LOLLIPOP_INCREMENT(counter) \
do { \
if((counter) > RPL_LOLLIPOP_CIRCULAR_REGION) { \
(counter) = ((counter) + 1) & RPL_LOLLIPOP_MAX_VALUE; \
} else { \
(counter) = ((counter) + 1) & RPL_LOLLIPOP_CIRCULAR_REGION; \
} \
} while(0)
#define RPL_LOLLIPOP_IS_INIT(counter) \
((counter) > RPL_LOLLIPOP_CIRCULAR_REGION)
/********** Data structures and types **********/
typedef uint16_t rpl_rank_t;
typedef uint16_t rpl_ocp_t;
/*---------------------------------------------------------------------------*/
struct rpl_metric_object_energy {
uint8_t flags;
uint8_t energy_est;
};
/* Logical representation of a DAG Metric Container. */
struct rpl_metric_container {
uint8_t type;
uint8_t flags;
uint8_t aggr;
uint8_t prec;
uint8_t length;
union metric_object {
struct rpl_metric_object_energy energy;
uint16_t etx;
} obj;
};
typedef struct rpl_metric_container rpl_metric_container_t;
/* RPL prefix information */
struct rpl_prefix {
uip_ipaddr_t prefix;
uint32_t lifetime;
uint8_t length;
uint8_t flags;
};
typedef struct rpl_prefix rpl_prefix_t;
/* All information related to a RPL parent */
struct rpl_parent {
#if RPL_WITH_MC
rpl_metric_container_t mc;
#endif /* RPL_WITH_MC */
rpl_rank_t rank;
uint8_t dtsn;
};
typedef struct rpl_parent rpl_parent_t;
/*---------------------------------------------------------------------------*/
/*
* API for RPL objective functions (OF)
*
* reset(dag) Resets the objective function state for a specific DAG. This function is
* called when doing a global repair on the DAG.
* parent_link_metric(parent) Returns the link metric of a parent
* parent_has_usable_link(parent) Returns 1 iff we have a usable link to this parent
* parent_is_acceptable(parent) Returns 1 iff the parent has a usable rank/link as defined by the OF
* parent_path_cost(parent) Returns the path cost of a parent
* rank_via_parent(parent) Returns our rank if we select a given parent as preferred parent
* parent_is_acceptable Returns 1 if a parent is usable as preferred parent, 0 otherwise
* best_parent(parent1, parent2) Compares two DAGs and returns the best one, according to the OF.
* update_metric_container() dao_ack_callback(parent, status)
*/
struct rpl_of {
void (*reset)(void);
uint16_t (*parent_link_metric)(rpl_parent_t *);
int (*parent_has_usable_link)(rpl_parent_t *);
int (*parent_is_acceptable)(rpl_parent_t *);
uint16_t (*parent_path_cost)(rpl_parent_t *);
rpl_rank_t (*rank_via_parent)(rpl_parent_t *);
rpl_parent_t *(*best_parent)(rpl_parent_t *, rpl_parent_t *);
void (*update_metric_container)(void);
rpl_ocp_t ocp;
};
typedef struct rpl_of rpl_of_t;
/*---------------------------------------------------------------------------*/
/* Directed Acyclic Graph */
struct rpl_dag {
uip_ipaddr_t dag_id;
rpl_prefix_t prefix_info;
rpl_parent_t *preferred_parent;
rpl_rank_t lowest_rank; /* The lowest rank seen in the current version */
rpl_rank_t rank; /* The current rank */
uint32_t lifetime;
uint8_t version;
uint8_t grounded;
uint8_t preference;
uint8_t dio_intcurrent; /* Current DIO interval */
uint8_t dio_send; /* internal trickle timer state: do we need to send a DIO at the next wakeup? */
uint8_t dio_counter; /* internal trickle timer state: redundancy counter */
uint8_t dao_last_seqno; /* the node's last sent DAO seqno */
uint8_t dao_last_acked_seqno; /* the last seqno we got an ACK for */
uint8_t dao_curr_seqno; /* the node's current DAO seqno (sent or to be sent) */
uint8_t dao_transmissions; /* the number of transmissions for the current DAO */
uint8_t is_reachable; /* is the node reachable via a downward route? */
/* Timers */
clock_time_t dio_next_delay; /* delay for completion of dio interval */
struct ctimer state_update;
struct ctimer dio_timer;
struct ctimer unicast_dio_timer;
struct ctimer dao_timer;
rpl_parent_t *unicast_dio_target;
#if RPL_WITH_PROBING
struct ctimer probing_timer;
rpl_parent_t *urgent_probing_target;
#endif /* RPL_WITH_PROBING */
#if RPL_WITH_DAO_ACK
uip_ipaddr_t dao_ack_target;
uint16_t dao_ack_sequence;
struct ctimer dao_ack_timer;
#endif /* RPL_WITH_DAO_ACK */
};
typedef struct rpl_dag rpl_dag_t;
/*---------------------------------------------------------------------------*/
/* Instance */
struct rpl_instance {
rpl_metric_container_t mc; /* Metric container. Set to MC_NONE when no mc is used */
rpl_of_t *of; /* The objective function */
uint8_t used;
uint8_t instance_id;
uint8_t mop; /* Mode of operation */
uint8_t dtsn_out;
uint8_t dio_intdoubl;
uint8_t dio_intmin;
uint8_t dio_redundancy;
rpl_rank_t max_rankinc;
rpl_rank_t min_hoprankinc;
uint8_t default_lifetime;
uint16_t lifetime_unit; /* lifetime in seconds = lifetime_unit * default_lifetime */
rpl_dag_t dag; /* We support only one dag */
};
typedef struct rpl_instance rpl_instance_t;
/** @} */
#endif /* RPL_TYPES_H */

185
core/net/rpl-lite/rpl.c Normal file
View File

@ -0,0 +1,185 @@
/*
* Copyright (c) 2009, Swedish Institute of Computer Science.
* 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
* ContikiRPL, an implementation of RPL: IPv6 Routing Protocol
* for Low-Power and Lossy Networks (IETF RFC 6550)
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
/**
* \addtogroup uip6
* @{
*/
#include "rpl.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
uip_ipaddr_t rpl_multicast_addr;
/*---------------------------------------------------------------------------*/
int
rpl_lollipop_greater_than(int a, int b)
{
/* Check if we are comparing an initial value with an old value */
if(a > RPL_LOLLIPOP_CIRCULAR_REGION && b <= RPL_LOLLIPOP_CIRCULAR_REGION) {
return (RPL_LOLLIPOP_MAX_VALUE + 1 + b - a) > RPL_LOLLIPOP_SEQUENCE_WINDOWS;
}
/* Otherwise check if a > b and comparable => ok, or
if they have wrapped and are still comparable */
return (a > b && (a - b) < RPL_LOLLIPOP_SEQUENCE_WINDOWS) ||
(a < b && (b - a) > (RPL_LOLLIPOP_CIRCULAR_REGION + 1-
RPL_LOLLIPOP_SEQUENCE_WINDOWS));
}
/*---------------------------------------------------------------------------*/
const uip_ipaddr_t *
rpl_get_global_address(void)
{
int i;
uint8_t state;
uip_ipaddr_t *ipaddr = NULL;
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
state == ADDR_PREFERRED &&
!uip_is_addr_linklocal(&uip_ds6_if.addr_list[i].ipaddr)) {
ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
}
}
return ipaddr;
}
/*---------------------------------------------------------------------------*/
void
rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
{
if(curr_instance.used == 1 ) {
rpl_parent_t *parent = rpl_parent_get_from_lladdr((uip_lladdr_t *)addr);
if(parent != NULL) {
/* Link stats were updated, and we need to update our internal state.
Updating from here is unsafe; postpone */
rpl_timers_schedule_state_update();
}
}
}
/*---------------------------------------------------------------------------*/
int
rpl_is_reachable(void)
{
return curr_instance.used && curr_instance.dag.is_reachable;
}
/*---------------------------------------------------------------------------*/
static void
set_ip_from_prefix(uip_ipaddr_t *ipaddr, rpl_prefix_t *prefix)
{
memset(ipaddr, 0, sizeof(uip_ipaddr_t));
memcpy(ipaddr, &prefix->prefix, (prefix->length + 7) / 8);
uip_ds6_set_addr_iid(ipaddr, &uip_lladdr);
}
/*---------------------------------------------------------------------------*/
void
rpl_reset_prefix(rpl_prefix_t *last_prefix)
{
uip_ipaddr_t ipaddr;
uip_ds6_addr_t *rep;
set_ip_from_prefix(&ipaddr, last_prefix);
rep = uip_ds6_addr_lookup(&ipaddr);
if(rep != NULL) {
PRINTF("RPL: removing global IP address ");
PRINT6ADDR(&ipaddr);
PRINTF("\n");
uip_ds6_addr_rm(rep);
}
curr_instance.dag.prefix_info.length = 0;
}
/*---------------------------------------------------------------------------*/
int
rpl_set_prefix_from_addr(uip_ipaddr_t *addr, unsigned len, uint8_t flags)
{
uip_ipaddr_t ipaddr;
if(addr == NULL || len == 0 || len > 128 || !(flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
PRINTF("RPL: ignoring DIO with no, not-supported, or invalid prefix\n");
return 0;
}
/* Try and initialize prefix */
memset(&curr_instance.dag.prefix_info.prefix, 0, sizeof(rpl_prefix_t));
memcpy(&curr_instance.dag.prefix_info.prefix, addr, (len + 7) / 8);
curr_instance.dag.prefix_info.length = len;
curr_instance.dag.prefix_info.lifetime = RPL_ROUTE_INFINITE_LIFETIME;
curr_instance.dag.prefix_info.flags = flags;
/* Add global address if not already there */
set_ip_from_prefix(&ipaddr, &curr_instance.dag.prefix_info);
if(uip_ds6_addr_lookup(&ipaddr) == NULL) {
PRINTF("RPL: adding global IP address ");
PRINT6ADDR(&ipaddr);
PRINTF("\n");
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
}
return 1;
}
/*---------------------------------------------------------------------------*/
int
rpl_set_prefix(rpl_prefix_t *prefix)
{
if(prefix != NULL && rpl_set_prefix_from_addr(&prefix->prefix, prefix->length, prefix->flags)) {
curr_instance.dag.prefix_info.lifetime = prefix->lifetime;
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
void
rpl_init(void)
{
PRINTF("RPL: initializing\n");
/* Initialize multicast address and register it */
uip_create_linklocal_rplnodes_mcast(&rpl_multicast_addr);
uip_ds6_maddr_add(&rpl_multicast_addr);
rpl_dag_init();
rpl_parent_init();
rpl_timers_init();
rpl_icmp6_init();
rpl_ns_init();
}
/*---------------------------------------------------------------------------*/
/** @}*/

127
core/net/rpl-lite/rpl.h Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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
* Public API declarations for RPL.
* \author
* Joakim Eriksson <joakime@sics.se> & Nicolas Tsiftes <nvt@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*
*/
#ifndef RPL_H
#define RPL_H
/********** Includes **********/
#include "uip.h"
#include "rpl-const.h"
#include "rpl-conf.h"
#include "rpl-types.h"
#include "rpl-icmp6.h"
#include "rpl-dag.h"
#include "rpl-ns.h"
#include "rpl-dag-root.h"
#include "rpl-parent.h"
#include "rpl-ext-header.h"
#include "rpl-timers.h"
/**
* \addtogroup uip6
* @{
*/
/********** Public symbols **********/
/* The only instance */
extern rpl_instance_t curr_instance;
/* The RPL multicast address (used for DIS and DIO) */
extern uip_ipaddr_t rpl_multicast_addr;
/********** Public functions **********/
/**
* Set prefix from an prefix data structure (from DIO)
*
* \param prefix The prefix
* \return 1 if success, 0 otherwise
*/
int rpl_set_prefix(rpl_prefix_t *prefix);
/**
* Set prefix from an IPv6 address
*
* \param addr The prefix
* \param len The prefix length
* \param flags The DIO prefix flags
* \return 1 if success, 0 otherwise
*/
int rpl_set_prefix_from_addr(uip_ipaddr_t *addr, unsigned len, uint8_t flags);
/**
* Removes current prefx
*
* \param last_prefix The last prefix (which is to be removed)
*/
void rpl_reset_prefix(rpl_prefix_t *last_prefix);
/**
* Get one of the node's global addresses
*
* \return A (constant) pointer to the global IPv6 address found.
* The pointer directs to the internals of DS6, should only be used
* in the current function's local scope
*/
const uip_ipaddr_t *rpl_get_global_address(void);
/**
* Get the RPL's best guess on if we are reachable via have downward route or not.
*
* \return 1 if we are reachable, 0 otherwise.
*/
int rpl_is_reachable(void);
/**
* Greater-than function for a lollipop counter
*
* \param a The first counter
* \param b The second counter
* \return 1 is a>b else 0
*/
int rpl_lollipop_greater_than(int a, int b);
/**
* Initialize RPL main module
*/
void rpl_init(void);
/** @} */
#endif /* RPL_H */

View File

@ -40,11 +40,67 @@
#include "contiki-conf.h"
/* DAG Mode of Operation */
#define RPL_MOP_NO_DOWNWARD_ROUTES 0
#define RPL_MOP_NON_STORING 1
#define RPL_MOP_STORING_NO_MULTICAST 2
#define RPL_MOP_STORING_MULTICAST 3
/* RPL Mode of operation */
#ifdef RPL_CONF_MOP
#define RPL_MOP_DEFAULT RPL_CONF_MOP
#else /* RPL_CONF_MOP */
#if RPL_WITH_MULTICAST
#define RPL_MOP_DEFAULT RPL_MOP_STORING_MULTICAST
#else
#define RPL_MOP_DEFAULT RPL_MOP_STORING_NO_MULTICAST
#endif /* RPL_WITH_MULTICAST */
#endif /* RPL_CONF_MOP */
/*
* Embed support for storing mode
*/
#ifdef RPL_CONF_WITH_STORING
#define RPL_WITH_STORING RPL_CONF_WITH_STORING
#else /* RPL_CONF_WITH_STORING */
/* By default: embed support for non-storing if and only if the configured MOP is not non-storing */
#define RPL_WITH_STORING (RPL_MOP_DEFAULT != RPL_MOP_NON_STORING)
#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 */
/* By default: embed support for non-storing if and only if the configured MOP is non-storing */
#define RPL_WITH_NON_STORING (RPL_MOP_DEFAULT == RPL_MOP_NON_STORING)
#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))
/* Emit a pre-processor error if the user configured multicast with bad MOP */
#if RPL_WITH_MULTICAST && (RPL_MOP_DEFAULT != RPL_MOP_STORING_MULTICAST)
#error "RPL Multicast requires RPL_MOP_DEFAULT==3. Check contiki-conf.h"
#endif
/* Set to 1 to enable RPL statistics */
#ifndef RPL_CONF_STATS
#define RPL_CONF_STATS 0
#endif /* RPL_CONF_STATS */
/* Set to 1 to drop packets when a forwarding loop is detected
* on a packet that already had an error signaled, as per RFC6550 - 11.2.2.2.
* Disabled by default for more reliability: even in the event of a loop,
* packets get a chance to eventually find their way to the destination. */
#ifdef RPL_CONF_LOOP_ERROR_DROP
#define RPL_LOOP_ERROR_DROP RPL_CONF_LOOP_ERROR_DROP
#else /* RPL_CONF_LOOP_ERROR_DROP */
#define RPL_LOOP_ERROR_DROP 0
#endif /* RPL_CONF_LOOP_ERROR_DROP */
/*
* The objective function (OF) used by a RPL root is configurable through
* the RPL_CONF_OF_OCP parameter. This is defined as the objective code
@ -155,7 +211,7 @@
#endif /* RPL_CONF_DAG_LIFETIME */
/*
*
*
*/
#ifndef RPL_CONF_DAO_SPECIFY_DAG
#if RPL_MAX_DAG_PER_INSTANCE > 1
@ -236,7 +292,7 @@
#endif
/*
* RPL DAO ACK support. When enabled, DAO ACK will be sent and requested.
* RPL DAO-ACK support. When enabled, DAO-ACK will be sent and requested.
* This will also enable retransmission of DAO when no ack is received.
* */
#ifdef RPL_CONF_WITH_DAO_ACK
@ -285,7 +341,7 @@
#ifdef RPL_CONF_PROBING_INTERVAL
#define RPL_PROBING_INTERVAL RPL_CONF_PROBING_INTERVAL
#else
#define RPL_PROBING_INTERVAL (120 * CLOCK_SECOND)
#define RPL_PROBING_INTERVAL (60 * CLOCK_SECOND)
#endif
/*

View File

@ -32,9 +32,10 @@
#include "contiki.h"
#include "contiki-net.h"
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-dag-root.h"
#include "rpl.h"
#include "rpl-private.h"
#include "rpl-dag-root.h"
#include "net/ipv6/uip-ds6-route.h"
#include <string.h>
@ -43,9 +44,9 @@
#define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1)
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
static struct uip_ds6_notification n;
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
static uint8_t to_become_root;
static struct ctimer c;
/*---------------------------------------------------------------------------*/
@ -112,7 +113,7 @@ create_dag_callback(void *ptr)
rank, we assume the network has broken, and we become the new
root of the network. */
if(dag->rank == INFINITE_RANK) {
if(dag->rank == RPL_INFINITE_RANK) {
if(to_become_root) {
rpl_dag_root_init_dag_immediately();
to_become_root = 0;
@ -123,7 +124,7 @@ create_dag_callback(void *ptr)
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
}
}
#if (UIP_CONF_MAX_ROUTES != 0)
#if (UIP_MAX_ROUTES != 0)
/*---------------------------------------------------------------------------*/
static void
route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
@ -139,20 +140,29 @@ route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
}
}
}
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
/*---------------------------------------------------------------------------*/
static uip_ipaddr_t *
set_global_address(void)
static void
set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid)
{
static uip_ipaddr_t ipaddr;
static uip_ipaddr_t root_ipaddr;
int i;
uint8_t state;
/* Assign a unique local address (RFC4193,
http://tools.ietf.org/html/rfc4193). */
uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
if(prefix == NULL) {
uip_ip6addr(&root_ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
} else {
memcpy(&root_ipaddr, prefix, 8);
}
if(iid == NULL) {
uip_ds6_set_addr_iid(&root_ipaddr, &uip_lladdr);
} else {
memcpy(((uint8_t*)&root_ipaddr) + 8, ((uint8_t*)iid) + 8, 8);
}
uip_ds6_addr_add(&root_ipaddr, 0, ADDR_AUTOCONF);
printf("IPv6 addresses: ");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
@ -163,21 +173,19 @@ set_global_address(void)
printf("\n");
}
}
return &ipaddr;
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_root_init(void)
rpl_dag_root_init(uip_ipaddr_t *prefix, uip_ipaddr_t *iid)
{
static uint8_t initialized = 0;
if(!initialized) {
to_become_root = 0;
set_global_address();
#if (UIP_CONF_MAX_ROUTES != 0)
set_global_address(prefix, iid);
#if (UIP_MAX_ROUTES != 0)
uip_ds6_notification_add(&n, route_callback);
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
#endif /* (UIP_MAX_ROUTES != 0) */
initialized = 1;
}
}
@ -190,7 +198,7 @@ rpl_dag_root_init_dag_immediately(void)
uint8_t state;
uip_ipaddr_t *ipaddr = NULL;
rpl_dag_root_init();
rpl_dag_root_init(NULL, NULL);
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
@ -236,9 +244,9 @@ rpl_dag_root_init_dag_immediately(void)
}
/*---------------------------------------------------------------------------*/
void
rpl_dag_root_init_dag(void)
rpl_dag_root_init_dag_delay(void)
{
rpl_dag_root_init();
rpl_dag_root_init(NULL, NULL);
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
to_become_root = 1;

View File

@ -32,8 +32,8 @@
#ifndef RPL_DAG_ROOT_H_
#define RPL_DAG_ROOT_H_
void rpl_dag_root_init(void);
void rpl_dag_root_init_dag(void);
void rpl_dag_root_init(uip_ipaddr_t *prefix, uip_ipaddr_t *iid);
void rpl_dag_root_init_dag_delay(void);
int rpl_dag_root_init_dag_immediately(void);
int rpl_dag_root_is_root(void);

View File

@ -45,7 +45,7 @@
#include "contiki.h"
#include "net/link-stats.h"
#include "net/rpl/rpl-private.h"
#include "rpl-private.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-nd6.h"
#include "net/ipv6/uip-ds6-nbr.h"
@ -103,7 +103,7 @@ rpl_print_neighbor_list(void)
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",
rpl_get_parent_ipaddr(p)->u8[15],
rpl_parent_get_ipaddr(p)->u8[15],
p->rank,
rpl_get_parent_link_metric(p),
rpl_rank_via_parent(p),
@ -155,7 +155,7 @@ rpl_get_parent_rank(uip_lladdr_t *addr)
if(p != NULL) {
return p->rank;
} else {
return INFINITE_RANK;
return RPL_INFINITE_RANK;
}
}
/*---------------------------------------------------------------------------*/
@ -180,7 +180,7 @@ rpl_rank_via_parent(rpl_parent_t *p)
return instance->of->rank_via_parent(p);
}
}
return INFINITE_RANK;
return RPL_INFINITE_RANK;
}
/*---------------------------------------------------------------------------*/
const linkaddr_t *
@ -190,7 +190,7 @@ rpl_get_parent_lladdr(rpl_parent_t *p)
}
/*---------------------------------------------------------------------------*/
uip_ipaddr_t *
rpl_get_parent_ipaddr(rpl_parent_t *p)
rpl_parent_get_ipaddr(rpl_parent_t *p)
{
const linkaddr_t *lladdr = rpl_get_parent_lladdr(p);
return uip_ds6_nbr_ipaddr_from_lladdr((uip_lladdr_t *)lladdr);
@ -233,13 +233,13 @@ rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p)
if(dag != NULL && dag->preferred_parent != p) {
PRINTF("RPL: rpl_set_preferred_parent ");
if(p != NULL) {
PRINT6ADDR(rpl_get_parent_ipaddr(p));
PRINT6ADDR(rpl_parent_get_ipaddr(p));
} else {
PRINTF("NULL");
}
PRINTF(" used to be ");
if(dag->preferred_parent != NULL) {
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
PRINT6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent));
} else {
PRINTF("NULL");
}
@ -323,7 +323,7 @@ should_refresh_routes(rpl_instance_t *instance, rpl_dio_t *dio, rpl_parent_t *p)
static int
acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank)
{
return rank != INFINITE_RANK &&
return rank != RPL_INFINITE_RANK &&
((dag->instance->max_rankinc == 0) ||
DAG_RANK(rank, dag->instance) <= DAG_RANK(dag->min_rank + dag->instance->max_rankinc, dag->instance));
}
@ -598,8 +598,8 @@ rpl_alloc_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
if(!dag->used) {
memset(dag, 0, sizeof(*dag));
dag->used = 1;
dag->rank = INFINITE_RANK;
dag->min_rank = INFINITE_RANK;
dag->rank = RPL_INFINITE_RANK;
dag->min_rank = RPL_INFINITE_RANK;
dag->instance = instance;
return dag;
}
@ -766,7 +766,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
} else if(p->dag == best_dag) {
best_dag = NULL;
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != INFINITE_RANK) {
if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != RPL_INFINITE_RANK) {
if(best_dag == NULL) {
best_dag = dag;
} else {
@ -823,7 +823,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
}
if(best_dag->preferred_parent != last_parent) {
rpl_set_default_route(instance, rpl_get_parent_ipaddr(best_dag->preferred_parent));
rpl_set_default_route(instance, rpl_parent_get_ipaddr(best_dag->preferred_parent));
PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n",
(unsigned)old_rank, best_dag->rank);
RPL_STAT(rpl_stats.parent_switch++);
@ -865,7 +865,7 @@ best_parent(rpl_dag_t *dag, int fresh_only)
for(p = nbr_table_head(rpl_parents); p != NULL; p = nbr_table_next(rpl_parents, p)) {
/* Exclude parents from other DAGs or announcing an infinite rank */
if(p->dag != dag || p->rank == INFINITE_RANK || p->rank < ROOT_RANK(dag->instance)) {
if(p->dag != dag || p->rank == RPL_INFINITE_RANK || p->rank < ROOT_RANK(dag->instance)) {
if(p->rank < ROOT_RANK(dag->instance)) {
PRINTF("RPL: Parent has invalid rank\n");
}
@ -934,7 +934,7 @@ void
rpl_remove_parent(rpl_parent_t *parent)
{
PRINTF("RPL: Removing parent ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINT6ADDR(rpl_parent_get_ipaddr(parent));
PRINTF("\n");
rpl_nullify_parent(parent);
@ -949,11 +949,11 @@ rpl_nullify_parent(rpl_parent_t *parent)
/* This function can be called when the preferred parent is NULL, so we
need to handle this condition in order to trigger uip_ds6_defrt_rm. */
if(parent == dag->preferred_parent || dag->preferred_parent == NULL) {
dag->rank = INFINITE_RANK;
dag->rank = RPL_INFINITE_RANK;
if(dag->joined) {
if(dag->instance->def_route != NULL) {
PRINTF("RPL: Removing default route ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINT6ADDR(rpl_parent_get_ipaddr(parent));
PRINTF("\n");
uip_ds6_defrt_rm(dag->instance->def_route);
dag->instance->def_route = NULL;
@ -969,7 +969,7 @@ rpl_nullify_parent(rpl_parent_t *parent)
}
PRINTF("RPL: Nullifying parent ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINT6ADDR(rpl_parent_get_ipaddr(parent));
PRINTF("\n");
}
/*---------------------------------------------------------------------------*/
@ -978,10 +978,10 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
{
if(parent == dag_src->preferred_parent) {
rpl_set_preferred_parent(dag_src, NULL);
dag_src->rank = INFINITE_RANK;
dag_src->rank = RPL_INFINITE_RANK;
if(dag_src->joined && dag_src->instance->def_route != NULL) {
PRINTF("RPL: Removing default route ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINT6ADDR(rpl_parent_get_ipaddr(parent));
PRINTF("\n");
PRINTF("rpl_move_parent\n");
uip_ds6_defrt_rm(dag_src->instance->def_route);
@ -990,12 +990,12 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
} 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);
rpl_remove_routes_by_nexthop(rpl_parent_get_ipaddr(parent), dag_src);
}
}
PRINTF("RPL: Moving parent ");
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINT6ADDR(rpl_parent_get_ipaddr(parent));
PRINTF("\n");
parent->dag = dag_dst;
@ -1283,13 +1283,13 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio)
dag->instance->lifetime_unit = dio->lifetime_unit;
dag->instance->of->reset(dag);
dag->min_rank = INFINITE_RANK;
dag->min_rank = RPL_INFINITE_RANK;
RPL_LOLLIPOP_INCREMENT(dag->instance->dtsn_out);
p = rpl_add_parent(dag, dio, from);
if(p == NULL) {
PRINTF("RPL: Failed to add a parent during the global repair\n");
dag->rank = INFINITE_RANK;
dag->rank = RPL_INFINITE_RANK;
} else {
dag->rank = rpl_rank_via_parent(p);
dag->min_rank = dag->rank;
@ -1316,7 +1316,7 @@ rpl_local_repair(rpl_instance_t *instance)
PRINTF("RPL: Starting a local instance repair\n");
for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) {
if(instance->dag_table[i].used) {
instance->dag_table[i].rank = INFINITE_RANK;
instance->dag_table[i].rank = RPL_INFINITE_RANK;
nullify_parents(&instance->dag_table[i], 0);
}
}
@ -1372,12 +1372,12 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
return_value = 1;
if(RPL_IS_STORING(instance)
&& uip_ds6_route_is_nexthop(rpl_get_parent_ipaddr(p))
&& uip_ds6_route_is_nexthop(rpl_parent_get_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));
PRINT6ADDR(rpl_parent_get_ipaddr(p));
PRINTF("\n");
rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(p), p->dag);
rpl_remove_routes_by_nexthop(rpl_parent_get_ipaddr(p), p->dag);
}
if(!acceptable_rank(p->dag, p->rank)) {
@ -1406,9 +1406,9 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
if(DAG_RANK(old_rank, instance) != DAG_RANK(instance->current_dag->rank, instance)) {
PRINTF("RPL: Moving in the instance from rank %hu to %hu\n",
DAG_RANK(old_rank, instance), DAG_RANK(instance->current_dag->rank, instance));
if(instance->current_dag->rank != INFINITE_RANK) {
if(instance->current_dag->rank != RPL_INFINITE_RANK) {
PRINTF("RPL: The preferred parent is ");
PRINT6ADDR(rpl_get_parent_ipaddr(instance->current_dag->preferred_parent));
PRINT6ADDR(rpl_parent_get_ipaddr(instance->current_dag->preferred_parent));
PRINTF(" (rank %u)\n",
(unsigned)DAG_RANK(instance->current_dag->preferred_parent->rank, instance));
} else {
@ -1538,7 +1538,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
}
if(dag->rank == ROOT_RANK(instance)) {
if(dio->rank != INFINITE_RANK) {
if(dio->rank != RPL_INFINITE_RANK) {
instance->dio_counter++;
}
return;
@ -1588,7 +1588,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
}
p->rank = dio->rank;
if(dio->rank == INFINITE_RANK && p == dag->preferred_parent) {
if(dio->rank == RPL_INFINITE_RANK && p == dag->preferred_parent) {
/* Our preferred parent advertised an infinite rank, reset DIO timer */
rpl_reset_dio_timer(instance);
}

View File

@ -47,8 +47,8 @@
#include "net/ip/uip.h"
#include "net/ip/tcpip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "rpl-private.h"
#include "rpl-ns.h"
#include "net/packetbuf.h"
#define DEBUG DEBUG_NONE
@ -69,7 +69,7 @@
#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_hbh_header(int uip_ext_opt_offset)
rpl_ext_header_hbh_update(int uip_ext_opt_offset)
{
rpl_instance_t *instance;
int down;
@ -176,7 +176,7 @@ rpl_verify_hbh_header(int uip_ext_opt_offset)
/*---------------------------------------------------------------------------*/
#if RPL_WITH_NON_STORING
int
rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr)
rpl_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr)
{
uint8_t *uip_next_hdr;
int last_uip_ext_len = uip_ext_len;
@ -217,7 +217,7 @@ rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr)
dest_node->parent == root_node)) {
/* Routing header found or the packet destined for a direct child of the root.
* 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
* address, via rpl_ext_header_srh_update. 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);
@ -230,7 +230,7 @@ rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr)
}
/*---------------------------------------------------------------------------*/
int
rpl_process_srh_header(void)
rpl_ext_header_srh_update(void)
{
uint8_t *uip_next_hdr;
int last_uip_ext_len = uip_ext_len;
@ -588,7 +588,7 @@ insert_hbh_header(const rpl_instance_t *instance)
}
/*---------------------------------------------------------------------------*/
void
rpl_remove_header(void)
rpl_ext_header_remove(void)
{
uint8_t temp_len;
uint8_t rpl_ext_hdr_len;
@ -633,7 +633,7 @@ rpl_remove_header(void)
}
/*---------------------------------------------------------------------------*/
int
rpl_update_header(void)
rpl_ext_header_update(void)
{
if(default_instance == NULL || default_instance->current_dag == NULL
|| uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) || uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
@ -643,7 +643,7 @@ rpl_update_header(void)
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();
rpl_ext_header_remove();
if(rpl_get_dag(&UIP_IP_BUF->destipaddr) != NULL) {
/* dest is in a DODAG; the packet is going down. */
if(RPL_IS_NON_STORING(default_instance)) {

View File

@ -50,8 +50,8 @@
#include "net/ipv6/uip-ds6.h"
#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 "rpl-private.h"
#include "rpl-ns.h"
#include "net/packetbuf.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#include "random.h"
@ -494,8 +494,8 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
is_root = (dag->rank == ROOT_RANK(instance));
#if RPL_LEAF_ONLY
PRINTF("RPL: LEAF ONLY DIO rank set to INFINITE_RANK\n");
set16(buffer, pos, INFINITE_RANK);
PRINTF("RPL: LEAF ONLY DIO rank set to RPL_INFINITE_RANK\n");
set16(buffer, pos, RPL_INFINITE_RANK);
#else /* RPL_LEAF_ONLY */
set16(buffer, pos, dag->rank);
#endif /* RPL_LEAF_ONLY */
@ -701,7 +701,7 @@ dao_input_storing(void)
DAG_RANK(parent->rank, instance) < DAG_RANK(dag->rank, instance)) {
PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
parent->rank = INFINITE_RANK;
parent->rank = RPL_INFINITE_RANK;
parent->flags |= RPL_PARENT_FLAG_UPDATED;
return;
}
@ -709,7 +709,7 @@ dao_input_storing(void)
/* If we get the DAO from our parent, we also have a loop. */
if(parent != NULL && parent == dag->preferred_parent) {
PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n");
parent->rank = INFINITE_RANK;
parent->rank = RPL_INFINITE_RANK;
parent->flags |= RPL_PARENT_FLAG_UPDATED;
return;
}
@ -782,18 +782,18 @@ dao_input_storing(void)
/* We forward the incoming No-Path DAO to our parent, if we have
one. */
if(dag->preferred_parent != NULL &&
rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) {
rpl_parent_get_ipaddr(dag->preferred_parent) != NULL) {
uint8_t out_seq;
out_seq = prepare_for_dao_fwd(sequence, rep);
PRINTF("RPL: Forwarding No-path DAO to parent - out_seq:%d",
out_seq);
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
PRINT6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent));
PRINTF("\n");
buffer = UIP_ICMP_PAYLOAD;
buffer[3] = out_seq; /* add an outgoing seq no before fwd */
uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
uip_icmp6_send(rpl_parent_get_ipaddr(dag->preferred_parent),
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
}
}
@ -866,7 +866,7 @@ fwd_dao:
}
if(dag->preferred_parent != NULL &&
rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) {
rpl_parent_get_ipaddr(dag->preferred_parent) != NULL) {
uint8_t out_seq = 0;
if(rep != NULL) {
/* if this is pending and we get the same seq no it is a retrans */
@ -880,12 +880,12 @@ fwd_dao:
}
PRINTF("RPL: Forwarding DAO to parent ");
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
PRINT6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent));
PRINTF(" in seq: %d out seq: %d\n", sequence, out_seq);
buffer = UIP_ICMP_PAYLOAD;
buffer[3] = out_seq; /* add an outgoing seq no before fwd */
uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
uip_icmp6_send(rpl_parent_get_ipaddr(dag->preferred_parent),
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
}
if(should_ack) {
@ -1155,7 +1155,7 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
return;
}
parent_ipaddr = rpl_get_parent_ipaddr(parent);
parent_ipaddr = rpl_parent_get_ipaddr(parent);
if(parent_ipaddr == NULL) {
PRINTF("RPL dao_output_target error parent IP address NULL\n");
return;

View File

@ -46,8 +46,8 @@
* @{
*/
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#include "rpl-private.h"
#include "net/nbr-table.h"
#include "net/link-stats.h"
@ -166,7 +166,7 @@ rank_via_parent(rpl_parent_t *p)
uint16_t path_cost;
if(p == NULL || p->dag == NULL || p->dag->instance == NULL) {
return INFINITE_RANK;
return RPL_INFINITE_RANK;
}
min_hoprankinc = p->dag->instance->min_hoprankinc;

View File

@ -44,7 +44,7 @@
*
*/
#include "net/rpl/rpl-private.h"
#include "rpl-private.h"
#include "net/nbr-table.h"
#include "net/ipv6/uip-ds6-nbr.h"
#include "net/ipv6/uip-ds6-route.h"
@ -134,7 +134,7 @@ update_nbr(void)
* This is the preferred parent for the DAG and must not be removed
* Note: this assumes that only RPL adds default routes.
*/
} else if(is_used == 0 && worst_rank < INFINITE_RANK &&
} else if(is_used == 0 && worst_rank < RPL_INFINITE_RANK &&
parent->rank > 0 &&
parent->dag != NULL &&
parent->dag->instance != NULL &&
@ -150,7 +150,7 @@ update_nbr(void)
if(is_used == 0) {
/* This neighbor is neither parent or child and can be safely removed */
worst_rank_nbr = lladdr;
worst_rank = INFINITE_RANK;
worst_rank = RPL_INFINITE_RANK;
} else if(is_used > 1) {
PRINTF("NBR-POLICY: *** Neighbor is both child and candidate parent: ");
PRINTLLADDR((uip_lladdr_t *)lladdr);
@ -225,7 +225,7 @@ find_removable_dao(uip_ipaddr_t *from, rpl_instance_t *instance)
max = NBR_TABLE_MAX_NEIGHBORS;
}
}
/* Check if this DAO sender is not yet neighbor and there is already too
many children. */
if(num_children >= max) {

View File

@ -37,14 +37,14 @@
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#include "net/rpl/rpl-conf.h"
#include "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 "rpl-private.h"
#include "rpl-ns.h"
#include "lib/list.h"
#include "lib/memb.h"
@ -210,7 +210,7 @@ rpl_ns_periodic(void)
l->lifetime--;
}
}
/* Second pass, for all expire nodes, deallocate them iff no child points to them */
/* Second pass, for all expired 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;

View File

@ -46,13 +46,16 @@
#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
#if RPL_WITH_NON_STORING
#define RPL_NS_LINK_NUM CONTIKI_NETWORK_SIZE
#else
#define RPL_NS_LINK_NUM 0
#endif
#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;

View File

@ -42,8 +42,8 @@
* @{
*/
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#include "rpl-private.h"
#include "net/nbr-table.h"
#include "net/link-stats.h"
@ -122,7 +122,7 @@ parent_rank_increase(rpl_parent_t *p)
{
uint16_t min_hoprankinc;
if(p == NULL || p->dag == NULL || p->dag->instance == NULL) {
return INFINITE_RANK;
return RPL_INFINITE_RANK;
}
min_hoprankinc = p->dag->instance->min_hoprankinc;
return (RANK_FACTOR * STEP_OF_RANK(p) + RANK_STRETCH) * min_hoprankinc;
@ -142,9 +142,9 @@ static rpl_rank_t
rank_via_parent(rpl_parent_t *p)
{
if(p == NULL) {
return INFINITE_RANK;
return RPL_INFINITE_RANK;
} else {
return MIN((uint32_t)p->rank + parent_rank_increase(p), INFINITE_RANK);
return MIN((uint32_t)p->rank + parent_rank_increase(p), RPL_INFINITE_RANK);
}
}
/*---------------------------------------------------------------------------*/

View File

@ -37,7 +37,7 @@
#ifndef RPL_PRIVATE_H
#define RPL_PRIVATE_H
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "lib/list.h"
#include "net/ip/uip.h"
@ -45,7 +45,7 @@
#include "sys/ctimer.h"
#include "net/ipv6/uip-ds6.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/rpl/rpl-ns.h"
#include "rpl-ns.h"
#include "net/ipv6/multicast/uip-mcast6.h"
/*---------------------------------------------------------------------------*/
@ -187,7 +187,7 @@
/* Rank of a root node. */
#define ROOT_RANK(instance) (instance)->min_hoprankinc
#define INFINITE_RANK 0xffff
#define RPL_INFINITE_RANK 0xffff
/*---------------------------------------------------------------------------*/
#define RPL_INSTANCE_LOCAL_FLAG 0x80
@ -199,65 +199,6 @@
#define RPL_ROUTE_FROM_MULTICAST_DAO 2
#define RPL_ROUTE_FROM_DIO 3
/* DAG Mode of Operation */
#define RPL_MOP_NO_DOWNWARD_ROUTES 0
#define RPL_MOP_NON_STORING 1
#define RPL_MOP_STORING_NO_MULTICAST 2
#define RPL_MOP_STORING_MULTICAST 3
/* RPL Mode of operation */
#ifdef RPL_CONF_MOP
#define RPL_MOP_DEFAULT RPL_CONF_MOP
#else /* RPL_CONF_MOP */
#if RPL_WITH_MULTICAST
#define RPL_MOP_DEFAULT RPL_MOP_STORING_MULTICAST
#else
#define RPL_MOP_DEFAULT RPL_MOP_STORING_NO_MULTICAST
#endif /* RPL_WITH_MULTICAST */
#endif /* RPL_CONF_MOP */
/*
* Embed support for storing mode
*/
#ifdef RPL_CONF_WITH_STORING
#define RPL_WITH_STORING RPL_CONF_WITH_STORING
#else /* RPL_CONF_WITH_STORING */
/* By default: embed support for non-storing if and only if the configured MOP is not non-storing */
#define RPL_WITH_STORING (RPL_MOP_DEFAULT != RPL_MOP_NON_STORING)
#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 */
/* By default: embed support for non-storing if and only if the configured MOP is non-storing */
#define RPL_WITH_NON_STORING (RPL_MOP_DEFAULT == RPL_MOP_NON_STORING)
#endif /* RPL_CONF_WITH_NON_STORING */
#if RPL_WITH_STORING && (UIP_DS6_ROUTE_NB == 0)
#error "RPL with storing mode included but #routes == 0. Set UIP_CONF_MAX_ROUTES accordingly."
#if !RPL_WITH_NON_STORING && (RPL_NS_LINK_NUM > 0)
#error "You might also want to set RPL_NS_CONF_LINK_NUM to 0."
#endif
#endif
#if RPL_WITH_NON_STORING && (RPL_NS_LINK_NUM == 0)
#error "RPL with non-storing mode included but #links == 0. Set RPL_NS_CONF_LINK_NUM accordingly."
#if !RPL_WITH_STORING && (UIP_DS6_ROUTE_NB > 0)
#error "You might also want to set UIP_CONF_MAX_ROUTES to 0."
#endif
#endif
#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))
/* Emit a pre-processor error if the user configured multicast with bad MOP */
#if RPL_WITH_MULTICAST && (RPL_MOP_DEFAULT != RPL_MOP_STORING_MULTICAST)
#error "RPL Multicast requires RPL_MOP_DEFAULT==3. Check contiki-conf.h"
#endif
/* Multicast Route Lifetime as a multiple of the lifetime unit */
#ifdef RPL_CONF_MCAST_LIFETIME
#define RPL_MCAST_LIFETIME RPL_CONF_MCAST_LIFETIME
@ -311,7 +252,7 @@ struct rpl_dio {
};
typedef struct rpl_dio rpl_dio_t;
#if RPL_CONF_STATS
#if RPL_CONF_STATS
/* Statistics for fault management. */
struct rpl_stats {
uint16_t mem_overflows;
@ -335,10 +276,11 @@ extern rpl_stats_t rpl_stats;
/* RPL macros. */
#if RPL_CONF_STATS
#define RPL_STAT(code) (code)
#define RPL_STAT(code) (code)
#else
#define RPL_STAT(code)
#endif /* RPL_CONF_STATS */
/*---------------------------------------------------------------------------*/
/* Instances */
extern rpl_instance_t instance_table[];

View File

@ -42,8 +42,8 @@
*/
#include "contiki-conf.h"
#include "net/rpl/rpl-private.h"
#include "net/rpl/rpl-ns.h"
#include "rpl-private.h"
#include "rpl-ns.h"
#include "net/link-stats.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#include "lib/random.h"
@ -362,7 +362,7 @@ static void
handle_unicast_dio_timer(void *ptr)
{
rpl_instance_t *instance = (rpl_instance_t *)ptr;
uip_ipaddr_t *target_ipaddr = rpl_get_parent_ipaddr(instance->unicast_dio_target);
uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(instance->unicast_dio_target);
if(target_ipaddr != NULL) {
dio_output(instance, target_ipaddr);
@ -402,7 +402,7 @@ get_probing_target(rpl_dag_t *dag)
rpl_parent_t *p;
rpl_parent_t *probing_target = NULL;
rpl_rank_t probing_target_rank = INFINITE_RANK;
rpl_rank_t probing_target_rank = RPL_INFINITE_RANK;
clock_time_t probing_target_age = 0;
clock_time_t clock_now = clock_time();
@ -462,7 +462,7 @@ handle_probing_timer(void *ptr)
{
rpl_instance_t *instance = (rpl_instance_t *)ptr;
rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(instance->current_dag);
uip_ipaddr_t *target_ipaddr = rpl_get_parent_ipaddr(probing_target);
uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
/* Perform probing */
if(target_ipaddr != NULL) {

View File

@ -46,8 +46,8 @@
#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 "rpl-private.h"
#include "rpl-ns.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#define DEBUG DEBUG_NONE
@ -290,7 +290,7 @@ rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr)
if(instance->used == 1 ) {
p = rpl_find_parent_any_dag(instance, &nbr->ipaddr);
if(p != NULL) {
p->rank = INFINITE_RANK;
p->rank = RPL_INFINITE_RANK;
/* Trigger DAG rank recalculation. */
PRINTF("RPL: rpl_ipv6_neighbor_callback infinite rank\n");
p->flags |= RPL_PARENT_FLAG_UPDATED;

View File

@ -274,25 +274,24 @@ 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(void);
int rpl_finalize_header(uip_ipaddr_t *addr);
int rpl_verify_hbh_header(int);
int rpl_ext_header_update(void);
int rpl_ext_header_hbh_update(int);
void rpl_insert_header(void);
void rpl_remove_header(void);
void rpl_ext_header_remove(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);
uint16_t rpl_get_parent_link_metric(rpl_parent_t *p);
rpl_rank_t rpl_rank_via_parent(rpl_parent_t *p);
const linkaddr_t *rpl_get_parent_lladdr(rpl_parent_t *p);
uip_ipaddr_t *rpl_get_parent_ipaddr(rpl_parent_t *nbr);
uip_ipaddr_t *rpl_parent_get_ipaddr(rpl_parent_t *nbr);
rpl_parent_t *rpl_get_parent(uip_lladdr_t *addr);
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);
int rpl_ext_header_srh_update(void);
int rpl_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr);
/* Per-parent RPL information */
NBR_TABLE_DECLARE(rpl_parents);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, RISE SICS.
* Copyright (c) 2017, Inria.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,7 +34,7 @@
* \file
* Default log levels for a number of modules
* \author
* Simon Duquennoy <simon.duquennoy@ri.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
/** \addtogroup sys

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, RISE SICS.
* Copyright (c) 2017, Inria.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,7 +34,7 @@
* \file
* Header file for the logging system
* \author
* Simon Duquennoy <simon.duquennoy@ri.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
/** \addtogroup sys

View File

@ -2,6 +2,8 @@ all: http-example
CONTIKI=../..
APPS += http-socket
CONTIKI_WITH_IPV6 = 1
CONTIKI_WITH_RPL_LITE = 0
include $(CONTIKI)/Makefile.include

View File

@ -1,5 +1,7 @@
all: ip64-router
CONTIKI=../..
CONTIKI_WITH_IPV6 = 1
CONTIKI_WITH_RPL_LITE = 0
include $(CONTIKI)/Makefile.include

View File

@ -2,7 +2,7 @@
#include "contiki-net.h"
#include "ip64.h"
#include "net/netstack.h"
#include "net/rpl/rpl-dag-root.h"
#include "rpl-dag-root.h"
/*---------------------------------------------------------------------------*/
PROCESS(router_node_process, "Router node");
@ -13,7 +13,7 @@ PROCESS_THREAD(router_node_process, ev, data)
PROCESS_BEGIN();
/* Set us up as a RPL root node. */
rpl_dag_root_init_dag();
rpl_dag_root_init_dag_delay();
/* Initialize the IP64 module so we'll start translating packets */
ip64_init();

View File

@ -38,7 +38,8 @@
#include "contiki.h"
#include "net/ip/uip.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "rpl-dag-root.h"
#include "net/netstack.h"
#include "er-coap-constants.h"
#include "er-coap-engine.h"
@ -245,16 +246,8 @@ setup_network(void)
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
#endif
uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL);
root_if = uip_ds6_addr_lookup(&ipaddr);
if(root_if != NULL) {
dag = rpl_set_root(RPL_DEFAULT_INSTANCE, &ipaddr);
uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &ipaddr, 64);
PRINTF("created a new RPL dag\n");
} else {
PRINTF("failed to create a new RPL DAG\n");
}
rpl_dag_root_init(&ipaddr, &ipaddr);
rpl_dag_root_init_dag_immediately();
#endif /* UIP_CONF_ROUTER */
PRINTF("IPv6 addresses: ");

View File

@ -87,7 +87,7 @@
#undef COAP_PROXY_OPTION_PROCESSING
#define COAP_PROXY_OPTION_PROCESSING 0
/* Turn off DAO ACK to make code smaller */
/* Turn off DAO-ACK to make code smaller */
#undef RPL_CONF_WITH_DAO_ACK
#define RPL_CONF_WITH_DAO_ACK 0

View File

@ -50,10 +50,10 @@
#undef QUEUEBUF_CONF_NUM
#define QUEUEBUF_CONF_NUM 4
#undef NBR_TABLE_CONF_MAX_NEIGHBORS
#define NBR_TABLE_CONF_MAX_NEIGHBORS 7
#undef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 7
#undef CONTIKI_NETWORK_SIZE
#define CONTIKI_NETWORK_SIZE 7
#undef CONTIKI_NETWORK_DENSITY
#define CONTIKI_NETWORK_DENSITY 7
#undef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 140

View File

@ -8,4 +8,5 @@ CONTIKI = ../../..
MODULES += core/net/ipv6/multicast
CONTIKI_WITH_IPV6 = 1
CONTIKI_WITH_RPL_LITE = 1
include $(CONTIKI)/Makefile.include

View File

@ -60,9 +60,9 @@
#define UIP_CONF_TCP 0
/* Code/RAM footprint savings so that things will fit on our device */
#undef NBR_TABLE_CONF_MAX_NEIGHBORS
#undef UIP_CONF_MAX_ROUTES
#define NBR_TABLE_CONF_MAX_NEIGHBORS 10
#define UIP_CONF_MAX_ROUTES 10
#undef CONTIKI_NETWORK_SIZE
#define CONTIKI_NETWORK_SIZE 10
#undef CONTIKI_NETWORK_DENSITY
#define CONTIKI_NETWORK_DENSITY 10
#endif /* PROJECT_CONF_H_ */

View File

@ -48,7 +48,8 @@
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "rpl-dag-root.h"
#define MAX_PAYLOAD_LEN 120
#define MCAST_SINK_UDP_PORT 3001 /* Host byte order */
@ -103,42 +104,6 @@ prepare_mcast(void)
mcast_conn = udp_new(&ipaddr, UIP_HTONS(MCAST_SINK_UDP_PORT), NULL);
}
/*---------------------------------------------------------------------------*/
static void
set_own_addresses(void)
{
int i;
uint8_t state;
rpl_dag_t *dag;
uip_ipaddr_t ipaddr;
uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
PRINTF("Our IPv6 addresses:\n");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused && (state == ADDR_TENTATIVE || state
== ADDR_PREFERRED)) {
PRINTF(" ");
PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
PRINTF("\n");
if(state == ADDR_TENTATIVE) {
uip_ds6_if.addr_list[i].state = ADDR_PREFERRED;
}
}
}
/* Become root of a new DODAG with ID our global v6 address */
dag = rpl_set_root(RPL_DEFAULT_INSTANCE, &ipaddr);
if(dag != NULL) {
rpl_set_prefix(dag, &ipaddr, 64);
PRINTF("Created a new RPL dag with ID: ");
PRINT6ADDR(&dag->dag_id);
PRINTF("\n");
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(rpl_root_process, ev, data)
{
static struct etimer et;
@ -147,7 +112,7 @@ PROCESS_THREAD(rpl_root_process, ev, data)
PRINTF("Multicast Engine: '%s'\n", UIP_MCAST6.name);
set_own_addresses();
rpl_dag_root_init_dag_immediately();
prepare_mcast();

View File

@ -40,7 +40,7 @@
#include "border-router.h"
#include "border-router-cmds.h"
#include "dev/serial-line.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "net/ip/uiplib.h"
#include <string.h>
@ -68,7 +68,11 @@ border_router_cmd_handler(const uint8_t *data, int len)
if(data[1] == 'G' && command_context == CMD_CONTEXT_STDIO) {
/* This is supposed to be from stdin */
printf("Performing Global Repair...\n");
#if UIP_CONF_IPV6_RPL_LITE
rpl_global_repair();
#else
rpl_repair_root(RPL_DEFAULT_INSTANCE);
#endif
return 1;
} else if(data[1] == 'M' && command_context == CMD_CONTEXT_RADIO) {
/* We need to know that this is from the slip-radio here. */

View File

@ -43,7 +43,8 @@
#include "contiki-net.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "rpl-dag-root.h"
#include "net/netstack.h"
#include "dev/slip.h"
@ -290,20 +291,10 @@ border_router_set_sensors(const char *data, int len)
static void
set_prefix_64(const uip_ipaddr_t *prefix_64)
{
rpl_dag_t *dag;
uip_ipaddr_t ipaddr;
memcpy(&prefix, prefix_64, 16);
memcpy(&ipaddr, prefix_64, 16);
prefix_set = 1;
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
dag = rpl_set_root(RPL_DEFAULT_INSTANCE, &ipaddr);
if(dag != NULL) {
rpl_set_prefix(dag, &prefix, 64);
PRINTF("created a new RPL dag\n");
}
rpl_dag_root_init(prefix_64, NULL);
rpl_dag_root_init_dag_immediately();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(border_router_process, ev, data)

View File

@ -40,10 +40,13 @@
#include "contiki-net.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#include "rpl-dag-root.h"
#if RPL_WITH_NON_STORING
#include "net/rpl/rpl-ns.h"
#include "rpl-ns.h"
#endif /* RPL_WITH_NON_STORING */
#include "net/netstack.h"
#include "dev/button-sensor.h"
@ -382,19 +385,10 @@ request_prefix(void)
void
set_prefix_64(uip_ipaddr_t *prefix_64)
{
rpl_dag_t *dag;
uip_ipaddr_t ipaddr;
memcpy(&prefix, prefix_64, 16);
memcpy(&ipaddr, prefix_64, 16);
prefix_set = 1;
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
dag = rpl_set_root(RPL_DEFAULT_INSTANCE, &ipaddr);
if(dag != NULL) {
rpl_set_prefix(dag, &prefix, 64);
PRINTF("created a new RPL dag\n");
}
rpl_dag_root_init(prefix_64, NULL);
rpl_dag_root_init_dag_immediately();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(border_router_process, ev, data)
@ -432,7 +426,11 @@ PROCESS_THREAD(border_router_process, ev, data)
PROCESS_YIELD();
if (ev == sensors_event && data == &button_sensor) {
PRINTF("Initiating global repair\n");
#if UIP_CONF_IPV6_RPL_LITE
rpl_global_repair();
#else
rpl_repair_root(RPL_DEFAULT_INSTANCE);
#endif
}
}

View File

@ -36,10 +36,6 @@
#endif /* WITH_NON_STORING */
#if WITH_NON_STORING
#undef RPL_NS_CONF_LINK_NUM
#define RPL_NS_CONF_LINK_NUM 40 /* Number of links maintained at the root */
#undef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 0 /* No need for routes */
#undef RPL_CONF_MOP
#define RPL_CONF_MOP RPL_MOP_NON_STORING /* Mode of operation*/
#endif /* WITH_NON_STORING */

View File

@ -0,0 +1,8 @@
all: node
CONTIKI=../../..
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
CONTIKI_WITH_IPV6 = 1
CONTIKI_WITH_RPL_LITE = 1
include $(CONTIKI)/Makefile.include

View File

@ -0,0 +1,150 @@
/*
* 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.
*
*/
#include "contiki.h"
#include "lib/random.h"
#include "sys/ctimer.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/ip/uip-udp-packet.h"
#include "rpl.h"
#include "rpl-dag-root.h"
#include "node-id.h"
#include "simple-udp.h"
#include "sys/ctimer.h"
#include <stdio.h>
#include <string.h>
#include "dev/serial-line.h"
#include "net/ipv6/uip-ds6-route.h"
#define UDP_PORT 8765
#define START_INTERVAL (15 * CLOCK_SECOND)
#define SEND_INTERVAL (60 * CLOCK_SECOND)
static struct simple_udp_connection udp_conn;
static uip_ipaddr_t node_ipaddr;
static uip_ipaddr_t root_ipaddr;
static uip_ipaddr_t destination_ipaddr;
/*---------------------------------------------------------------------------*/
PROCESS(node_process, "RPL Simple Process");
AUTOSTART_PROCESSES(&node_process);
/*---------------------------------------------------------------------------*/
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
int seq_id;
memcpy(&seq_id, data, sizeof(int));
if(uip_ip6addr_cmp(&destination_ipaddr, &node_ipaddr)) {
printf("App: received %u from %u\n", seq_id, sender_addr->u8[15]);
printf("App: sending reply to %u\n", sender_addr->u8[15]);
simple_udp_sendto(&udp_conn, &seq_id, sizeof(seq_id), sender_addr);
} else {
printf("App: received reply %u from %u\n", seq_id, sender_addr->u8[15]);
}
}
/*---------------------------------------------------------------------------*/
static void
send_packet(void *ptr)
{
if(rpl_get_default_instance() != NULL) {
static int seq_id = 0;
printf("App: sending request %u to %u\n", ++seq_id, destination_ipaddr.u8[15]);
simple_udp_sendto(&udp_conn, &seq_id, sizeof(seq_id), &destination_ipaddr);
} else {
printf("App: not joined\n");
}
}
/*---------------------------------------------------------------------------*/
static void
get_global_address(void)
{
int i;
uint8_t state;
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
state == ADDR_PREFERRED &&
!uip_is_addr_linklocal(&uip_ds6_if.addr_list[i].ipaddr)) {
uip_ip6addr_copy(&node_ipaddr, &uip_ds6_if.addr_list[i].ipaddr);
}
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(node_process, ev, data)
{
static struct etimer periodic;
static struct ctimer backoff_timer;
PROCESS_BEGIN();
/* Hardcoded IPv6 addresses */
uip_ip6addr(&root_ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101);
uip_ip6addr(&destination_ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101);
rpl_dag_root_init(NULL, NULL);
get_global_address();
/* Configure root */
if(uip_ip6addr_cmp(&root_ipaddr, &node_ipaddr)) {
rpl_dag_root_init_dag_immediately();
}
/* New connection with remote host */
simple_udp_register(&udp_conn, UDP_PORT, NULL, UDP_PORT, receiver);
/* Wait for START_INTERVAL */
etimer_set(&periodic, START_INTERVAL);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic));
if(!uip_ip6addr_cmp(&destination_ipaddr, &node_ipaddr)) {
/* Send data periodically */
etimer_set(&periodic, SEND_INTERVAL);
while(1) {
PROCESS_YIELD();
if(etimer_expired(&periodic)) {
etimer_reset(&periodic);
ctimer_set(&backoff_timer, random_rand() % (SEND_INTERVAL), send_packet, NULL);
}
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2015, Swedish Institute of Computer Science.
* 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.
*/
#ifndef PROJECT_CONF_H_
#define PROJECT_CONF_H_
#undef CSMA_CONF_802154_AUTOACK
#define CSMA_CONF_802154_AUTOACK 1
#endif

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[APPS_DIR]/mrm</project>
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
<project EXPORT="discard">[APPS_DIR]/avrora</project>
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
<simulation>
<title>Simple RPL Example</title>
<randomseed>generated</randomseed>
<motedelay_us>5000000</motedelay_us>
<radiomedium>
org.contikios.cooja.radiomediums.UDGM
<transmitting_range>50.0</transmitting_range>
<interference_range>50.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
org.contikios.cooja.mspmote.SkyMoteType
<identifier>sky2</identifier>
<description>Sky Mote Type #sky2</description>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rpl-simple/node.sky</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
</motetype>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>48.435974731198804</x>
<y>-66.16503914182063</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>1</id>
</interface_config>
<motetype_identifier>sky2</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>28.87281458333398</x>
<y>-21.744318674852618</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>2</id>
</interface_config>
<motetype_identifier>sky2</motetype_identifier>
</mote>
</simulation>
<plugin>
org.contikios.cooja.plugins.SimControl
<width>185</width>
<z>2</z>
<height>154</height>
<location_x>1651</location_x>
<location_y>778</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Visualizer
<plugin_config>
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.AttributeVisualizerSkin</skin>
<viewport>1.260147830790386 0.0 0.0 1.260147830790386 105.5104655860535 140.74330745981246</viewport>
</plugin_config>
<width>258</width>
<z>1</z>
<height>309</height>
<location_x>1573</location_x>
<location_y>11</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.LogListener
<plugin_config>
<filter />
<formatted_time />
<coloring />
</plugin_config>
<width>854</width>
<z>3</z>
<height>919</height>
<location_x>5</location_x>
<location_y>2</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.TimeLine
<plugin_config>
<mote>0</mote>
<mote>1</mote>
<showRadioRXTX />
<showRadioHW />
<showLEDs />
<zoomfactor>2736.9736958636</zoomfactor>
</plugin_config>
<width>1858</width>
<z>4</z>
<height>223</height>
<location_x>0</location_x>
<location_y>931</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.RadioLogger
<plugin_config>
<split>477</split>
<formatted_time />
<showdups>false</showdups>
<hidenodests>false</hidenodests>
<analyzers name="6lowpan" />
</plugin_config>
<width>874</width>
<z>0</z>
<height>917</height>
<location_x>857</location_x>
<location_y>10</location_y>
</plugin>
</simconf>

View File

@ -38,10 +38,13 @@
#include "contiki.h"
#include "node-id.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "rpl-dag-root.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/mac/tsch/tsch.h"
#include "net/rpl/rpl-private.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#if WITH_ORCHESTRA
#include "orchestra.h"
#endif /* WITH_ORCHESTRA */
@ -144,16 +147,12 @@ print_network_status(void)
static void
net_init(uip_ipaddr_t *br_prefix)
{
uip_ipaddr_t global_ipaddr;
if(br_prefix) { /* We are RPL root. Will be set automatically
as TSCH pan coordinator via the tsch-rpl module */
memcpy(&global_ipaddr, br_prefix, 16);
uip_ds6_set_addr_iid(&global_ipaddr, &uip_lladdr);
uip_ds6_addr_add(&global_ipaddr, 0, ADDR_AUTOCONF);
rpl_set_root(RPL_DEFAULT_INSTANCE, &global_ipaddr);
rpl_set_prefix(rpl_get_any_dag(), br_prefix, 64);
rpl_repair_root(RPL_DEFAULT_INSTANCE);
rpl_dag_root_init(br_prefix, NULL);
rpl_dag_root_init_dag_immediately();
} else {
rpl_dag_root_init(NULL, NULL);
}
NETSTACK_MAC.on();

View File

@ -49,8 +49,6 @@
/********* Enable RPL non-storing mode *****************/
/*******************************************************/
#undef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 0 /* No need for routes */
#undef RPL_CONF_MOP
#define RPL_CONF_MOP RPL_MOP_NON_STORING /* Mode of operation*/
#undef ORCHESTRA_CONF_RULES
@ -142,6 +140,12 @@
#if CONTIKI_TARGET_COOJA
#define COOJA_CONF_SIMULATE_TURNAROUND 0
/* A bug in cooja causes many EBs to be missed at scan. Increase EB
frequency to shorten the join process */
#undef TSCH_CONF_EB_PERIOD
#define TSCH_CONF_EB_PERIOD (4 * CLOCK_SECOND)
#undef TSCH_CONF_MAX_EB_PERIOD
#define TSCH_CONF_MAX_EB_PERIOD (4 * CLOCK_SECOND)
#endif /* CONTIKI_TARGET_COOJA */
#endif /* __PROJECT_CONF_H__ */

View File

@ -34,17 +34,14 @@
#define WITH_NON_STORING 0 /* Set this to run with non-storing mode */
#endif /* WITH_NON_STORING */
#undef NBR_TABLE_CONF_MAX_NEIGHBORS
#undef UIP_CONF_MAX_ROUTES
#ifdef TEST_MORE_ROUTES
/* configure number of neighbors and routes */
#define NBR_TABLE_CONF_MAX_NEIGHBORS 10
#define UIP_CONF_MAX_ROUTES 30
#define CONTIKI_NETWORK_DENSITY 10
#define CONTIKI_NETWORK_SIZE 30
#else
/* configure number of neighbors and routes */
#define NBR_TABLE_CONF_MAX_NEIGHBORS 10
#define UIP_CONF_MAX_ROUTES 10
#define CONTIKI_NETWORK_DENSITY 10
#define CONTIKI_NETWORK_SIZE 10
#endif /* TEST_MORE_ROUTES */
#undef CSMA_CONF_802154_AUTOACK
@ -59,10 +56,6 @@
#define RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME 1
#if WITH_NON_STORING
#undef RPL_NS_CONF_LINK_NUM
#define RPL_NS_CONF_LINK_NUM 40 /* Number of links maintained at the root. Can be set to 0 at non-root nodes. */
#undef UIP_CONF_MAX_ROUTES
#define UIP_CONF_MAX_ROUTES 0 /* No need for routes */
#undef RPL_CONF_MOP
#define RPL_CONF_MOP RPL_MOP_NON_STORING /* Mode of operation*/
#endif /* WITH_NON_STORING */

View File

@ -31,7 +31,8 @@
#include "contiki-lib.h"
#include "contiki-net.h"
#include "net/ip/uip.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "rpl-dag-root.h"
#include "net/netstack.h"
#include "dev/button-sensor.h"
@ -123,7 +124,7 @@ PROCESS_THREAD(udp_server_process, ev, data)
* Note Wireshark's IPCMV6 checksum verification depends on the correct
* uncompressed addresses.
*/
#if 0
/* Mode 1 - 64 bits inline */
uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 1);
@ -135,20 +136,10 @@ PROCESS_THREAD(udp_server_process, ev, data)
uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
#endif
uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL);
root_if = uip_ds6_addr_lookup(&ipaddr);
if(root_if != NULL) {
rpl_dag_t *dag;
dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr);
uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &ipaddr, 64);
PRINTF("created a new RPL dag\n");
} else {
PRINTF("failed to create a new RPL DAG\n");
}
rpl_dag_root_init(&ipaddr, &ipaddr);
rpl_dag_root_init_dag_immediately();
#endif /* UIP_CONF_ROUTER */
print_local_addresses();
server_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL);
@ -169,7 +160,11 @@ PROCESS_THREAD(udp_server_process, ev, data)
tcpip_handler();
} else if (ev == sensors_event && data == &button_sensor) {
PRINTF("Initiaing global repair\n");
#if UIP_CONF_IPV6_RPL_LITE
rpl_global_repair();
#else
rpl_repair_root(RPL_DEFAULT_INSTANCE);
#endif
}
}

View File

@ -42,9 +42,11 @@
*/
/*---------------------------------------------------------------------------*/
#include "contiki-conf.h"
#include "rpl/rpl-private.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#include "mqtt.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/ipv6/sicslowpan.h"

View File

@ -50,7 +50,7 @@
#include "net/ip/uip-debug.h"
#include "dev/watchdog.h"
#include "dev/leds.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
/*---------------------------------------------------------------------------*/
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len])

View File

@ -35,7 +35,7 @@
#include "contiki.h"
#include "contiki-lib.h"
#include "contiki-net.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "net/ip/uip.h"
#include <string.h>
@ -104,6 +104,7 @@ timeout_handler(void)
uip_ip6addr_t *globaladdr = NULL;
uint16_t dest_port = CETIC_6LBR_NODE_INFO_PORT;
int has_dest = 0;
rpl_instance_t *instance;
rpl_dag_t *dag;
uip_ds6_addr_t *addr_desc = uip_ds6_get_global(ADDR_PREFERRED);
@ -153,9 +154,9 @@ timeout_handler(void)
PRINTF("Client sending to: ");
PRINT6ADDR(&client_conn->ripaddr);
i = sprintf(buf, "%d | ", ++seq_id);
dag = rpl_get_any_dag();
if(dag && dag->instance->def_route) {
add_ipaddr(buf + i, &dag->instance->def_route->ipaddr);
instance = rpl_get_default_instance();
if(instance && instance->dag.preferred_parent) {
add_ipaddr(buf + i, rpl_parent_get_ipaddr(instance->dag.preferred_parent));
} else {
sprintf(buf + i, "(null)");
}

View File

@ -36,9 +36,11 @@
*/
/*---------------------------------------------------------------------------*/
#include "contiki-conf.h"
#include "rpl/rpl-private.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#include "mqtt.h"
#include "net/rpl/rpl.h"
#include "rpl.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-icmp6.h"
#include "sys/etimer.h"

View File

@ -57,8 +57,8 @@
* Set the TCP MSS
*/
#define UIP_CONF_BUFFER_SIZE 900
#define NBR_TABLE_CONF_MAX_NEIGHBORS 5
#define UIP_CONF_MAX_ROUTES 5
#define CONTIKI_NETWORK_SIZE 5
#define CONTIKI_NETWORK_DENSITY 5
#define UIP_CONF_TCP_MSS 128
/*---------------------------------------------------------------------------*/
#endif /* PROJECT_CONF_H_ */

View File

@ -40,8 +40,10 @@
#include "net/netstack.h"
#include "net/ipv6/uip-ds6-nbr.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/rpl/rpl.h"
#include "net/rpl/rpl-private.h"
#include "rpl.h"
#if UIP_CONF_IPV6_RPL_LITE == 0
#include "rpl-private.h"
#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */
#include "rest-engine.h"
#include "er-coap.h"
@ -283,7 +285,7 @@ keep_mac_on(void)
#if RPL_WITH_PROBING
/* Determine if we are about to send a RPL probe */
if(CLOCK_LT(etimer_expiration_time(
&rpl_get_default_instance()->probing_timer.etimer),
&rpl_get_default_instance()->dag.probing_timer.etimer),
(clock_time() + PERIODIC_INTERVAL))) {
rv = MAC_MUST_STAY_ON;
}

Some files were not shown because too many files have changed in this diff Show More