Added RPL-lite, a lightweight implementation of RPL. This is the new default.
This commit is contained in:
parent
ebd0196539
commit
a6643a9835
|
@ -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'
|
||||
|
|
|
@ -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)}}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* Output functions.
|
||||
* \author
|
||||
|
||||
* Simon Duquennoy <simon.duquennoy@ri.se>
|
||||
* Simon Duquennoy <simon.duquennoy@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef CSMA_OUTPUT_H_
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
/********** Includes **********/
|
||||
|
||||
#include "net/rpl/rpl.h"
|
||||
#include "rpl.h"
|
||||
#include "net/mac/tsch/tsch-queue.h"
|
||||
|
||||
/********** Functions *********/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
|
@ -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_ */
|
|
@ -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();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
|
@ -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 */
|
|
@ -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(¤t_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 *)¤t_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @}*/
|
|
@ -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_ */
|
|
@ -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 */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/** @}*/
|
|
@ -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_ */
|
|
@ -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
|
||||
};
|
||||
|
||||
/** @}*/
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @}*/
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
||||
};
|
||||
|
||||
/** @}*/
|
|
@ -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);
|
||||
}
|
||||
/** @} */
|
|
@ -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 */
|
|
@ -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();
|
||||
}
|
||||
|
||||
/** @}*/
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/** @}*/
|
|
@ -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 */
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,6 +2,8 @@ all: http-example
|
|||
CONTIKI=../..
|
||||
APPS += http-socket
|
||||
|
||||
CONTIKI_WITH_IPV6 = 1
|
||||
CONTIKI_WITH_RPL_LITE = 0
|
||||
include $(CONTIKI)/Makefile.include
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
all: ip64-router
|
||||
CONTIKI=../..
|
||||
|
||||
CONTIKI_WITH_IPV6 = 1
|
||||
CONTIKI_WITH_RPL_LITE = 0
|
||||
include $(CONTIKI)/Makefile.include
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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: ");
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,4 +8,5 @@ CONTIKI = ../../..
|
|||
MODULES += core/net/ipv6/multicast
|
||||
|
||||
CONTIKI_WITH_IPV6 = 1
|
||||
CONTIKI_WITH_RPL_LITE = 1
|
||||
include $(CONTIKI)/Makefile.include
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
|
@ -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
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue