Вы находитесь на странице: 1из 146

diff --git a/Makefile.include b/Makefile.

include
index 92e49e5..f50ca43 100644
--- a/Makefile.include
+++ b/Makefile.include
@@ -164,7 +164,7 @@ endef
rm -f *~ *core core *.srec \
*.lst *.map \
*.cprg *.bin *.data contiki*.a *.firmware core-labels.S *.ihex
*.ini \
*.ce *.co $(CLEAN)
+
*.ce *.co *.hex *.$(TARGET) $(CLEAN)
-rm -rf $(OBJECTDIR)
ifndef CUSTOM_RULE_C_TO_CE
@@ -225,4 +225,5 @@ endif
# abstract from the actual binary name. It needs to contain some
# command in order to be a rule, not just a prerequisite.
%: %.$(TARGET)
+
msp430-objcopy -O ihex $< $@.hex
@
diff --git a/README-P2P-RPL b/README-P2P-RPL
new file mode 100644
index 0000000..2062b4f
--- /dev/null
+++ b/README-P2P-RPL
@@ -0,0 +1,68 @@
+
RPL Point to Point (P2P) extension
+
Reactive Discovery of Point-to-Point Routes in Contiki
+
+
Author: Matthias Philipp <matthias-philipp@gmx.de>
+
Contributor: Emmanuel Baccelli <emmanuel.baccelli@inria.fr>
+
+
QUICK START GUIDE
+
=================
+
+
+Prerequisites:
+-------------+
+ * msp430-gcc: to compile the firmware
+ * recent java JDK: to compile/run the Cooja simulator
+
+The easiest way to get a suitable environment is Instant Contiki, a
virtual
+machine image that comes pre-installed with all necessary tools. It is
available
+at http://sourceforge.net/projects/contiki/files/Instant%20Contiki/
+Make sure to select the latest version.
+
+
+Example application:
+-------------------+
+This distribution contains an example application that demonstrates the

+operation of P2P-RPL. It can be launched as follows:


+
+Compile the firmware:
+ cd examples/ipv6/rpl-p2p/
+ make
+
+Compile and run the Cooja simulator:
+ cd tools/cooja/
+ ant run
+
+In Cooja click File > Open Simulation and select
+examples/ipv6/rpl-p2p/p2p-sim-medium.csc
+
+Click Start to run the simulation.
+
+Double-clicking a node selects a random target node and measures the
route
+along the global DAG. Afterwards a P2P route discovery is initiated. You
should
+see the formation of the DAG, the discovered route, and the expiration
of the
+DAG. Finally the P2P route is measured. Subsequent double-clicks on the
same
+node trigger the transmission of UDP data packets along the route.
+
+Use the speed slider to adjust the simulation speed.
+
+An explanation of what is going on during the simulation is given in a
video
+available at http://contiki-p2p-rpl.gforge.inria.fr/
+
+To save memory, only two temporary DAGs (i.e. route discoveries) may be
active
+simultaneously (can be adjusted by setting RPL_MAX_DAG_ENTRIES). If this
number
+is exceeded, a new discovery can only be started after a previous one is
expired.
+
+
+Source Code:
+-----------+
+The source code can be found in core/net/rpl/
+
+The main P2P mechanisms are implemented in rpl-p2p.c. Parameters can be
adjusted
+in rpl-p2p.h. Generation and parsing of control messages is done in rplicmp6.c
+and DIO processing takes place in rpl-dag.c.
+
+The p2p-rpl branch has been regularly merged with upstream to benefit
from
+updates in the Contiki core. The last merge was on Oct 4 2011.
diff --git a/README-PATCH b/README-PATCH

new file mode 100644


index 0000000..0bcb668
--- /dev/null
+++ b/README-PATCH
@@ -0,0 +1,77 @@
+
RPL Point to Point (P2P) extension
+
Reactive Discovery of Point-to-Point Routes in Contiki
+
+
Author: Matthias Philipp <matthias-philipp@gmx.de>
+
Contributor: Emmanuel Baccelli <emmanuel.baccelli@inria.fr>
+
+
PATCHING GUIDE
+
==============
+
+
+Prerequisites:
+-------------+
+ * msp430-gcc: to compile the firmware
+ * recent java JDK: to compile/run the Cooja simulator
+
+The easiest way to get a suitable environment is Instant Contiki, a
virtual
+machine image that comes pre-installed with all necessary tools. It is
available
+at http://sourceforge.net/projects/contiki/files/Instant%20Contiki/
+Make sure to select the latest version.
+
+The patch contains an implementation of the P2P extension for RPL. It
is based
+on commit a2073db715f5a1773e4416b3f78a7b6ded9dc075 (Tue Oct 4 10:29:40
2011
++0200) but should also apply to the official release of Contiki 2.5.
+
+
+Patching the Contiki distribution:
+---------------------------------+
+# clone the contiki git repository (already done in Instant Contiki)
+git clone git://contiki.git.sourceforge.net/gitroot/contiki/contiki
+cd contiki
+
+# create a branch for P2P-RPL
+git checkout -b p2p-rpl a2073db715
+# if you'd prefer to base the p2p-rpl branch on the 2.5 release use:
+# git checkout -b p2p-rpl 2.5-release
+
+# get information on what the patch changes
+git apply --stat p2p-rpl.patch
+
+# check whether there are any conflicts
+git apply --check p2p-rpl.patch
+
+# actually apply the patch

+git apply p2p-rpl.patch


+
+
+Run P2P-RPL:
+-----------+
+Please have a look at README-P2P-RPL
+
+
+Creating a Patch
+---------------+
+# Create base branch starting at the commit (of the master branch)
before the
+# last merge
+git checkout -b p2p-base a2073db715
+# This can be omitted if the p2p-rpl branch has just been merged with
the head
+# of the master branch. In this case simply use 'master' instead of
'p2p-base'
+# in the following commands.
+
+git checkout p2p-rpl
+# check which files have been changed/added
+git diff --name-status p2p-base..p2p-rpl
+
+# Create a single patch with all the changes squashed together:
+git diff p2p-base > p2p-rpl.patch
+# This loses the history of individual commits, which is quite handy for
a
+# release. To create a patch that keeps the history of all the
individual
+# commits use:
+# git format-patch p2p-base --stdout > p2p-rpl.patch
+
+# Manually check the patch and remove unwanted content (e.g. wsn430
platform)
+vi p2p-rpl.patch
diff --git a/core/lib/random.c b/core/lib/random.c
index 91db6c7..1590163 100644
--- a/core/lib/random.c
+++ b/core/lib/random.c
@@ -28,28 +28,59 @@
*
* This file is part of the Contiki operating system.
*
- * @(#)$Id: random.c,v 1.5 2010/12/13 16:52:02 dak664 Exp $
+ * @(#)$Id: random.c,v 1.2 2008/02/10 12:30:57 oliverschmidt Exp $
+ */
+
+/*
+ * Minimal standard random number generator.
+ *
+ * Simple crappy ANSI C compatible random number generator that is

+
+
+
+
+

* good enough for us!


*
* Park, S.K. and K.W. Miller, 1988;
* Random Number Generators: Good Ones are Hard to Find,
* Comm. of the ACM, V. 31. No. 10, pp 1192-1201
*/
#include "lib/random.h"
#include "sys/clock.h"

-#include <stdlib.h>
+static uint32_t rand_state = 1;
-/*--------------------------------------------------------------------------*/
void
random_init(unsigned short seed)
{
- srand(seed);
+ rand_state = seed;
}
-/*--------------------------------------------------------------------------*/
+
unsigned short
random_rand(void)
{
-/* In gcc int rand() uses RAND_MAX and long random() uses
RANDOM_MAX=0x7FFFFFFF */
-/* RAND_MAX varies depending on the architecture */
+ uint32_t hi, lo;
+
+ /*
+
* Perform two 16x16 bits multiplication with 32 bit results.
+
*/
+ lo = 16807ul * (uint16_t)(rand_state);
+ hi = 16807ul * (uint16_t)(rand_state >> 16);
+
+ lo += (hi & 0x7fff) << 16;
+
+ /*
+
* lo += hi >> 15; But faster using 16 bit registers.
+
*/
+ hi <<= 1;
+ lo += (uint16_t)(hi >> 16);
+
+ if ((int32_t)lo <= 0)
/* Deal with rand_state == 0. */
+
lo -= 0x7fffffff;
+
+ rand_state = lo;
+
+ if (sizeof(int) == sizeof(int16_t))
+
return (lo ^ (lo >> 16)) & RANDOM_RAND_MAX; /* Not ANSI C! */

+
+

else
return lo & RANDOM_RAND_MAX;

return (unsigned short)rand();


}
-/*--------------------------------------------------------------------------*/
diff --git a/core/lib/random.h b/core/lib/random.h
index d63cb55..6037f0c 100644
--- a/core/lib/random.h
+++ b/core/lib/random.h
@@ -28,7 +28,7 @@
*
* This file is part of the Contiki operating system.
*
- * @(#)$Id: random.h,v 1.2 2010/12/13 16:52:02 dak664 Exp $
+ * @(#)$Id: random.h,v 1.1 2006/06/17 22:41:18 adamdunkels Exp $
*/
#ifndef __RANDOM_H__
#define __RANDOM_H__
@@ -40,14 +40,12 @@
void random_init(unsigned short seed);
/*
- * Calculate a pseudo random number between
+ * Calculate a pseudo random number between
*
- * \return A pseudo-random number between 0
+ * \return A pseudo-random number between 0
*/
unsigned short random_rand(void);

0 and 65535.
0 and 32767.
and 65535.
and 32767.

-/* In gcc int rand() uses RAND_MAX and long random() uses RANDOM_MAX */
-/* Since random_rand casts to unsigned short, we'll use this maxmimum */
-#define RANDOM_RAND_MAX 65535U
+#define RANDOM_RAND_MAX 0x7fff
#endif /* __RANDOM_H__ */
diff --git a/core/net/mac/mac.c b/core/net/mac/mac.c
index b207744..a8146ce 100644
--- a/core/net/mac/mac.c
+++ b/core/net/mac/mac.c
@@ -50,6 +50,9 @@ mac_call_sent_callback(mac_callback_t sent, void *ptr,
int status, int num_tx)
switch(status) {
case MAC_TX_COLLISION:
PRINTF("mac: collision after %d tx\n", num_tx);
+#ifdef SENSLAB
+
printf("ERR collision\n");
+#endif /* SENSLAB */
break;
case MAC_TX_NOACK:
PRINTF("mac: noack after %d tx\n", num_tx);
diff --git a/core/net/neighbor-info.c b/core/net/neighbor-info.c

index c36a2b8..1029ef9 100644


--- a/core/net/neighbor-info.c
+++ b/core/net/neighbor-info.c
@@ -57,6 +57,9 @@ update_metric(const rimeaddr_t *dest, int
packet_metric)
{
link_metric_t *metricp;
link_metric_t recorded_metric, new_metric;
+#ifdef SENSLAB
+ struct neighbor_addr *attr;
+#endif /* SENSLAB */
metricp = (link_metric_t *)neighbor_attr_get_data(&etx, dest);
packet_metric = NEIGHBOR_INFO_ETX2FIX(packet_metric);
@@ -80,6 +83,14 @@ update_metric(const rimeaddr_t *dest, int
packet_metric)
neighbor_attr_set_data(&etx, dest, &new_metric);
if(new_metric != recorded_metric && subscriber_callback != NULL) {
subscriber_callback(dest, 1, new_metric);
+#ifdef SENSLAB
+
printf("LINK NBR: ");
+
for(attr = neighbor_attr_list_neighbors(); attr != NULL; attr =
list_item_next(attr)) {
+
metricp = (link_metric_t *)etx.data + attr->index * etx.size;
+
printf("%u-%d ", attr->addr.u8[sizeof(rimeaddr_t) - 1],
NEIGHBOR_INFO_FIX2ETX(*metricp));
+
}
+
putchar('\n');
+#endif /* SENSLAB */
}
}
}
@@ -134,20 +145,44 @@ neighbor_info_packet_sent(int status, int numtx)
update_metric(dest, packet_metric);
}
/*--------------------------------------------------------------------------*/
+static link_metric_t
+lqi_to_etx(uint8_t lqi)
+{
+ link_metric_t etx;
+
+ /* Cooja does not generate reasonable LQI values but always returns 37
(at
+
* least for UDGM constant loss with 100% RX and TX ratios) */
+ if(lqi == 37) {
+
return 1;
+ }
+
+ if(lqi >= 85) {
+
etx = 1;
+ } else if(lqi >= 70) {
+
etx = 1024 / (48 * lqi - 3140);

+ } else {
+
etx = 10;
+ }
+ return etx;
+}
+/*--------------------------------------------------------------------------*/
void
neighbor_info_packet_received(void)
{
const rimeaddr_t *src;
+ link_metric_t packet_metric;
src = packetbuf_addr(PACKETBUF_ADDR_SENDER);
if(rimeaddr_cmp(src, &rimeaddr_null)) {
return;
}
- PRINTF("neighbor-info: packet received from %d.%d\n",
src->u8[sizeof(*src) - 2], src->u8[sizeof(*src) - 1]);
+ PRINTF("neighbor-info: packet received from %d.%d lqi: %d\n",
+
src->u8[sizeof(*src) - 2], src->u8[sizeof(*src) - 1],
packetbuf_attr(PACKETBUF_ATTR_LINK_QUALITY));
add_neighbor(src);
+ packet_metric =
lqi_to_etx(packetbuf_attr(PACKETBUF_ATTR_LINK_QUALITY));
+ update_metric(src, packet_metric);
}
/*--------------------------------------------------------------------------*/
int
@@ -168,6 +203,6 @@ neighbor_info_get_metric(const rimeaddr_t *addr)
link_metric_t *metricp;
metricp = (link_metric_t *)neighbor_attr_get_data(&etx, addr);
return metricp == NULL ? ETX_LIMIT : *metricp;
return metricp == NULL ? NEIGHBOR_INFO_ETX2FIX(ETX_LIMIT) : *metricp;

+
}

/*--------------------------------------------------------------------------*/
diff --git a/core/net/rpl/Makefile.rpl b/core/net/rpl/Makefile.rpl
index 68f67f2..c1dfd92 100644
--- a/core/net/rpl/Makefile.rpl
+++ b/core/net/rpl/Makefile.rpl
@@ -1,2 +1,7 @@
+ifdef WITH_RPL_P2P
CONTIKI_SOURCEFILES += rpl.c rpl-dag.c rpl-icmp6.c rpl-timers.c \
rpl-of-etx.c
+
rpl-of-etx.c rpl-of0.c rpl-p2p.c
+else
+CONTIKI_SOURCEFILES += rpl.c rpl-dag.c rpl-icmp6.c rpl-timers.c \

+
rpl-of-etx.c rpl-of0.c
+endif
diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c
index c304be4..d037d60 100644
--- a/core/net/rpl/rpl-dag.c
+++ b/core/net/rpl/rpl-dag.c
@@ -38,9 +38,9 @@
*
Logic for Directed Acyclic Graphs in RPL.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes
<nvt@sics.se>
+ * Contributor: Matthias Philipp <matthias-philipp@gmx.de>
*/
#include "contiki.h"
#include "net/rpl/rpl-private.h"
#include "net/uip.h"
@@ -55,25 +55,16 @@
#define DEBUG DEBUG_NONE
#include "net/uip-debug.h"
+#if WITH_RPL_P2P
+#include "net/rpl/rpl-p2p.h"
+#endif /* WITH_RPL_P2P */
+
#include "net/neighbor-info.h"
/************************************************************************
/
extern rpl_of_t RPL_OF;
static rpl_of_t * const objective_functions[] = {&RPL_OF};
/************************************************************************
/
-#ifndef RPL_CONF_MAX_DAG_ENTRIES
-#define RPL_MAX_DAG_ENTRIES
2
-#else
-#define RPL_MAX_DAG_ENTRIES
RPL_CONF_MAX_DAG_ENTRIES
-#endif /* !RPL_CONF_MAX_DAG_ENTRIES */
-#ifndef RPL_CONF_MAX_PARENTS
-#define RPL_MAX_PARENTS
8
-#else
-#define RPL_MAX_PARENTS
RPL_CONF_MAX_PARENTS
-#endif /* !RPL_CONF_MAX_PARENTS */
-/***********************************************************************
*/
/* RPL definitions. */
#ifndef RPL_CONF_GROUNDED

@@ -94,15 +85,29 @@ static rpl_of_t * const objective_functions[] =


{&RPL_OF};
#define RPL_DIO_INTERVAL_DOUBLINGS
RPL_CONF_DIO_INTERVAL_DOUBLINGS
#endif /* !RPL_CONF_DIO_INTERVAL_DOUBLINGS */
+const rpl_dodag_config_t DEFAULT_DODAG_CONFIG = {
+ DEFAULT_DIO_INTERVAL_DOUBLINGS,
+ DEFAULT_DIO_INTERVAL_MIN,
+ DEFAULT_DIO_REDUNDANCY,
+ DEFAULT_MAX_RANKINC,
+ DEFAULT_MIN_HOPRANKINC,
+ 1,
+ RPL_DEFAULT_LIFETIME,
+ RPL_DEFAULT_LIFETIME_UNIT
+};
/************************************************************************
/
/* Allocate parents from the same static MEMB chunk to reduce memory
waste. */
MEMB(parent_memb, struct rpl_parent, RPL_MAX_PARENTS);
-static rpl_dag_t dag_table[RPL_MAX_DAG_ENTRIES];
+rpl_dag_t dag_table[RPL_MAX_DAG_ENTRIES];
+
+#if (DEBUG) & DEBUG_ANNOTATE
+extern rpl_dag_t *latest_p2p_dag;
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
/************************************************************************
/
/* Remove DAG parents with a rank that is at least the same as
minimum_rank. */
-static void
-remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
+void
+rpl_remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
{
rpl_parent_t *p, *p2;
@@ -139,6 +144,7 @@ remove_worst_parent(rpl_dag_t *dag, rpl_rank_t
min_worst_rank)
}
}
/************************************************************************
/
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
static int
should_send_dao(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p)
{
@@ -146,13 +152,30 @@ should_send_dao(rpl_dag_t *dag, rpl_dio_t *dio,
rpl_parent_t *p)

if(dag->mop == RPL_MOP_NO_DOWNWARD_ROUTES) return 0;


return dio->dtsn != p->dtsn && p == dag->preferred_parent;
}
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
/************************************************************************
/
static int
acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank)
{
return rank != INFINITE_RANK &&
(dag->max_rankinc == 0 ||
DAG_RANK(rank, dag) <= DAG_RANK(dag->min_rank + dag->max_rankinc,
dag));
+
(dag->config.max_rankinc == 0 ||
+
DAG_RANK(rank, dag) <= DAG_RANK(dag->min_rank + dag>config.max_rankinc, dag));
+}
+/***********************************************************************
*/
+uint8_t
+rpl_set_dodag_config(rpl_dag_t *dag, const rpl_dodag_config_t *dcf)
+{
+ rpl_of_t *of;
+ /* Determine objective function from the objective code point */
+ of = rpl_find_of(dcf->ocp);
+ if (of == NULL) {
+
PRINTF("RPL: Unable to determine OF for OCP %d\n", dcf->ocp);
+
return 0;
+ }
+ dag->of = of;
+ /* copy configuration struct */
+ memcpy(&dag->config, dcf, sizeof(rpl_dodag_config_t));
+ return 1;
}
/************************************************************************
/
rpl_dag_t *
@@ -162,7 +185,7 @@ rpl_set_root(uip_ipaddr_t *dag_id)
int version;
version = -1;
dag = rpl_get_dag(RPL_DEFAULT_INSTANCE);
dag = rpl_get_dag(RPL_DEFAULT_INSTANCE, NULL);
if(dag != NULL) {
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
version = dag->version;
@@ -179,20 +202,12 @@ rpl_set_root(uip_ipaddr_t *dag_id)
dag->version = version + 1;
dag->grounded = RPL_GROUNDED;
dag->mop = RPL_MOP_DEFAULT;
- dag->of = &RPL_OF;
+

dag->preferred_parent = NULL;
dag->dtsn_out = 1; /* Trigger DAOs from the beginning. */
+

rpl_set_dodag_config(dag, &DEFAULT_DODAG_CONFIG);
memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id));

dag->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS;
dag->dio_intmin = DEFAULT_DIO_INTERVAL_MIN;
dag->dio_redundancy = DEFAULT_DIO_REDUNDANCY;
dag->max_rankinc = DEFAULT_MAX_RANKINC;
dag->min_hoprankinc = DEFAULT_MIN_HOPRANKINC;
dag->default_lifetime = RPL_DEFAULT_LIFETIME;
dag->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
dag->rank = ROOT_RANK(dag);

@@ -202,8 +217,14 @@ rpl_set_root(uip_ipaddr_t *dag_id)


PRINT6ADDR(&dag->dag_id);
PRINTF("\n");
- ANNOTATE("#A root=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
+#if (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P
+ rpl_repaint_links();
+#endif /* (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P */
+#ifdef SENSLAB
+ printf("RPL DAG ");
+ print6addr(&dag->dag_id);
+ printf(" 0x%02x ROOT\n", dag->instance_id);
+#endif /* SENSLAB */
rpl_reset_dio_timer(dag, 1);
@@ -227,6 +248,13 @@ rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix,
int len)
int
rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from)
{
+#if WITH_RPL_P2P
+ /* Don't set any default routes in P2P mode */
+ if(dag->mop == RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
return 1;
+ }
+#endif /* WITH_RPL_P2P */
+
if(dag->def_route != NULL) {
PRINTF("RPL: Removing default route through ");
PRINT6ADDR(&dag->def_route->ipaddr);
@@ -240,7 +268,7 @@ rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t
*from)
PRINTF("\n");
dag->def_route = uip_ds6_defrt_add(from,
RPL_LIFETIME(dag,

dag>default_lifetime));
+
dag>config.default_lifetime));
if(dag->def_route == NULL) {
return 0;
}
@@ -264,6 +292,7 @@ rpl_alloc_dag(uint8_t instance_id)
dag->def_route = NULL;
dag->rank = INFINITE_RANK;
dag->min_rank = INFINITE_RANK;
+
dag->used = 1;
return dag;
}
}
@@ -279,15 +308,21 @@ rpl_free_dag(rpl_dag_t *dag)
PRINT6ADDR(&dag->dag_id);
PRINTF("\n");
- /* Remove routes installed by DAOs. */
- rpl_remove_routes(dag);
+ /* Do NOT remove routes installed by P2P DROs when the temporary P2P
DAG
+
* expires. */
+ if (dag->mop != RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
/* Remove routes installed by DAOs. */
+
rpl_remove_routes(dag);
+ }
+

/* Remove parents and the default route. */


remove_parents(dag, 0);
rpl_remove_parents(dag, 0);
rpl_set_default_route(dag, NULL);

ctimer_stop(&dag->dio_timer);
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
ctimer_stop(&dag->dao_timer);
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
dag->used = 0;
dag->joined = 0;
@@ -297,17 +332,34 @@ rpl_parent_t *
rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
{
rpl_parent_t *p;
+ uip_ds6_nbr_t *nbr;

p = memb_alloc(&parent_memb);
if(p == NULL) {
RPL_STAT(rpl_stats.mem_overflows++);
return NULL;
remove_worst_parent(dag, dio->rank);

+
p = memb_alloc(&parent_memb);
+
if(p == NULL) {
+
RPL_STAT(rpl_stats.mem_overflows++);
+#ifdef SENSLAB
+
puts("ERR MEM parent");
+#endif /* SENSLAB */
+
return NULL;
+
}
}
memcpy(&p->addr, addr, sizeof(p->addr));
p->dag = dag;
p->rank = dio->rank;
- p->link_metric = INITIAL_LINK_METRIC;
+ /* get the actual value of the link metric for this neighbor */
+ nbr = uip_ds6_nbr_lookup(addr);
+ if(nbr != NULL) {
+
p->link_metric = neighbor_info_get_metric((rimeaddr_t *)&nbr>lladdr);
+
PRINTF("ETX to parent candidate %u is %d\n", addr->u8[15],
NEIGHBOR_INFO_FIX2ETX(p->link_metric));
+ } else {
+
printf("ERR parent candidate %u not in neighbor cache!\n", addr>u8[15]);
+
p->link_metric = INITIAL_LINK_METRIC;
+ }
+
p->dtsn = 0;
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
@@ -330,7 +382,88 @@ rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr)
return NULL;
}
+/***********************************************************************
*/
+#if (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P
+void
+rpl_repaint_links(void)
+{
+ static uint8_t old_global_bp_id = 0;
+ static uint8_t old_local_bp_id = 0;
+ uint8_t global_bp_id = 0;
+ uint8_t local_bp_id = 0;
+ rpl_dag_t *dag;
+
+ /* set correct node color */
+ if(latest_p2p_dag != NULL && !latest_p2p_dag->p2p->expired) {
+
ANNOTATE("#A ping=\n");
+
ANNOTATE("#A join=%u\n", latest_p2p_dag->dag_id.u8[15]);
+
if(latest_p2p_dag->rank == ROOT_RANK(latest_p2p_dag)) {
+
ANNOTATE("#A color=red\n");
+
} else if(latest_p2p_dag->p2p->target.u8[sizeof(rpl_cmpr_addr_t) 2] == rpl_get_own_addr(1)->u8[15]) {

+
ANNOTATE("#A color=green\n");
+
} else {
+
ANNOTATE("#A color=orange\n");
+
ANNOTATE("#A p2p=\n");
+
}
+ } else {
+
ANNOTATE("#A join=\n");
+
if((dag = rpl_get_dag(RPL_DEFAULT_INSTANCE, NULL)) != NULL) {
+
if(dag->rank == ROOT_RANK(dag)) {
+
ANNOTATE("#A color=blue\n");
+
ANNOTATE("#A root=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) 1]);
+
} else {
+
ANNOTATE("#A color=orange\n");
+
}
+
} else {
+
ANNOTATE("#A color=white\n");
+
}
+ }
+
+ /* Determine currently best parents */
+ dag = rpl_get_dag(RPL_DEFAULT_INSTANCE, NULL);
+ if(dag != NULL && dag->preferred_parent != NULL) {
+
global_bp_id = dag->preferred_parent->addr.u8[sizeof(uip_ipaddr_t) 1];
+ }
+ /* Find the newest P2P DAG that is not yet expired */
+ if(latest_p2p_dag != NULL &&
+
latest_p2p_dag->joined &&
+
!latest_p2p_dag->p2p->expired &&
+
latest_p2p_dag->preferred_parent != NULL) {
+
local_bp_id = latest_p2p_dag->preferred_parent>addr.u8[sizeof(uip_ipaddr_t) - 1];
+ }
+ if(old_global_bp_id == global_bp_id && old_local_bp_id == local_bp_id)
{
+
/* Nothing changed, nothing needs to be repainted */
+
return;
+ }
+ /* Some old links may have to be removed */
+ if(old_global_bp_id != 0) {
+
ANNOTATE("#L %u 0\n", old_global_bp_id);
+ }
+ if(old_local_bp_id != 0) {
+
ANNOTATE("#L %u 0\n", old_local_bp_id);
+ }
+
+ /* Add new links to best parents. */
+ if (global_bp_id == local_bp_id) {
+
/* Cooja does not support two relations between the same nodes,
therefore we
+
* define one relation that looks like two. */
+
if(global_bp_id > 0) {

+
ANNOTATE("#L %u 1 dashed,red,overlay\n", global_bp_id);
+
}
+ } else {
+
if(global_bp_id > 0) {
+
ANNOTATE("#L %u 1\n", global_bp_id);
+
}
+
if(local_bp_id > 0) {
+
ANNOTATE("#L %u 1 dashed,red\n", local_bp_id);
+
}
+ }
+
+ old_global_bp_id = global_bp_id;
+ old_local_bp_id = local_bp_id;
+}
+#endif /* (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P */
/************************************************************************
/
rpl_parent_t *
rpl_select_parent(rpl_dag_t *dag)
@@ -356,16 +489,42 @@ rpl_select_parent(rpl_dag_t *dag)
if(dag->preferred_parent != best) {
PRINTF("RPL: Sending a No-Path DAO to old DAO parent\n");
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
dao_output(dag->preferred_parent, ZERO_LIFETIME);
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
dag->preferred_parent = best; /* Cache the value. */
dag->of->update_metric_container(dag);
rpl_set_default_route(dag, &best->addr);
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
/* The DAO parent set changed - schedule a DAO transmission. */
if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
rpl_schedule_dao(dag);
}
rpl_reset_dio_timer(dag, 1);
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
+
/* Do not reset trickle timer for P2P DAG. There the trickle
operation
+
* is only based on the route metrics and the DIO might thus still
be
+
* considered consistent even if the best parent changed. */
+#if WITH_RPL_P2P
+
if(dag->p2p == NULL) {
+#endif /* WITH_RPL_P2P */
+
rpl_reset_dio_timer(dag, 1);
+#if WITH_RPL_P2P
+
}
+#endif /* WITH_RPL_P2P */

+#if (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P


+
rpl_repaint_links();
+#endif /* (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P */
+#ifdef SENSLAB
+
if(dag->instance_id == RPL_DEFAULT_INSTANCE) {
+
printf("RPL ");
+
} else {
+
printf("P2P ");
+
}
+
printf("DAG ");
+
print6addr(&dag->dag_id);
+
printf(" 0x%02x BP %u\n", dag->instance_id, best->addr.u8[15]);
+#endif /* SENSLAB */
PRINTF("RPL: New preferred parent, rank changed from %u to %u\n",
(unsigned)dag->rank, dag->of->calculate_rank(best, 0));
RPL_STAT(rpl_stats.parent_switch++);
@@ -378,9 +537,11 @@ rpl_select_parent(rpl_dag_t *dag)
dag->min_rank = dag->rank;
} else if(!acceptable_rank(dag, best->rank)) {
/* Send a No-Path DAO to the soon-to-be-removed preferred parent. */
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
dao_output(best, ZERO_LIFETIME);
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
+

remove_parents(dag, 0);
rpl_remove_parents(dag, 0);
return NULL;
}

@@ -392,16 +553,23 @@ rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t


*parent)
{
uip_ds6_defrt_t *defrt;
- /* Remove uIPv6 routes that have this parent as the next hop. **/
- uip_ds6_route_rm_by_nexthop(&parent->addr);
- defrt = uip_ds6_defrt_lookup(&parent->addr);
- if(defrt != NULL) {
PRINTF("RPL: Removing default route ");
PRINT6ADDR(&parent->addr);
PRINTF("\n");
uip_ds6_defrt_rm(defrt);
dag->def_route = NULL;
+#if WITH_RPL_P2P
+ /* Don't remove any routes in P2P mode */
+ if (dag->p2p == NULL) {
+#endif /* WITH_RPL_P2P */
+
/* Remove uIPv6 routes that have this parent as the next hop. **/
+
uip_ds6_route_rm_by_nexthop(&parent->addr);
+
defrt = uip_ds6_defrt_lookup(&parent->addr);
+
if(defrt != NULL) {
+
PRINTF("RPL: Removing default route ");

+
PRINT6ADDR(&parent->addr);
+
PRINTF("\n");
+
uip_ds6_defrt_rm(defrt);
+
dag->def_route = NULL;
+
}
+#if WITH_RPL_P2P
}
+#endif /* WITH_RPL_P2P */
PRINTF("RPL: Removing parent ");
PRINT6ADDR(&parent->addr);
@@ -417,13 +585,27 @@ rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t
*parent)
}
/************************************************************************
/
rpl_dag_t *
-rpl_get_dag(int instance_id)
+rpl_get_dag(int instance_id, uip_ipaddr_t *dodag_id)
{
int i;
+ /* RPL_ANY_INSTANCE denotes any global (i.e. non-P2P) DAG, since we
support only
+
* one global DAG, this is the same as RPL_DEFAULT_INSTANCE */
+ if(instance_id == RPL_ANY_INSTANCE) {
+
instance_id = RPL_DEFAULT_INSTANCE;
+ }
+ /* A DODAG is identified by its RPLInstanceID, DODAGID, and version.
But since
+
* new version override old ones we never store more than one version
for the
+
* same DAG */
for(i = 0; i < RPL_MAX_DAG_ENTRIES; i++) {
if(dag_table[i].joined && (instance_id == RPL_ANY_INSTANCE ||
dag_table[i].instance_id == instance_id)) {
+
if (dag_table[i].joined && ((
+
dag_table[i].instance_id == instance_id &&
+
dodag_id == NULL
+
) || (
+
dag_table[i].instance_id == instance_id &&
+
uip_ipaddr_cmp(&dag_table[i].dag_id, dodag_id)
+
)
+
)
+
) {
return &dag_table[i];
}
}
@@ -451,11 +633,13 @@ join_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
{
rpl_dag_t *dag;
rpl_parent_t *p;
- rpl_of_t *of;

dag = rpl_alloc_dag(dio->instance_id);
if(dag == NULL) {
PRINTF("RPL: Failed to allocate a DAG object!\n");
+#ifdef SENSLAB
+
puts("ERR MEM dag");
+#endif /* SENSLAB */
return;
}
@@ -469,76 +653,121 @@ join_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
}
PRINTF("succeeded\n");
+
+
+
+

/* Determine the objective function by using the


objective code point of the DIO. */
of = rpl_find_of(dio->ocp);
if(of == NULL) {
if (dio->dodag_config == NULL) {
rpl_set_dodag_config(dag, &DEFAULT_DODAG_CONFIG);
}
else if (!rpl_set_dodag_config(dag, dio->dodag_config)) {
PRINTF("RPL: DIO for DAG instance %u does not specify a supported
OF\n",
dio->instance_id);
return;
}
- /* Autoconfigure an address if this node does not already have an
address
with this prefix. */
- if((dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
uip_ipaddr_t ipaddr;
/* assume that the prefix ends with zeros! */
memcpy(&ipaddr, &dio->prefix_info.prefix, 16);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
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);
+ if (dio->prefix_info != NULL) {
+
/* Autoconfigure an address if this node does not already have an
address
+
with this prefix. */
+
if (dio->prefix_info->flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
+
uip_ipaddr_t ipaddr;
+
if(uip_ds6_list_loop
+
((uip_ds6_element_t *) uip_ds6_if.addr_list, UIP_DS6_ADDR_NB,
+
sizeof(uip_ds6_addr_t), &dio->prefix_info->prefix, 64,
+
(uip_ds6_element_t **) & ipaddr) != FOUND) {
+
/* assume that the prefix ends with zeros! */
+
memcpy(&ipaddr, &dio->prefix_info->prefix, 16);
+
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);

+
+
+
+
+

PRINTF("RPL: adding global IP address ");


PRINT6ADDR(&ipaddr);
PRINTF("\n");
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
}
}
/* copy prefix information into the dag */
memcpy(&dag->prefix_info, dio->prefix_info, sizeof(rpl_prefix_t));

+
+
}
-

dag->joined = 1;
dag->used = 1;
dag->of = of;
dag->grounded = dio->grounded;
dag->mop = dio->mop;
dag->preference = dio->preference;
dag->instance_id = dio->instance_id;
dag->max_rankinc = dio->dag_max_rankinc;
dag->min_hoprankinc = dio->dag_min_hoprankinc;
dag->version = dio->version;
dag->preferred_parent = p;
dag->of->update_metric_container(dag);

dag->dio_intdoubl = dio->dag_intdoubl;
dag->dio_intmin = dio->dag_intmin;
dag->dio_redundancy = dio->dag_redund;
memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id));

/* copy prefix information into the dag */


memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));

dag->rank = dag->of->calculate_rank(p, dio->rank);


dag->min_rank = dag->rank; /* So far this is the lowest rank we know
of. */
+ rpl_reset_dio_timer(dag, 1);
+ rpl_set_default_route(dag, from);
+
+#if WITH_RPL_P2P
+ if (dio->mop == RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
/* Check maximum rank constraint */
+
if(dio->rdo->max_rank > 0 && DAG_RANK(dag->rank, dag) > dio->rdo>max_rank) {
+
printf("P2P: Maximum rank exceeded, not joining DAG %u (%u) >
%u\n", DAG_RANK(dag->rank, dag), dag->rank, dio->rdo->max_rank);
+
rpl_free_dag(dag);
+
return;
+
}
+
/* Allocate memory for the P2P extension */
+
dag->p2p = rpl_p2p_alloc_dag(dag);
+
if (dag->p2p == NULL) {

+
PRINTF("RPL: Failed to allocate P2P extension for DAG object!\n");
+#ifdef SENSLAB
+
puts("ERR MEM p2p");
+#endif /* SENSLAB */
+
rpl_free_dag(dag);
+
return;
+
}
+
/* Initialize additional attributes for the P2P extension */
+
rpl_p2p_update_dag(dag, dio);
+
/* Set lifetime in seconds */
+
dag->p2p->lifetime = rpl_p2p_lt2sec(dag->p2p->rdo_lifetime);
+
/* This has to be called after the DIO timer was reset, because it
stops the
+
* timer in case this node is the target. */
+
rpl_p2p_process_target(dag, dio);
+ } else {
+
dag->p2p = NULL;
+ }
+#endif /* WITH_RPL_P2P */
+
PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
dio->instance_id, dag->rank);
PRINT6ADDR(&dag->dag_id);
PRINTF("\n");
- ANNOTATE("#A join=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]);
- dag->default_lifetime = dio->default_lifetime;
- dag->lifetime_unit = dio->lifetime_unit;
+#ifdef SENSLAB
+ if(dag->instance_id == RPL_DEFAULT_INSTANCE) {
+
printf("RPL ");
+ } else {
+
printf("P2P ");
+ }
+ printf("DAG ");
+ print6addr(&dag->dag_id);
+ printf(" 0x%02x JOIN\n", dag->instance_id);
+ if(dag->instance_id == RPL_DEFAULT_INSTANCE) {
+
printf("RPL ");
+ } else {
+
printf("P2P ");
+ }
+ printf("DAG ");
+ print6addr(&dag->dag_id);
+ printf(" 0x%02x BP %u\n", dag->instance_id, p->addr.u8[15]);
+#endif /* SENSLAB */
- rpl_reset_dio_timer(dag, 1);
- rpl_set_default_route(dag, from);
+#if (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P
+ /* Visualize the change in Cooja */
+ rpl_repaint_links();

+#endif /* (DEBUG) & DEBUG_ANNOTATE && WITH_RPL_P2P */


+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
if(should_send_dao(dag, dio, p)) {
rpl_schedule_dao(dag);
} else {
PRINTF("RPL: The DIO does not meet the prerequisites for sending a
DAO\n");
}
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
}
/************************************************************************
/
static void
@@ -546,7 +775,7 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag,
rpl_dio_t *dio)
{
rpl_parent_t *p;
+

remove_parents(dag, 0);
rpl_remove_parents(dag, 0);
dag->version = dio->version;
dag->dtsn_out = 1;
dag->of->reset(dag);
@@ -558,9 +787,11 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag,
rpl_dio_t *dio)
dag->rank = dag->of->calculate_rank(NULL, dio->rank);
dag->min_rank = dag->rank;
rpl_reset_dio_timer(dag, 1);
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
if(should_send_dao(dag, dio, p)) {
rpl_schedule_dao(dag);
}
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
}
PRINTF("RPL: Participating in a global repair (version=%u, rank=
%hu)\n",
dag->version, dag->rank);
@@ -586,7 +817,7 @@ rpl_local_repair(rpl_dag_t *dag)
PRINTF("RPL: Starting a local DAG repair\n");
+

dag->rank = INFINITE_RANK;
remove_parents(dag, 0);
rpl_remove_parents(dag, 0);
rpl_reset_dio_timer(dag, 1);

RPL_STAT(rpl_stats.local_repairs++);
@@ -599,11 +830,17 @@ rpl_recalculate_ranks(void)
rpl_parent_t *p;

/*
* We recalculate ranks when we receive feedback from the system
rather
* than RPL protocol messages. This periodical recalculation is called
* from a timer in order to keep the stack depth reasonably low.
+
* We recalculate ranks when we receive feedback from the system (i.e.
ETX
+
* changes) rather than RPL protocol messages. This periodical
recalculation
+
* is called from a timer in order to keep the stack depth reasonably
low.
+
*
+
* Rank re-caclulation is only done for the global DAG, because the
local DAGs
+
* from the P2P extension are only updated from incoming DIOs as
opposed to
+
* system feedback. This is because feedback-triggered recalculation
would
+
* require storing the whole route discovery DIO information (in
particular
+
* the source route option) for every neighbor.
*/
- dag = rpl_get_dag(RPL_ANY_INSTANCE);
+ dag = rpl_get_dag(RPL_ANY_INSTANCE, NULL);
if(dag != NULL) {
for(p = list_head(dag->parents); p != NULL; p = p->next) {
if(p->updated) {
@@ -647,7 +884,16 @@ rpl_process_parent_event(rpl_dag_t *dag,
rpl_parent_t *p)
PRINT6ADDR(&dag->preferred_parent->addr);
PRINTF(" (rank %u)\n",
(unsigned)DAG_RANK(dag->preferred_parent->rank, dag));
rpl_reset_dio_timer(dag, 1);
+
/* Do not reset trickle timer for P2P DAG. There the trickle
operation
+
* is only based on the route metrics and the DIO might thus still
be
+
* considered consistent even if the rank changed. */
+#if WITH_RPL_P2P
+
if(dag->p2p == NULL) {
+#endif /* WITH_RPL_P2P */
+
rpl_reset_dio_timer(dag, 1);
+#if WITH_RPL_P2P
+
}
+#endif /* WITH_RPL_P2P */
}
if(parent_rank == INFINITE_RANK ||
@@ -665,13 +911,46 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
{
rpl_dag_t *dag;
rpl_parent_t *p;
-

+#if WITH_RPL_P2P
+ uip_ds6_nbr_t *nbr;
+ rpl_parent_t *p2;
+ int adv_route_improved = 0;
+#endif /* WITH_RPL_P2P */
+
+#if WITH_RPL_P2P
+ if(dio->mop != RPL_MOP_DEFAULT && dio->mop !=
RPL_MOP_P2P_ROUTE_DISCOVERY) {
+#else
if(dio->mop != RPL_MOP_DEFAULT) {
+#endif /* WITH_RPL_P2P */
PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio>mop);
return;
}
- dag = rpl_get_dag(dio->instance_id);
+#if WITH_RPL_P2P
+ if(dio->mop == RPL_MOP_P2P_ROUTE_DISCOVERY && dio->rdo == NULL) {
+
PRINTF("RPL: Ignoring a P2P Mode DIO without route discovery
option\n");
+
return;
+ }
+ /* Check whether we have bidirectional reachcability with the sender
of the DIO.
+
* Since the ETX value is based on the LQI of incoming packets we
cannot check
+
* for that. However, links with ETX <= 3 are ussually bidirectional.
*/
+ nbr = uip_ds6_nbr_lookup(from);
+ if(nbr == NULL || neighbor_info_get_metric((rimeaddr_t *)&nbr->lladdr)
> NEIGHBOR_INFO_ETX2FIX(3)) {
+
PRINTF("RPL: Discarding DIO because of unidirectional
reachability\n");
+
return;
+ }
+ /* XXX The draft recommends (SHOULD) the metric container to be
updated before
+
* the constraint is evaluated, which is not the case in this
implementation.
+
* The objective function framework in Contiki only allows to update
the
+
* metric container for the current best parent, and not an arbitrary
parent
+
* (as the DIO originator). */
+ if (dio->mop == RPL_MOP_P2P_ROUTE_DISCOVERY && !
rpl_p2p_meets_constraints(&dio->mc, dio->constr)) {
+
printf("P2P: Constraints not met, ignoring DIO\n");
+
return;
+ }
+#endif /* WITH_RPL_P2P */
+
+ dag = rpl_get_dag(dio->instance_id, &dio->dag_id);

if(dag == NULL) {
/* Join the first possible DAG of this RPL instance. */
if(dio->rank != INFINITE_RANK) {
@@ -720,6 +999,20 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
return;
}
+#if WITH_RPL_P2P
+ if (dag->mop == RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
if(dag->p2p->expired) {
+
PRINTF("RPL: Ignoring DIO for already expired P2P DAG\n");
+
return;
+
}
+
/* Check maximum rank constraint */
+
if(dio->rdo->max_rank > 0 && DAG_RANK(dio->rank, dag) > dio->rdo>max_rank) {
+
printf("P2P: Ignoring DIO whith too high rank %u (%u) > %u\n",
DAG_RANK(dio->rank, dag), dag->rank, dio->rdo->max_rank);
+
return;
+
}
+ }
+#endif /* WITH_RPL_P2P */
+
/*
* At this point, we know that this DIO pertains to a DAG that
* we are already part of. We consider the sender of the DIO to be
@@ -747,10 +1040,37 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t
*dio)
PRINT6ADDR(from);
PRINTF("\n");
} else if(DAG_RANK(p->rank, dag) == DAG_RANK(dio->rank, dag)) {
PRINTF("RPL: Received consistent DIO\n");
dag->dio_counter++;
+
/* Do not increase DIO counter for P2P DAG. There the trickle
operation
+
* is only based on the route metrics and the DIO might thus still
be
+
* considered inconsistent even if the rank did not change. */
+#if WITH_RPL_P2P
+
if(dag->p2p == NULL) {
+#endif /* WITH_RPL_P2P */
+
PRINTF("RPL: Received consistent DIO\n");
+
dag->dio_counter++;
+#if WITH_RPL_P2P
+
}
+#endif /* WITH_RPL_P2P */
}
+#if WITH_RPL_P2P
+ if (dio->mop == RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
/* Make sure that the neighbor set only contains the current
preferred parent
+
* and the originator of this DIO. Thereby we can be sure that, if
the preferred

+
* parent was changed in rpl_process_parent_event() it was changed
to the DIO
+
* originator. Otherwise rpl_process_parent_event() could select any
neighbor
+
* in the parent set and we would therefore need to store the
partial route
+
* for each element in the parent set. */
+
for(p2 = list_head(dag->parents); p2 != NULL; p2 =
list_item_next(p2)) {
+
if(p2 != p && p2 != dag->preferred_parent) {
+
rpl_remove_parent(dag, p2);
+
}
+
}
+
/* Check whether this DIO will lead to an improvement in the route
that we advertise */
+
adv_route_improved = (dag->of->p2p_route_cmp(dag, dio, p) > 0);
+ }
+#endif /* WITH_RPL_P2P */
+
/* We have allocated a candidate parent; process the DIO further. */
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
@@ -760,9 +1080,57 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
return;
}
+#if WITH_RPL_P2P
+ if (dio->mop == RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
/* Trickle operation is slightly different in P2P mode. The decision
whether
+
* this DIO is consistent or not only relies on the metric value.
*/
+
if(adv_route_improved) {
+
/* DIO lead to metric improvement and is thus considered
inconsistent. */
+
printf("P2P: Advertised route improved, rank: %d, bp: %u\n", dag>rank, dag->preferred_parent->addr.u8[15]);
+
rpl_p2p_update_dag(dag, dio);
+
rpl_reset_dio_timer(dag, 1);
+
} else if (dag->of->p2p_route_cmp(dag, dio, NULL) >= 0) {
+
/* DIO advertises better or same route than we do, but did not
lead to an
+
* improvement in the value that we advertise. It is thus
considered
+
* consistent. */
+
/* Sometimes we receive a second DIO before the DIO timer fired
even
+
* once, although it was reset to 0. (This probably only occurs
in
+
* simulations.) Therefore only increase the redundancy counter
if we
+
* sent at least one DIO after the last timer reset. */
+
PRINTF("originator: %u, preferred parent: %u\n", p->addr.u8[15],
dag->preferred_parent->addr.u8[15]);

+
//if(dag->dio_intcurrent > dag->config.dio_intmin) {
+
//if(1) {
+
if(p != dag->preferred_parent) {
+
dag->dio_counter++;
+
}
+
if (dag->of->p2p_route_cmp(dag, dio, p) >= 0) {
+
/* No change in the path metric but probably a different path.
+
* Add this partial route to the list in order to increase
diversity. */
+
if(rpl_p2p_route_differs(dag, dio)) {
+
printf("P2P: Alternative partial route ");
+
rpl_print_rdo(dio->rdo->start, &dio->dag_id);
+
/* Store alternative partial route */
+
if(rpl_p2p_add_partial_route(dag, dio)) {
+
printf(" cached\n");
+
} else {
+
printf(" NOT cached\n");
+
}
+
}
+
}
+
} else {
+
/* No improvement and DIO advertises worse metrics, thus no impact
on
+
* trickle. */
+
}
+
/* Stop the DIO timer and start the DRO timer if we are the target.
*/
+
rpl_p2p_process_target(dag, dio);
+ }
+#endif /* WITH_RPL_P2P */
+
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
if(should_send_dao(dag, dio, p)) {
rpl_schedule_dao(dag);
}
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
p->dtsn = dio->dtsn;
}
diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c
index 72393bf..6ebb68e 100644
--- a/core/net/rpl/rpl-icmp6.c
+++ b/core/net/rpl/rpl-icmp6.c
@@ -39,7 +39,8 @@
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes
<nvt@sics.se>
* Contributors: Niclas Finne <nfi@sics.se>, Joel Hoglund
<joel@sics.se>,
- *
Mathieu Pouillot <m.pouillot@watteco.com>
+ *
Mathieu Pouillot <m.pouillot@watteco.com>, Matthias
Philipp

+ *
*/

<matthias-philipp@gmx.de>

#include "net/tcpip.h"
@@ -54,13 +55,26 @@
#include <string.h>
#define DEBUG DEBUG_NONE
#include "net/uip-debug.h"
+#if WITH_RPL_P2P
+#include "net/rpl/rpl-p2p.h"
+#include "lib/memb.h"
+#include "lib/list.h"
+#include "sys/ctimer.h"
+#include "sys/process.h"
+#include "lib/random.h"
+#if WITH_RPL_P2P_MEASUREMENT
+#include "net/neighbor-info.h"
+#define NI_ETX_TO_RPL_ETX(etx)
\
+
((etx) * (RPL_DAG_MC_ETX_DIVISOR / NEIGHBOR_INFO_ETX_DIVISOR))
+#endif /* WITH_RPL_P2P_MEASUREMENT */
+#endif /* WITH_RPL_P2P */
+
/*--------------------------------------------------------------------------*/
#define RPL_DIO_GROUNDED
0x80
#define RPL_DIO_MOP_SHIFT
3
-#define RPL_DIO_MOP_MASK
0x3c
+#define RPL_DIO_MOP_MASK
0x38
#define RPL_DIO_PREFERENCE_MASK
0x07
#define UIP_IP_BUF
@@ -69,6 +83,8 @@

((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])

/*--------------------------------------------------------------------------*/
static void dis_input(void);
static void dio_input(void);
+static uint8_t rpl_send_uip_buf = 0;
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
static void dao_input(void);
static void dao_ack_input(void);
@@ -92,6 +108,21 @@ get_global_addr(uip_ipaddr_t *addr)
}
return 0;
}
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */

+/*--------------------------------------------------------------------------*/
+//#if (DEBUG) & DEBUG_PRINT
+void
+print_buffer(uint8_t *buf, uint8_t len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+
printf("0x%02x ", *buf);
+
buf++;
+
if ((i + 1) % 4 == 0) printf("\n");
+ }
+ printf("\n");
+}
+//#endif /* (DEBUG) & DEBUG_PRINT */
/*--------------------------------------------------------------------------*/
static uint32_t
get32(uint8_t *buffer, int pos)
@@ -132,7 +163,7 @@ dis_input(void)
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
+

dag = rpl_get_dag(RPL_ANY_INSTANCE);
dag = rpl_get_dag(RPL_ANY_INSTANCE, NULL);
if(dag != NULL) {
if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
PRINTF("RPL: Multicast DIS => reset DIO timer\n");
@@ -167,6 +198,9 @@ dis_output(uip_ipaddr_t *addr)
} else {
PRINTF("RPL: Sending a unicast DIS\n");
}
+#ifdef SENSLAB
+ printf("RPL DIS 2 Bytes\n");
+#endif /* SENSLAB */
uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIS, 2);
}
/*--------------------------------------------------------------------------*/
@@ -180,14 +214,15 @@ dio_input(void)
int i;
int len;
uip_ipaddr_t from;
- uip_ds6_nbr_t *nbr;
+ int j, mc_len;
+ rpl_prefix_t rif;
+ rpl_dodag_config_t dcf;
+ rpl_prefix_t pif;
+#if WITH_RPL_P2P
+ rpl_dio_rdo_t rdo;
+#endif /* SENSLAB */

+
memset(&dio, 0, sizeof(dio));
-

dio.dag_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS;
dio.dag_intmin = DEFAULT_DIO_INTERVAL_MIN;
dio.dag_redund = DEFAULT_DIO_REDUNDANCY;
uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);

/* DAG Information Object */


@@ -195,22 +230,6 @@ dio_input(void)
PRINT6ADDR(&from);
PRINTF("\n");
- 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)) != NULL) {
/* set reachable timer */
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
PRINTF("RPL: Neighbor added to neighbor cache ");
PRINT6ADDR(&from);
PRINTF(", ");
PRINTLLADDR((uip_lladdr_t
*)packetbuf_addr(PACKETBUF_ADDR_SENDER));
PRINTF("\n");
}
- } else {
PRINTF("RPL: Neighbor already in neighbor cache\n");
- }
buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
#if RPL_CONF_ADJUST_LLH_LEN
@@ -221,6 +240,8 @@ dio_input(void)
i = 0;
buffer = UIP_ICMP_PAYLOAD;
+
+

//print_buffer(buffer, buffer_length);

dio.instance_id = buffer[i++];
dio.version = buffer[i++];
dio.rank = get16(buffer, i);
@@ -239,6 +260,29 @@ dio_input(void)
memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
i += sizeof(dio.dag_id);
+#ifdef SENSLAB
+ /* XXX OK here it gets dirty! This should never occur in the first
place!
+
* It still has to be investigated where these DIOs come from. It
might be
+
* either defective nodes in the testbed, or rather due to stack
overflow on

+
* the processing node. If there are DIOs with invalid IDs it is very
likely
+
* that there are also DIOs with corrupted data in less obvoius
fields. */
+ if(dio.dag_id.u16[0] != 0xaaaa || dio.dag_id.u16[1] != 0 ||
dio.dag_id.u16[2] != 0 || dio.dag_id.u16[3] != 0 ||
+
dio.dag_id.u16[4] != 0 || dio.dag_id.u16[5] != 0 ||
dio.dag_id.u16[6] != 0 || dio.dag_id.u8[14] != 0) {
+
puts("ERR DIO bad id");
+
return;
+ }
+#endif /* SENSLAB */
+
+ dio.dodag_config = NULL;
+ dio.route_info = NULL;
+ dio.prefix_info = NULL;
+ dio.mc.type = RPL_DAG_MC_NONE;
+#if WITH_RPL_P2P
+ /* Additional options for P2P extension */
+ dio.rdo = NULL;
+ dio.constr = NULL;
+#endif /* WITH_RPL_P2P */
+
/* Check if there are any DIO suboptions. */
for(; i < buffer_length; i += len) {
subopt_type = buffer[i];
@@ -261,96 +305,151 @@ dio_input(void)
case RPL_OPTION_DAG_METRIC_CONTAINER:
if(len < 6) {
PRINTF("RPL: Invalid DAG MC, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
+
RPL_STAT(rpl_stats.malformed_msgs++);
return;
}
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_ETX) {
dio.mc.obj.etx = get16(buffer, i + 6);
PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length
%u, ETX %u\n",
(unsigned)dio.mc.type,
(unsigned)dio.mc.flags,
(unsigned)dio.mc.aggr,
(unsigned)dio.mc.prec,
(unsigned)dio.mc.length,
(unsigned)dio.mc.obj.etx);
} 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: Unhandled DAG MC type: %u\n",
(unsigned)dio.mc.type);
return;
+
/* One metric option may have multiple metric containers */
+
for(j = i + 2; j < i + len; j += mc_len) {
+
mc_len = 4 + buffer[j + 3];
+
if((buffer[j + 1] << 1) & RPL_DAG_MC_FLAG_C) {
+
/* Constraint object (only evaluated for P2P extension) */
+#if WITH_RPL_P2P
+
rpl_metric_container_t constr;
+
dio.constr = &constr;
+
constr.type = buffer[j];
+
constr.flags = buffer[j + 1] << 1;
+
constr.flags |= buffer[j + 2] >> 7;
+
constr.aggr = (buffer[j + 2] >> 4) & 0x3;
+
constr.prec = buffer[j + 2] & 0xf;
+
constr.length = buffer[j + 3];
+
+
if(constr.type == RPL_DAG_MC_ETX) {
+
constr.obj.etx = buffer[j + 4] << 8;
+
constr.obj.etx |= buffer[j + 5];
+
} else {
+
PRINTF("RPL: Unhandled DAG MC type: %u\n",
(unsigned)constr.type);
+
return;
+
}
+#endif /* WITH_RPL_P2P */
+
} else {
+
/* Metric object */
+
dio.mc.type = buffer[j];
+
dio.mc.flags = buffer[j + 1] << 1;
+
dio.mc.flags |= buffer[j + 2] >> 7;
+
dio.mc.aggr = (buffer[j + 2] >> 4) & 0x3;
+
dio.mc.prec = buffer[j + 2] & 0xf;
+
dio.mc.length = buffer[j + 3];
+
+
if(dio.mc.type == RPL_DAG_MC_ETX) {
+
dio.mc.obj.etx = get16(buffer, j + 4);
+
PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u,
length %u, ETX %u\n",
+
(unsigned)dio.mc.type,
+
(unsigned)dio.mc.flags,
+
(unsigned)dio.mc.aggr,
+
(unsigned)dio.mc.prec,
+
(unsigned)dio.mc.length,
+
(unsigned)dio.mc.obj.etx);
+
} else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
+
dio.mc.obj.energy.flags = buffer[j + 4];
+
dio.mc.obj.energy.energy_est = buffer[j + 5];
+
} else {

+
PRINTF("RPL: Unhandled DAG MC type: %u\n",
(unsigned)dio.mc.type);
+
return;
+
}
+
}
}
break;
case RPL_OPTION_ROUTE_INFO:
if(len < 9) {
PRINTF("RPL: Invalid destination prefix option, len = %d\n",
len);
RPL_STAT(rpl_stats.malformed_msgs++);
+
RPL_STAT(rpl_stats.malformed_msgs++);
return;
}
+
+
+
+
+
+
+
+

/* flags is both preference and flags for now */


dio.destination_prefix.length = buffer[i + 2];
dio.destination_prefix.flags = buffer[i + 3];
dio.destination_prefix.lifetime = get32(buffer, i + 4);
dio.route_info = &rif;
rif.length = buffer[i + 2];
rif.flags = buffer[i + 3];
rif.lifetime = get32(buffer, i + 4);
if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
dio.destination_prefix.length <= 128) {
if(((rif.length + 7) / 8) + 8 <= len && rif.length <= 128) {
PRINTF("RPL: Copying destination prefix\n");
memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
(dio.destination_prefix.length + 7) / 8);
memcpy(&rif.prefix, &buffer[i + 8], (rif.length + 7) / 8);
} else {
PRINTF("RPL: Invalid route infoprefix option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
return;
RPL_STAT(rpl_stats.malformed_msgs++);
return;
}
break;
case RPL_OPTION_DAG_CONF:
if(len != 16) {
PRINTF("RPL: Invalid DAG configuration option, len = %d\n",

len);
RPL_STAT(rpl_stats.malformed_msgs++);
+
RPL_STAT(rpl_stats.malformed_msgs++);
return;
}
+
dio.dodag_config = &dcf;
/* 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);
dcf.dio_intdoubl = buffer[i + 3];
dcf.dio_intmin = buffer[i + 4];
dcf.dio_redund = buffer[i + 5];
dcf.max_rankinc = get16(buffer, i + 6);
dcf.min_hoprankinc = get16(buffer, i + 8);
dcf.ocp = get16(buffer, i + 10);
/* buffer + 12 is reserved */
dio.default_lifetime = buffer[i + 13];
dio.lifetime_unit = get16(buffer, i + 14);
+
dcf.default_lifetime = buffer[i + 13];
+
dcf.lifetime_unit = get16(buffer, i + 14);
PRINTF("RPL: DIO Conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d
ocp=%d d_l=%u l_u=%u\n",
dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
dio.default_lifetime, dio.lifetime_unit);
+
dcf.dio_intdoubl, dcf.dio_intmin, dcf.dio_redund,
dcf.max_rankinc,
+
dcf.min_hoprankinc, dcf.ocp, dcf.default_lifetime,
+
dcf.lifetime_unit);
break;
case RPL_OPTION_PREFIX_INFO:
if(len != 32) {
PRINTF("RPL: DAG Prefix info not ok, len != 32\n");
RPL_STAT(rpl_stats.malformed_msgs++);
+
RPL_STAT(rpl_stats.malformed_msgs++);
return;
}
dio.prefix_info.length = buffer[i + 2];
dio.prefix_info.flags = buffer[i + 3];
+
dio.prefix_info = &pif;
+
pif.length = buffer[i + 2];
+
pif.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);
+
pif.lifetime = get32(buffer, i + 8);
/* 32-bit reserved at i + 12 */
PRINTF("RPL: Copying prefix information\n");
memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
+
memcpy(&pif.prefix, &buffer[i + 16], 16);
+
break;
+#if WITH_RPL_P2P
+
case RPL_DIO_SUBOPT_ROUTE_DISCOVERY:
+
if(len <= 4) {
+
PRINTF("RPL: Unrecognized route discovery option\n");
+
RPL_STAT(rpl_stats.malformed_msgs++);
+
return;
+
}
+
if(dio.rdo != NULL) {

+
PRINTF("RPL: Multiple route discovery options\n");
+
RPL_STAT(rpl_stats.malformed_msgs++);
+
return;
+
}
+
if(RPL_BITMASK_READ(P2P_RDO_C, buffer[i + 2]) <
RPL_P2P_RDO_COMPR_MIN) {
+
PRINTF("RPL: Unable to handle RDO, compression too low.\n");
+
return;
+
}
+
dio.rdo = &rdo;
+
rdo.start = &buffer[i];
+
rdo.both_directions = RPL_FLAG_GET(P2P_RDO_D, buffer[i + 2]);
+
rdo.hop_by_hop = RPL_FLAG_GET(P2P_RDO_H, buffer[i + 2]);
+
rdo.num_routes = RPL_BITMASK_READ(P2P_RDO_N, buffer[i + 2]);
+
rdo.compr = RPL_BITMASK_READ(P2P_RDO_C, buffer[i + 2]);
+
rdo.lifetime = RPL_BITMASK_READ(P2P_RDO_L, buffer[i + 3]);
+
rdo.max_rank = RPL_BITMASK_READ(P2P_RDO_R, buffer[i + 3]);
+
rdo.target = &buffer[i + 4];
+
rdo.addr_start = &buffer[i + 4 + 16 - rdo.compr];
+
/* Ignore empty address slots */
+
rdo.addr_len = len - 4 - 16 + rdo.compr;
break;
+#endif /* WITH_RPL_P2P */
default:
PRINTF("RPL: Unsupported suboption type in DIO: %u\n",
(unsigned)subopt_type);
@@ -360,13 +459,75 @@ dio_input(void)
rpl_process_dio(&from, &dio);
}
/*--------------------------------------------------------------------------*/
+static uint8_t
+write_rdo(unsigned char *buffer, rpl_dag_t *dag, list_t addr_list)
+{
+ uip_ds6_src_route_addr_t *a;
+ uint8_t pos = 0;
+
+ buffer[pos++] = RPL_DIO_SUBOPT_ROUTE_DISCOVERY;
+ buffer[pos] = 2 + (16 - dag->p2p->compr) * (1 +
list_length(addr_list));
+ /* We add our own address if we are neither the origin nor the target
*/
+ if(!uip_ds6_is_my_addr(&dag->dag_id) && !rpl_p2p_is_target(dag->p2p))
{
+
buffer[pos] += 16 - dag->p2p->compr;
+ }
+ buffer[++pos] = 0;
+ if(dag->p2p->both_directions) {
+
RPL_FLAG_SET(P2P_RDO_D, buffer[pos]);
+ }
+ if(dag->p2p->hop_by_hop) {
+
RPL_FLAG_SET(P2P_RDO_H, buffer[pos]);
+ }

+ RPL_BITMASK_WRITE(P2P_RDO_N, buffer[pos], dag->p2p->num_routes);


+ RPL_BITMASK_WRITE(P2P_RDO_C, buffer[pos], dag->p2p->compr);
+ pos++;
+ buffer[pos] = 0;
+ RPL_BITMASK_WRITE(P2P_RDO_L, buffer[pos], dag->p2p->rdo_lifetime);
+ RPL_BITMASK_WRITE(P2P_RDO_R, buffer[pos], dag->p2p->max_rank);
+ pos++;
+ /* Add the already compressed target */
+ memcpy(&buffer[pos], &dag->p2p->target, 16 - dag->p2p->compr);
+ pos += 16 - dag->p2p->compr;
+ /* Add the already compressed source route addresses */
+ for (a = list_head(addr_list); a != NULL; a = list_item_next(a)) {
+
memcpy(&buffer[pos], &a->addr, 16 - dag->p2p->compr);
+
pos += 16 - dag->p2p->compr;
+ }
+ /* Add our own compressed global address if we are neither the origin
nor the target. */
+ if(!uip_ds6_is_my_addr(&dag->dag_id) && !rpl_p2p_is_target(dag->p2p))
{
+
memcpy(&buffer[pos], ((uint8_t *)rpl_get_own_addr(1)) + dag->p2p>compr, 16 - dag->p2p->compr);
+
pos += 16 - dag->p2p->compr;
+ }
+ //print_buffer(buffer, pos);
+ return pos;
+}
+/*--------------------------------------------------------------------------*/
void
dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
{
unsigned char *buffer;
int pos;
uip_ipaddr_t addr;
+#if WITH_RPL_P2P
+ list_t partial_route;
+ void *empty_list = NULL;
+ uint8_t i, cnt;
+ unsigned short r = 0;
+#endif /* WITH_RPL_P2P */
+
+#if WITH_RPL_P2P
+ if (dag->mop == RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
if(dag->p2p->expired) {
+
PRINTF("P2P: Suppressing DIO for expired DAG\n");
+
return;
+
}
+
/* Do not send DIO if the rank cannot be increased anyway. */
+
if(dag->p2p->max_rank > 0 && DAG_RANK(dag->rank, dag) == dag->p2p>max_rank) {
+
printf("P2P: Reached maximum rank, suppressing DIO\n");
+
return;
+
}

+ }
+#endif /* WITH_RPL_P2P */
/* DAG Information Object */
pos = 0;
@@ -382,7 +543,16 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
}
buffer[pos++] = dag->mop << RPL_DIO_MOP_SHIFT;
- buffer[pos++] = ++dag->dtsn_out;
+ /* XXX Why do the Contiki guys increase the DTSN with every DIO? */
+#if WITH_RPL_P2P
+ if(dag->p2p == NULL) {
+#endif /* WITH_RPL_P2P */
+
buffer[pos++] = ++dag->dtsn_out;
+#if WITH_RPL_P2P
+ } else {
+
buffer[pos++] = dag->dtsn_out;
+ }
+#endif /* WITH_RPL_P2P */
/* reserved 2 bytes */
buffer[pos++] = 0; /* flags */
@@ -393,7 +563,6 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
if(dag->mc.type != RPL_DAG_MC_NONE) {
dag->of->update_metric_container(dag);
buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
buffer[pos++] = 6;
buffer[pos++] = dag->mc.type;
@@ -411,32 +580,89 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
buffer[pos++] = dag->mc.obj.energy.energy_est;
} else {
PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type
%u\n",
(unsigned)dag->mc.type);
+ (unsigned)dag->mc.type);
return;
}
}
+#if WITH_RPL_P2P
+ /* Add P2P constraint if present */
+ if(dag->mop == RPL_MOP_P2P_ROUTE_DISCOVERY && dag->p2p->constr.type !=
RPL_DAG_MC_NONE) {
+
/* Add the metric container option header if not already present */
+
if(dag->mc.type == RPL_DAG_MC_NONE) {
+
buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
+
buffer[pos++] = 6;
+
} else {
+
/* Option header already present, only update the length */
+
buffer[pos - 7] += 6;
+
}

+
buffer[pos++] = dag->p2p->constr.type;
+
buffer[pos++] = dag->p2p->constr.flags >> 1;
+
buffer[pos] = (dag->p2p->constr.flags & 1) << 7;
+
buffer[pos] = dag->p2p->constr.aggr << 4;
+
buffer[pos++] |= dag->p2p->constr.prec;
+
if(dag->p2p->constr.type == RPL_DAG_MC_ETX) {
+
buffer[pos++] = 2;
+
buffer[pos++] = dag->p2p->constr.obj.etx >> 8;
+
buffer[pos++] = dag->p2p->constr.obj.etx & 0xff;
+
} else {
+
PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type
%u\n",
+ (unsigned)dag->p2p->constr.type);
+
return;
+
}
+ }
+#endif /* WITH_RPL_P2P */
+
+ /* FIXME
+
* The information communicated in this option is generally static and
+
* unchanging within the DODAG, therefore it is not necessary to
include in
+
* every DIO.
+
*/
+#if 1
/* Always add a DAG configuration option. */
buffer[pos++] = RPL_OPTION_DAG_CONF;
buffer[pos++] = 14;
buffer[pos++] = 0; /* No Auth, PCS = 0 */
- buffer[pos++] = dag->dio_intdoubl;
- buffer[pos++] = dag->dio_intmin;
- buffer[pos++] = dag->dio_redundancy;
- set16(buffer, pos, dag->max_rankinc);
+ buffer[pos++] = dag->config.dio_intdoubl;
+ buffer[pos++] = dag->config.dio_intmin;
+ buffer[pos++] = dag->config.dio_redund;
+ set16(buffer, pos, dag->config.max_rankinc);
pos += 2;
- set16(buffer, pos, dag->min_hoprankinc);
+ set16(buffer, pos, dag->config.min_hoprankinc);
pos += 2;
/* OCP is in the DAG_CONF option */
set16(buffer, pos, dag->of->ocp);
pos += 2;
buffer[pos++] = 0; /* reserved */
- buffer[pos++] = dag->default_lifetime;
- set16(buffer, pos, dag->lifetime_unit);
+ buffer[pos++] = dag->config.default_lifetime;
+ set16(buffer, pos, dag->config.lifetime_unit);
pos += 2;
+#endif
-

/* Check if we have a prefix to send also. */


if(dag->prefix_info.length > 0) {

+#if WITH_RPL_P2P
+ if (dag->mop == RPL_MOP_P2P_ROUTE_DISCOVERY) {
+
/* chose a partial route to include in the DIO */
+
for(i = 0, cnt = 0; i < RPL_P2P_MAX_PARTIAL_ROUTES; i++) {
+
if(list_length(dag->p2p->partial_routes[i]) != 0) {
+
cnt++;
+
}
+
}
+
if(cnt > 1) {
+
r = random_rand() / (RANDOM_RAND_MAX / cnt);
+
printf("P2P: Including partial route %u of %u in DIO\n", r + 1,
cnt);
+
}
+
partial_route = dag->p2p->partial_routes[r];
+
if(list_length(partial_route) == 1 &&
+
memcmp(&((rpl_src_route_addr_t *)list_head(partial_route))->addr,
((uint8_t *)&dag->dag_id) + dag->p2p->compr, 16 - dag->p2p->compr) == 0)
{
+
/* treat as empty address list */
+
partial_route = &empty_list;
+
}
+
/* Add the route discovery option. */
+
pos += write_rdo(&buffer[pos], dag, partial_route);
+ }
+ else
+#endif /* WITH_RPL_P2P */
+ if (dag->prefix_info.length > 0) {
buffer[pos++] = RPL_OPTION_PREFIX_INFO;
buffer[pos++] = 30; /* always 30 bytes + 2 long */
buffer[pos++] = dag->prefix_info.length;
@@ -457,6 +683,18 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
dag->prefix_info.length);
}
+#ifdef SENSLAB
+ if(dag->instance_id == RPL_DEFAULT_INSTANCE) {
+
printf("RPL ");
+ } else {
+
printf("P2P ");
+ }
+ printf("DIO ");
+ print6addr(&dag->dag_id);
+ printf(" 0x%02x rank %u, %u Bytes\n", dag->instance_id, dag->rank,
pos);
+#endif /* SENSLAB */
+
+ //print_buffer(buffer, pos);
/* Unicast requests get unicast replies! */
if(uc_addr == NULL) {
PRINTF("RPL: Sending a multicast-DIO with rank %u\n",
@@ -472,6 +710,7 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
}
}

/*--------------------------------------------------------------------------*/
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
static void
dao_input(void)
{
@@ -513,14 +752,14 @@ dao_input(void)
pos = 0;
instance_id = buffer[pos++];
+

dag = rpl_get_dag(instance_id);
dag = rpl_get_dag(instance_id, NULL);
if(dag == NULL) {
PRINTF("RPL: Ignoring a DAO for a different RPL instance (%u)\n",
instance_id);
return;
}

lifetime = dag->default_lifetime;
lifetime = dag->config.default_lifetime;

flags = buffer[pos++];
/* reserved */
@@ -590,6 +829,9 @@ dao_input(void)
if(p != NULL && DAG_RANK(p->rank, dag) < DAG_RANK(dag->rank, dag)) {
PRINTF("RPL: Loop detected when receiving a unicast DAO from a
node with a lower rank! (%u < %u)\n",
DAG_RANK(p->rank, dag), DAG_RANK(dag->rank, dag));
+#ifdef SENSLAB
+
puts("ERR loop");
+#endif /* SENSLAB */
p->rank = INFINITE_RANK;
p->updated = 1;
return;
@@ -601,6 +843,9 @@ dao_input(void)
if(rep == NULL) {
RPL_STAT(rpl_stats.mem_overflows++);
PRINTF("RPL: Could not add a route after receiving a DAO\n");
+#ifdef SENSLAB
+
puts("ERR route add");
+#endif /* SENSLAB */
return;
}
}
@@ -638,7 +883,7 @@ dao_output(rpl_parent_t *n, rpl_lifetime_t lifetime)
}
+

if(n == NULL) {
dag = rpl_get_dag(RPL_ANY_INSTANCE);
dag = rpl_get_dag(RPL_ANY_INSTANCE, NULL);
if(dag == NULL) {
PRINTF("RPL: Did not join a DAG before sending DAO\n");

return;
@@ -684,6 +929,12 @@ dao_output(rpl_parent_t *n, rpl_lifetime_t lifetime)
uip_ipaddr_copy(&addr, &n->addr);
}
+#ifdef SENSLAB
+ printf("RPL DAO ");
+ print6addr(&dag->dag_id);
+ printf(" 0x%02x %u Bytes\n", dag->instance_id, pos);
+#endif /* SENSLAB */
+
PRINTF("RPL: Sending DAO with prefix ");
PRINT6ADDR(&prefix);
PRINTF(" to ");
@@ -740,10 +991,664 @@ dao_ack_output(rpl_dag_t *dag, uip_ipaddr_t *dest,
uint8_t sequence)
uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
}
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
+#if WITH_RPL_P2P
+#if WITH_RPL_P2P_MEASUREMENT
+/*--------------------------------------------------------------------------*/
+static uint8_t mo_sequence = 0;
+static struct process *mo_processes[RPL_P2P_MO_MAX_REQUESTS];
+/*--------------------------------------------------------------------------*/
+static void
+mo_input(void)
+{
+ unsigned char *buffer;
+ uint8_t buffer_length;
+ uint8_t pos;
+ uint8_t i;
+ static rpl_mo_result_t r;
+ uip_ipaddr_t origin;
+ uip_ipaddr_t *nexthop;
+ uip_ds6_route_t *hbhrt;
+ uip_ds6_src_route_t *srcrt;
+ uip_ds6_src_route_addr_t *a;
+ rpl_dag_t *dag;
+ uip_ds6_nbr_t *nbr;
+
+ buffer = UIP_ICMP_PAYLOAD;
+ buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
+
+ PRINTF("RPL: Received MO\n");
+ /*print_buffer(buffer, buffer_length);*/
+
+ /* Decompress origin and target */
+ memcpy(&origin, rpl_get_own_addr(1), RPL_P2P_RDO_COMPR);

+ memcpy(((uint8_t *)&origin) + RPL_P2P_RDO_COMPR, &buffer[4], 16 RPL_P2P_RDO_COMPR);


+ memcpy(&r.target, rpl_get_own_addr(1), RPL_P2P_RDO_COMPR);
+ memcpy(((uint8_t *)&r.target) + RPL_P2P_RDO_COMPR, &buffer[4 + 16 RPL_P2P_RDO_COMPR], 16 - RPL_P2P_RDO_COMPR);
+
+ /* Extract path metric */
+ pos = 4 + (RPL_BITMASK_READ(P2P_MO_N, buffer[3]) + 2) * (16 RPL_P2P_RDO_COMPR) + 6;
+ r.path_metric = buffer[pos] << 8;
+ r.path_metric |= buffer[pos + 1];
+
+ /* Compare origin address */
+ if(uip_ds6_is_my_addr(&origin)) {
+
/* We are the origin */
+
if(RPL_FLAG_GET(P2P_MO_T, buffer[1])) {
+
PRINTF("RPL: Received MO request but we are the origin!\n");
+
return;
+
}
+
PRINTF("ETX for route to ");
+
PRINT6ADDR(&r.target);
+
PRINTF(" is %u.%u\n", r.path_metric / RPL_DAG_MC_ETX_DIVISOR,
(r.path_metric %
+
RPL_DAG_MC_ETX_DIVISOR * 100) / RPL_DAG_MC_ETX_DIVISOR);
+
/* Notify the application layer that we received the MO reply. */
+
if(RPL_BITMASK_READ(P2P_MO_S, buffer[2]) < RPL_P2P_MO_MAX_REQUESTS
&& mo_processes[RPL_BITMASK_READ(P2P_MO_S, buffer[2])] != NULL) {
+
process_post_synch(mo_processes[RPL_BITMASK_READ(P2P_MO_S,
buffer[2])], rpl_p2p_event_mo, &r);
+
}
+
return;
+ }
+
+ /* Get the value of the link metric to the previous hop */
+ nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr);
+ if(nbr != NULL) {
+
/* Update path metric value */
+
r.path_metric +=
NI_ETX_TO_RPL_ETX(neighbor_info_get_metric((rimeaddr_t *)&nbr->lladdr));
+
buffer[pos] = r.path_metric >> 8;
+
buffer[pos + 1] = r.path_metric & 0xff;
+ } else {
+
PRINTF("RPL: unable to get link metric to %u discarding MO!\n",
UIP_IP_BUF->srcipaddr.u8[15]);
+
return;
+ }
+
+ /* Compare target address */
+ if(uip_ds6_is_my_addr(&r.target)) {
+
/* We are the target */
+
if(!RPL_FLAG_GET(P2P_MO_T, buffer[1])) {
+
PRINTF("RPL: Received MO reply but we are the target!\n");
+
return;
+
}

+
/* Generate MO reply */
+
RPL_FLAG_CLR(P2P_MO_T, buffer[1]);
+
if((buffer[0] & RPL_LOCAL_DEFAULT_INSTANCE && RPL_FLAG_GET(P2P_MO_A,
buffer[1])) ||
+
RPL_FLAG_GET(P2P_MO_R, buffer[1])) {
+
/* Address vector contains a source route that we can inverse and
use to
+
* send the MO reply. */
+
/* Create an entry in the source routing table */
+
rpl_p2p_add_src_route(&origin, &buffer[4 + 2 * (16 RPL_P2P_RDO_COMPR)],
+
(RPL_BITMASK_READ(P2P_MO_I, buffer[3]) - 1) * (16 RPL_P2P_RDO_COMPR),
+
RPL_P2P_RDO_COMPR, 1);
+
}
+
/* Remove address vector to decrease packet size */
+
memmove(&buffer[4 + 2 * (16 - RPL_P2P_RDO_COMPR)], &buffer[pos - 6],
8);
+
buffer[3] = 0;
+
/* calculate new length */
+
pos = 4 + 2 * (16 - RPL_P2P_RDO_COMPR) + 8;
+
+
PRINTF("RPL: Sending MO reply\n");
+
/*print_buffer(buffer, pos);*/
+
/* Send content of uip_buf when this function returns. */
+
rpl_send_uip_buf = 1;
+
/* The uip_buf contains the MO, we only have to change relevant
header fields. */
+
UIP_IP_BUF->len[0] = (UIP_ICMPH_LEN + pos) >> 8;
+
UIP_IP_BUF->len[1] = (UIP_ICMPH_LEN + pos) & 0xff;
+
memcpy(&UIP_IP_BUF->destipaddr, &origin, 16);
+
uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
+
UIP_ICMP_BUF->icode = RPL_CODE_MO;
+
UIP_ICMP_BUF->icmpchksum = 0;
+
UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
+
uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + pos;
+
return;
+ }
+
+ /* We are an intermediate node */
+ if(!RPL_FLAG_GET(P2P_MO_T, buffer[1])) {
+
PRINTF("RPL: Received MO reply but we are an intermediate node!\n");
+
return;
+ }
+ /* Determine next hop */
+ if(!RPL_FLAG_GET(P2P_MO_H, buffer[1])) {
+
/* MO travels along source route */
+
buffer[3]++; /* XXX unhandled overflow!!! */
+
if(RPL_BITMASK_READ(P2P_MO_I, buffer[3]) <=
RPL_BITMASK_READ(P2P_MO_N, buffer[3])) {
+
/* Decompress nexthop address (reuse target variable) */
+
memcpy(((uint8_t *)&r.target) + RPL_P2P_RDO_COMPR, &buffer[4 +
(RPL_BITMASK_READ(P2P_MO_I, buffer[3]) + 1)* (16 - RPL_P2P_RDO_COMPR)],
16 - RPL_P2P_RDO_COMPR);

+
}
+
nexthop = &r.target;
+ } else {
+
/* MO travels along Hop-by-hop route */
+
dag = rpl_get_dag(buffer[0], NULL);
+
/* Are we the root of a global non-storing DAG? */
+
if(!buffer[0] & RPL_LOCAL_DEFAULT_INSTANCE && dag != NULL &&
+
dag->mop == RPL_MOP_NON_STORING && dag->rank == ROOT_RANK(dag))
{
+
/* Look up source route to the target */
+
srcrt = uip_ds6_src_route_lookup(&r.target);
+
if(srcrt == NULL) {
+
PRINTF("RPL: Root of global non-storing DAG but no src route to
target!\n");
+
uip_icmp6_error_output(ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_NOROUTE, 0);
+
return;
+
}
+
/* Clear flags */
+
RPL_FLAG_CLR(P2P_MO_H, buffer[1]);
+
RPL_FLAG_CLR(P2P_MO_A, buffer[1]);
+
RPL_FLAG_CLR(P2P_MO_R, buffer[1]);
+
/* Index is 1 */
+
RPL_BITMASK_WRITE(P2P_MO_I, buffer[3], 1);
+
RPL_BITMASK_WRITE(P2P_MO_N, buffer[3], (list_length(srcrt>addr_list) - 1));
+
/* Move metric container to make space for address vector */
+
memmove(&buffer[4 + (RPL_BITMASK_READ(P2P_MO_N, buffer[3]) + 2) *
(16 - RPL_P2P_RDO_COMPR)], &buffer[pos - 6], 8);
+
pos = 4 + 2 * (16 - RPL_P2P_RDO_COMPR);
+
a = list_head(srcrt->addr_list);
+
nexthop = &a->addr;
+
/* Insert address vector with comressed source route but ommit
last
+
* address (link-local address of the target) */
+
for (; a != NULL && list_item_next(a) != NULL; a =
list_item_next(a)) {
+
memcpy(&buffer[pos], ((uint8_t *)&a->addr) + RPL_P2P_RDO_COMPR,
16 - RPL_P2P_RDO_COMPR);
+
pos += 16 - RPL_P2P_RDO_COMPR;
+
}
+
/* Correct the packet length */
+
pos += 8;
+
UIP_IP_BUF->len[0] = (UIP_ICMPH_LEN + pos) >> 8;
+
UIP_IP_BUF->len[1] = (UIP_ICMPH_LEN + pos) & 0xff;
+
uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + pos;
+
} else {
+
/* Look up hop-by-hop route to target
+
* XXX use dodagid and instance to lookup correct route */
+
if((hbhrt = uip_ds6_route_lookup(&r.target)) != NULL) {
+
nexthop = &hbhrt->nexthop;
+
} else if((nexthop = uip_ds6_defrt_choose()) == NULL) {
+
printf("RPL: Unable to determine nexthop for MO!\n");

+
uip_icmp6_error_output(ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_NOROUTE, 0);
+
return;
+
}
+
/* Do we need to add our address to the vector? */
+
if(buffer[0] & RPL_LOCAL_DEFAULT_INSTANCE &&
RPL_FLAG_GET(P2P_MO_A, buffer[1])) {
+
/* Check address vector for duplicate */
+
for(i = 2; i <= RPL_BITMASK_READ(P2P_MO_I, buffer[3]); i++) {
+
/* Decompress address (reuse target variable) */
+
memcpy(((uint8_t *)&r.target) + RPL_P2P_RDO_COMPR, &buffer[4 +
i * (16 - RPL_P2P_RDO_COMPR)], 16 - RPL_P2P_RDO_COMPR);
+
if(uip_ds6_is_my_addr(&r.target)) {
+
PRINTF("RPL: Loop in address vector, dropping MO!\n");
+
return;
+
}
+
}
+
/* add our compressed address */
+
memcpy(&buffer[4 + i * (16 - RPL_P2P_RDO_COMPR)], ((uint8_t
*)rpl_get_own_addr(1)) + RPL_P2P_RDO_COMPR, 16 - RPL_P2P_RDO_COMPR);
+
buffer[3]++;
+
}
+
}
+ }
+ /* XXX This is a hack! we need a link local address for the next hop,
+
* since neighbor discovery is not implemented or does not work. */
+ uip_create_linklocal_prefix(nexthop);
+ /* Unicast the message to the next hop */
+ PRINTF("RPL: Forwarding MO to ");
+ PRINT6ADDR(nexthop);
+ PRINTF("\n");
+ /*print_buffer(buffer, buffer_length);*/
+ /* Send content of uip_buf when this function returns. */
+ rpl_send_uip_buf = 1;
+ /* Packet header is unchanged except for IPv6 addresses and ICMP
checksum. */
+ memcpy(&UIP_IP_BUF->destipaddr, nexthop, 16);
+ uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
+ UIP_ICMP_BUF->icmpchksum = 0;
+ UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
+}
+/*--------------------------------------------------------------------------*/
+void
+mo_output(uip_ipaddr_t *target)
+{
+ unsigned char *buffer;
+ uint8_t pos;
+ uip_ds6_src_route_t *srcrt;
+ uip_ds6_src_route_addr_t *a;
+ uip_ds6_route_t *hbhrt;
+ uip_ipaddr_t *nexthop;
+ rpl_dag_t *dag;
+

+ /* Measurement Object */
+ if(target == NULL) {
+
PRINTF("RPL: Invalid target address, unable to send MO!\n");
+
return;
+ }
+
+ mo_sequence = (mo_sequence + 1) % RPL_P2P_MO_MAX_REQUESTS;
+ mo_processes[mo_sequence] = PROCESS_CURRENT();
+
+ buffer = UIP_ICMP_PAYLOAD;
+ /* Set fields that are independet of the type of route that we are
measuring */
+ pos = 1;
+ buffer[pos] = 0;
+ RPL_BITMASK_WRITE(P2P_MO_C, buffer[pos], RPL_P2P_RDO_COMPR);
+ RPL_FLAG_SET(P2P_MO_T, buffer[pos]);
+ buffer[++pos] = 0;
+ RPL_BITMASK_WRITE(P2P_MO_S, buffer[pos], mo_sequence);
+ buffer[++pos] = 0;
+ pos++;
+ /* Add compressed origin and target */
+ memcpy(&buffer[pos], ((uint8_t *)rpl_get_own_addr(1)) +
RPL_P2P_RDO_COMPR, 16 - RPL_P2P_RDO_COMPR);
+ pos += 16 - RPL_P2P_RDO_COMPR;
+ memcpy(&buffer[pos], ((uint8_t *)target) + RPL_P2P_RDO_COMPR, 16 RPL_P2P_RDO_COMPR);
+ pos += 16 - RPL_P2P_RDO_COMPR;
+
+ srcrt = uip_ds6_src_route_lookup(target);
+ if(srcrt != NULL) {
+
/* We have a full source route to the target. */
+
buffer[0] = RPL_LOCAL_DEFAULT_INSTANCE;
+
RPL_FLAG_SET(P2P_MO_R, buffer[1]);
+
/* Index is 1 */
+
RPL_BITMASK_WRITE(P2P_MO_I, buffer[3], 1);
+
RPL_BITMASK_WRITE(P2P_MO_N, buffer[3], (list_length(srcrt>addr_list) - 1));
+
a = list_head(srcrt->addr_list);
+
nexthop = &a->addr;
+
/* Add compressed addresses except last one (link-local address of
the
+
* target) */
+
for (; a != NULL && list_item_next(a) != NULL; a =
list_item_next(a)) {
+
memcpy(&buffer[pos], ((uint8_t *)&a->addr) + RPL_P2P_RDO_COMPR, 16
- RPL_P2P_RDO_COMPR);
+
pos += 16 - RPL_P2P_RDO_COMPR;
+
}
+ } else {
+
/* No source route, see if we have a hbh route */
+
hbhrt = uip_ds6_route_lookup(target);
+
if(hbhrt != NULL) {
+
buffer[0] = hbhrt->state.instance;
+
RPL_FLAG_SET(P2P_MO_H, buffer[1]);

+
nexthop = &hbhrt->nexthop;
+
/* If the instance ID is local, than the DADAGID must be our
global
+
* address, otherwise we cannot measure this route. */
+
if(hbhrt->state.instance & RPL_LOCAL_DEFAULT_INSTANCE) {
+
if(!uip_ds6_is_my_addr(&hbhrt->state.dodagid)) {
+
PRINTF("RPL: Local hop-by-hop route does not belong to me,
unable to send MO!\n");
+
return;
+
}
+
/* We measure a hop-by-hop route with local instance ID. */
+
RPL_FLAG_SET(P2P_MO_A, buffer[1]);
+
/* Index is 1 */
+
RPL_BITMASK_WRITE(P2P_MO_I, buffer[3], 1);
+
RPL_BITMASK_WRITE(P2P_MO_N, buffer[3],
RPL_P2P_MO_DEFAULT_VECTOR_SIZE);
+
/* Add an empty address vector */
+
memset(&buffer[4 + 2 * (16 - RPL_P2P_RDO_COMPR)], 0,
RPL_P2P_MO_DEFAULT_VECTOR_SIZE * (16 - RPL_P2P_RDO_COMPR));
+
pos += RPL_P2P_MO_DEFAULT_VECTOR_SIZE * (16 RPL_P2P_RDO_COMPR);
+
} else {
+
/* We measure a hop-by-hop route with global instance ID. */
+
/* Do not record the route and do not add an address vector */
+
}
+
/* Try to use default route along global DODAG */
+
} else if((nexthop = uip_ds6_defrt_choose()) != NULL &&
+
(dag = rpl_get_dag(RPL_DEFAULT_INSTANCE, NULL)) != NULL) {
+
buffer[0] = dag->instance_id;
+
RPL_FLAG_SET(P2P_MO_H, buffer[1]);
+
} else {
+
/* No route at all */
+
PRINTF("RPL: No route to target, unable to send MO!\n");
+
return;
+
}
+ }
+
+ /* Add metric container */
+ buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
+ buffer[pos++] = 6;
+ buffer[pos++] = RPL_DAG_MC_ETX;
+ /* no flags */
+ buffer[pos++] = 0;
+ buffer[pos++] = 0 | (RPL_DAG_MC_AGGR_ADDITIVE << 4);
+ buffer[pos++] = 2;
+ /* ETX value of a link may differ depeneding on the direction in which
it is
+
* measured (especially since we currently approximate it from LQI).
Therefore
+
* we measure it in backwards direction as in the P2P route discovery.
*/
+ buffer[pos++] = 0;
+ buffer[pos++] = 0;
+

+ /* Unicast the message to the next hop */


+ PRINTF("RPL: Sending MO\n");
+ /*print_buffer(buffer, pos);*/
+ uip_icmp6_send(nexthop, ICMP6_RPL, RPL_CODE_MO, pos);
+}
+#endif /* WITH_RPL_P2P_MEASUREMENT */
+/*--------------------------------------------------------------------------*/
+MEMB(dro_cache_memb, rpl_dro_cache_entry_t, RPL_MAX_DRO_CACHE_ENTRIES);
+LIST(dro_cache);
+/*--------------------------------------------------------------------------*/
+static void
+dro_rexmit(void *ptr)
+{
+ uip_ipaddr_t addr;
+ rpl_dro_cache_entry_t *c;
+ c = (rpl_dro_cache_entry_t *)ptr;
+
+ memcpy(UIP_ICMP_PAYLOAD, &c->buffer, c->length);
+ c->rexmits++;
+ if(c->rexmits < RPL_MAX_DRO_REXMITS) {
+
ctimer_reset(&c->timer);
+ } else {
+
list_remove(dro_cache, c);
+
memb_free(&dro_cache_memb, c);
+ }
+
+ PRINTF("RPL: Retransmiting DRO at %p, length: %d, rexmits: %d\n", &c>buffer, c->length, c->rexmits);
+ uip_create_linklocal_rplnodes_mcast(&addr);
+ uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DRO, c->length);
+}
+/*--------------------------------------------------------------------------*/
+static void
+dro_ack_input(void)
+{
+ unsigned char *buffer;
+ rpl_dro_cache_entry_t *c;
+
+ uint8_t removed = 0;
+
+ buffer = UIP_ICMP_PAYLOAD;
+ printf("P2P: Received DRO-ACK from %d\n", UIP_IP_BUF>srcipaddr.u8[15]);
+ /* print_buffer(buffer, uip_len - uip_l2_l3_icmp_hdr_len); */
+
+ /* Check whether we have any pending retransmissions for this DRO */
+ for(c = list_head(dro_cache); c != NULL; c = list_item_next(c)) {
+
/* DRO matches if it has the same DODAGID, instance and DRO sequence
number */
+
if(buffer[0] == c->buffer[0] &&\
+
uip_ipaddr_cmp(&buffer[4], &c->buffer[4]) &&\

+
RPL_BITMASK_READ(P2P_DRO_Q, buffer[2]) ==
RPL_BITMASK_READ(P2P_DRO_Q, buffer[2])) {
+
/* DRO has arrived, cancel retransmission timer and free memory.
*/
+
PRINTF("RPL: Canceling rexmit for DRO at %p length %d\n", &c>buffer, c->length);
+
ctimer_stop(&c->timer);
+
list_remove(dro_cache, c);
+
memb_free(&dro_cache_memb, c);
+
removed = 1;
+
break;
+
}
+ }
+ if(!removed) {
+
PRINTF("Did not find entry for ");
+
PRINT6ADDR((uip_ipaddr_t *)&buffer[4]);
+
PRINTF(" 0x%02x (%d packets cached)\n", buffer[0],
list_length(dro_cache));
+ }
+}
+/*--------------------------------------------------------------------------*/
+static void
+dro_input(void)
+{
+ rpl_dag_t *dag;
+ unsigned char *buffer;
+ uint8_t buffer_length;
+ uint8_t instance_id;
+ uint8_t version;
+ uint8_t compr;
+ uint8_t rem;
+ uip_ipaddr_t *dodag_id;
+ uip_ipaddr_t target;
+ uip_ipaddr_t nexthop;
+ uip_ds6_route_t *hbhrt;
+ int pos;
+
+ buffer = UIP_ICMP_PAYLOAD;
+ buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
+
+ /* Discovery Reply Object */
+ PRINTF("RPL: Received DRO from %d\n", UIP_IP_BUF->srcipaddr.u8[15]);
+ //print_buffer(buffer, buffer_length);
+
+ pos = 0;
+ instance_id = buffer[pos++];
+ version = buffer[pos++];
+ /* Skip flags and reserved */
+ pos += 2;
+ dodag_id = (uip_ipaddr_t *)&buffer[pos];
+ pos += 16;
+ while(buffer[pos] != RPL_DIO_SUBOPT_ROUTE_DISCOVERY && pos <
buffer_length) {

+
if(pos >= buffer_length) {
+
PRINTF("RPL: Received DRO without RDO.\n");
+
return;
+
}
+
pos += buffer[pos + 1] + 2;
+ }
+ compr = RPL_BITMASK_READ(P2P_RDO_C, buffer[pos + 2]);
+ rem = RPL_BITMASK_READ(P2P_RDO_R, buffer[pos + 3]);
+
+ /* Evaluate STOP bit */
+ if(RPL_FLAG_GET(P2P_DRO_S, buffer[2])) {
+
dag = rpl_get_dag(instance_id, dodag_id);
+
if(dag != NULL && !dag->p2p->expired) {
+
printf("RPL: Received DRO with STOP bit while DAG still active,
detaching.\n");
+
ctimer_stop(&dag->dio_timer);
+
dag->p2p->lifetime = 0;
+
}
+ }
+
+ /* Are we the origin of the corresponding route request? */
+ if(uip_ds6_is_my_addr(dodag_id)) {
+
PRINTF("RPL: DRO reached origin\n");
+#if (DEBUG) & DEBUG_ANNOTATE
+
rpl_annotate_rdo(&buffer[pos], dodag_id);
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
+#ifdef SENSLAB
+
printf("P2P DAG ");
+
print6addr(dodag_id);
+
printf(" 0x%02x REPLY ", buffer[0]);
+
rpl_print_rdo(&buffer[pos], dodag_id);
+
putchar('\n');
+#endif /* SENSLAB */
+
/* Decompress the target */
+
memcpy(&target, dodag_id, compr);
+
memcpy(((uint8_t *)&target) + compr, &buffer[pos + 4], 16 - compr);
+
if(RPL_FLAG_GET(P2P_RDO_H, buffer[pos + 2])) {
+
if(pos + 4 + 16 - compr == buffer_length) {
+
/* If the address vector is empty, target = nexthop */
+
memcpy(&nexthop, &target, 16);
+
} else {
+
/* Decompress first address in address vector */
+
memcpy(&nexthop, dodag_id, compr);
+
memcpy(((uint8_t *)&nexthop) + compr, &buffer[pos + 4 + 16 compr], 16 - compr);
+
}
+
/* XXX This is a hack! we need a link local address for the next
hop,
+
* since neighbor discovery is not implemented or does not work.
*/
+
uip_create_linklocal_prefix(&nexthop);
+
/* Store state for hop by hop route */
+
rpl_p2p_add_hbh_route(instance_id, dodag_id, &target, &nexthop);
+
} else {

+
/* Store the source route contained in the RDO */
+
rpl_p2p_add_src_route(&target, &buffer[pos + 4 + 16 - compr],
buffer[pos + 1] - 2 - 16 + compr, compr, 0);
+
}
+
/* Send DRO-ACK if requested */
+
if(RPL_FLAG_GET(P2P_DRO_A, buffer[2])) {
+
/* Packet follows the same format as DRO, everything after Seq is
reserved. */
+
buffer[2] &= RPL_P2P_DRO_Q_MASK;
+
buffer[3] = 0;
+
/* Send content of uip_buf when this function returns. */
+
rpl_send_uip_buf = 1;
+
/* The uip_buf contains a DRO, we only have to change relevant
header fields. */
+
UIP_IP_BUF->len[0] = (UIP_ICMPH_LEN + 20) >> 8;
+
UIP_IP_BUF->len[1] = (UIP_ICMPH_LEN + 20) & 0xff;
+
/* Decompress the target */
+
memcpy(&UIP_IP_BUF->destipaddr, dodag_id, compr);
+
memcpy(((uint8_t *)&UIP_IP_BUF->destipaddr) + compr, &buffer[pos +
4], 16 - compr);
+
uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF>destipaddr);
+
UIP_ICMP_BUF->icode = RPL_CODE_DRO_ACK;
+
UIP_ICMP_BUF->icmpchksum = 0;
+
UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
+
uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + 20;
+#ifdef SENSLAB
+
printf("P2P DRO-ACK ");
+
print6addr(dodag_id);
+
printf(" 0x%02x 20 Bytes\n", buffer[0]);
+#endif /* SENSLAB */
+
/* print_buffer(buffer, 20); */
+
}
+
/* Notify the application layer that we received the route reply. */
+
if((dag = rpl_get_dag(instance_id, dodag_id)) != NULL && dag->p2p>process != NULL) {
+
PRINTF("RPL: Notifying process %s at %p\n",
PROCESS_NAME_STRING(dag->p2p->process), dag->p2p->process);
+
process_post_synch(dag->p2p->process, rpl_p2p_event_dro, NULL);
+
} else {
+
/* Normally the DRO should arrive before the DODAG expires. And
even if it
+
* is expired, the data structure is still kept around for some
time. If
+
* this turns out to be not sufficient, we need to implement an
additional
+
* static data structure that stores pointers to the processes
that
+
* initiated a route request. */
+
PRINTF("RPL: Unable to notify application about DRO
reception!\n");
+
}
+
return;
+ }

+
+ /* We are an intermediate node */
+ /* Decompress address at position REM */
+ memcpy(&nexthop, dodag_id, compr);
+ memcpy(((uint8_t *)&nexthop) + compr, &buffer[pos + 4 + rem * (16 compr)], 16 - compr);
+ /* Stop processing and do not forward if we do not take part in the
route. It's
+
* important to check for Rem > 0 because address[0] points to the
target
+
* address and the target would thus forward the DRO again in that
case. */
+ if(rem <= 0 || !uip_ds6_is_my_addr(&nexthop)) {
+
PRINTF("RPL: Not forwarding DRO\n");
+
return;
+ }
+
+ /* We take part in the route, store hop by hop route if requested */
+ if(RPL_FLAG_GET(P2P_RDO_H, buffer[pos + 2])) {
+
/* Decompress the target */
+
memcpy(&target, dodag_id, compr);
+
memcpy(((uint8_t *)&target) + compr, &buffer[pos + 4], 16 - compr);
+
if(pos + 4 + (rem + 1) * (16 - compr) >= buffer_length) {
+
/* Rem points to last address, target is nexthop */
+
memcpy(&nexthop, &target, 16);
+
} else {
+
/* Decompress address at Rem + 1 in address vector */
+
memcpy(&nexthop, dodag_id, compr);
+
memcpy(((uint8_t *)&nexthop) + compr, &buffer[pos + 4 + (rem + 1)
* (16 - compr)], 16 - compr);
+
}
+
/* XXX This is a hack! we need a link local address for the next
hop,
+
* since neighbor discovery is not implemented or does not work. */
+
uip_create_linklocal_prefix(&nexthop);
+
/* Do we already have a route with same RPLInstanceID and DODAGID
to this target? */
+
if((hbhrt = uip_ds6_route_lookup(&target)) != NULL) {
+
/* XXX actually compare RPLInstanceID and DODAGID */
+
if(uip_ipaddr_cmp(&hbhrt->nexthop, &nexthop)) {
+
PRINTF("RPL: Received DRO with conflicting next hop\n");
+
return;
+
}
+
} else {
+
/* Store state for hop by hop route */
+
rpl_p2p_add_hbh_route(instance_id, dodag_id, &target, &nexthop);
+
}
+ }
+ /* Rem field is at the very end of the field, thus we can simply
substract */
+ buffer[pos + 3] -= 1;
+
+ PRINTF("RPL: Forwarding DRO\n");
+ /*print_buffer(buffer, pos + 2 + buffer[pos + 1]);*/

+
+#ifdef SENSLAB
+ printf("P2P DRO ");
+ print6addr(dodag_id);
+ printf(" 0x%02x %u Bytes\n", buffer[0], pos + 2 + buffer[pos + 1]);
+#endif /* SENSLAB */
+
+ /* Send content of uip_buf when this function returns. */
+ rpl_send_uip_buf = 1;
+ /* Packet header is unchanged except for IPv6 source address and ICMP
checksum. */
+ uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
+ UIP_ICMP_BUF->icmpchksum = 0;
+ UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
+}
+/*--------------------------------------------------------------------------*/
+void
+dro_output(rpl_dag_t *dag, list_t addr_list)
+{
+ unsigned char *buffer;
+ uint8_t pos, rem;
+ uip_ipaddr_t addr;
+
+ /* Destination Reply Object */
+ if(dag == NULL || dag->p2p == NULL) {
+
PRINTF("RPL: Invalid DAG object, unable to send DRO!\n");
+
return;
+ }
+
+ buffer = UIP_ICMP_PAYLOAD;
+ pos = 0;
+
+ buffer[pos++] = dag->instance_id;
+ buffer[pos++] = dag->version;
+ buffer[pos] = 0;
+ /* Sequence number */
+ RPL_BITMASK_WRITE(P2P_DRO_Q, buffer[pos], dag->p2p->dro_seq++);
+ /*Set STOP bit and let DAG expire if we don't need further routes. */
+ if(RPL_P2P_SET_STOP_BIT) {
+
PRINTF("P2P: Setting STOP bit in DRO\n");
+
RPL_FLAG_SET(P2P_DRO_S, buffer[pos]);
+
dag->p2p->lifetime = 0;
+ }
+ /* Request DRO-ACK */
+ RPL_FLAG_SET(P2P_DRO_A, buffer[pos]);
+ pos++;
+ /* Reserved */
+ buffer[pos++] = 0;
+ memcpy(&buffer[pos], &dag->dag_id, 16);
+ pos += 16;
+
+ /* Add the route discovery option */
+ write_rdo(&buffer[pos], dag, addr_list);

+ /* Clear Rem field */


+ buffer[pos + 3] &= ~RPL_P2P_RDO_R_MASK;
+ /* Set Rem field to number of address in the vector */
+ rem = (buffer[pos + 1] - 2) / (16 - RPL_BITMASK_READ(P2P_RDO_C,
buffer[pos + 2])) - 1;
+ RPL_BITMASK_WRITE(P2P_RDO_R, buffer[pos + 3], rem);
+ pos += buffer[pos + 1] + 2;
+ /* No metric container */
+
+ /* Cache the packet in order to being able to retransmit it in case no
ack was
+
* received. */
+ if(pos <= RPL_DRO_CACHE_ENTRY_SIZE) {
+
rpl_dro_cache_entry_t *c;
+
c = memb_alloc(&dro_cache_memb);
+
if (c != NULL) {
+
c->length = pos;
+
memcpy(&c->buffer, buffer, c->length);
+
c->rexmits = 0;
+
ctimer_set(&c->timer, RPL_DRO_ACK_WAIT_TIME, dro_rexmit, c);
+
list_add(dro_cache, c);
+
PRINTF("RPL: Caching DRO at %p length %d\n", &c->buffer, c>length);
+
} else {
+
PRINTF("RPL: No free memory to cache DRO\n");
+
}
+ } else {
+
PRINTF("RPL: DRO too large to cache.\n");
+ }
+
+#ifdef SENSLAB
+ printf("P2P DRO ");
+ print6addr(&dag->dag_id);
+ printf(" 0x%02x %u Bytes ", dag->instance_id, pos);
+ rpl_print_rdo(&buffer[20], &dag->dag_id);
+ putchar('\n');
+#endif /* SENSLAB */
+
+ /* print_buffer(buffer, pos); */
+ PRINTF("RPL: Sending DRO\n");
+ uip_create_linklocal_rplnodes_mcast(&addr);
+ uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DRO, pos);
+}
+#endif /* WITH_RPL_P2P */
/*--------------------------------------------------------------------------*/
void
uip_rpl_input(void)
{
+ uip_ds6_nbr_t *nbr;
+
+ /* Make sure neighbor cache is also filled when receiving DROs. */
+ if((nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr)) == NULL) {

+
if((nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, (uip_lladdr_t *)
+
packetbuf_addr(PACKETBUF_ADDR_SENDER),
+
0, NBR_REACHABLE)) != NULL) {
+
/* set reachable timer */
+
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
+
PRINTF("RPL: Neighbor added to neighbor cache ");
+
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
+
PRINTF(", ");
+
PRINTLLADDR((uip_lladdr_t
*)packetbuf_addr(PACKETBUF_ADDR_SENDER));
+
PRINTF("\n");
+
}
+ } else {
+
PRINTF("RPL: Neighbor already in neighbor cache\n");
+ }
+
PRINTF("Received an RPL control message\n");
switch(UIP_ICMP_BUF->icode) {
case RPL_CODE_DIO:
@@ -752,16 +1657,37 @@ uip_rpl_input(void)
case RPL_CODE_DIS:
dis_input();
break;
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
case RPL_CODE_DAO:
dao_input();
break;
case RPL_CODE_DAO_ACK:
dao_ack_input();
break;
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
+#if WITH_RPL_P2P
+ case RPL_CODE_DRO:
+
dro_input();
+
break;
+ case RPL_CODE_DRO_ACK:
+
dro_ack_input();
+
break;
+#if WITH_RPL_P2P_MEASUREMENT
+ case RPL_CODE_MO:
+
mo_input();
+
break;
+#endif /* WITH_RPL_P2P_MEASUREMENT */
+#endif /* WITH_RPL_P2P */
default:
PRINTF("RPL: received an unknown ICMP6 code (%u)\n", UIP_ICMP_BUF>icode);
break;
}
-

uip_len = 0;

+ /* When this function returns and uip_len != 0 then the content of the
uip_buf
+
* gets sent. */
+ if(rpl_send_uip_buf) {
+
rpl_send_uip_buf = 0;
+ } else {
+
uip_len = 0;
+ }
}
diff --git a/core/net/rpl/rpl-of-etx.c b/core/net/rpl/rpl-of-etx.c
index 55bbadc..6c1b92d 100644
--- a/core/net/rpl/rpl-of-etx.c
+++ b/core/net/rpl/rpl-of-etx.c
@@ -41,6 +41,7 @@
*
transmissions (ETX) as the additive routing metric.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes
<nvt@sics.se>
+ * Contributor: Matthias Philipp <matthias-philipp@gmx.de>
*/
#include "net/rpl/rpl-private.h"
@@ -54,6 +55,7 @@ static void parent_state_callback(rpl_parent_t *, int,
int);
static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t);
static void update_metric_container(rpl_dag_t *);
+static int p2p_route_cmp(rpl_dag_t *, rpl_dio_t *, rpl_parent_t *);
rpl_of_t rpl_of_etx = {
reset,
@@ -61,7 +63,8 @@ rpl_of_t rpl_of_etx = {
best_parent,
calculate_rank,
update_metric_container,
- 1
+ 1,
+ p2p_route_cmp
};
#define NI_ETX_TO_RPL_ETX(etx)
\
@@ -114,7 +117,7 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
}
rank_increase = NEIGHBOR_INFO_FIX2ETX(INITIAL_LINK_METRIC) *
DEFAULT_MIN_HOPRANKINC;
} else {
rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric) * p->dag>min_hoprankinc;
+
rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric) * p->dag>config.min_hoprankinc;
if(base_rank == 0) {
base_rank = p->rank;
}
@@ -211,3 +214,33 @@ update_metric_container(rpl_dag_t *dag)

#endif /* RPL_DAG_MC */
}
+
+/* Compare currently advertised P2P route with route advertised in the
DIO.
+ * If the parent argument is not NULL, the link metric to that parent is
+ * included in the comparison.
+ * Returns an integer less than, equal to, or greater than zero if the
route
+ * advertised in the DIO is found, respectively, to be worse, be equal,
or be
+ * better than the route currently advertised. */
+static int
+p2p_route_cmp(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p)
+{
+ rpl_path_metric_t dag_metric;
+ rpl_path_metric_t dio_metric;
+ rpl_path_metric_t min_diff;
+
+ min_diff = RPL_DAG_MC_ETX_DIVISOR / PARENT_SWITCH_THRESHOLD_DIV;
+
+ dag_metric = dag->mc.obj.etx;
+ dio_metric = dio->mc.obj.etx;
+ if(p != NULL) {
+
dio_metric += NI_ETX_TO_RPL_ETX(p->link_metric);
+ }
+
+ if(dio_metric > dag_metric - min_diff && dio_metric < dag_metric +
min_diff) {
+
return 0;
+ } else if(dio_metric > dag_metric) {
+
return -1;
+ } else {
+
return 1;
+ }
+}
diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c
index b9ea90a..54ae0fd 100644
--- a/core/net/rpl/rpl-of0.c
+++ b/core/net/rpl/rpl-of0.c
@@ -37,6 +37,7 @@
*
An implementation of RPL's objective function 0.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes
<nvt@sics.se>
+ * Contributor: Matthias Philipp <matthias-philipp@gmx.de>
*/
#include "net/rpl/rpl-private.h"
@@ -50,6 +51,7 @@ static void reset(rpl_dag_t *);
static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t);
static void update_metric_container(rpl_dag_t *);

+static int p2p_route_cmp(rpl_dag_t *, rpl_dio_t *, rpl_parent_t *);


rpl_of_t rpl_of0 = {
reset,
@@ -57,12 +59,13 @@ rpl_of_t rpl_of0 = {
best_parent,
calculate_rank,
update_metric_container,
- 0
+ 0,
+ p2p_route_cmp
};
#define DEFAULT_RANK_INCREMENT

DEFAULT_MIN_HOPRANKINC

-#define MIN_DIFFERENCE (NEIGHBOR_INFO_ETX_DIVISOR +


NEIGHBOR_INFO_ETX_DIVISOR / 2)
+#define MIN_DIFFERENCE NEIGHBOR_INFO_ETX_DIVISOR
static void
reset(rpl_dag_t *dag)
@@ -81,7 +84,7 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
base_rank = p->rank;
}
- increment = p != NULL ? p->dag->min_hoprankinc :
DEFAULT_RANK_INCREMENT;
+ increment = p != NULL ? p->dag->config.min_hoprankinc :
DEFAULT_RANK_INCREMENT;
if((rpl_rank_t)(base_rank + increment) < base_rank) {
PRINTF("RPL: OF0 rank %d incremented to infinite rank due to
wrapping\n",
@@ -131,3 +134,31 @@ update_metric_container(rpl_dag_t *dag)
{
dag->mc.type = RPL_DAG_MC_NONE;
}
+
+/* Compare currently advertised P2P route with route advertised in the
DIO.
+ * If the parent argument is not NULL, the link metric to that parent is
+ * included in the comparison.
+ * Returns an integer less than, equal to, or greater than zero if the
route
+ * advertised in the DIO is found, respectively, to be worse, be equal,
or be
+ * better than the route currently advertised. */
+static int
+p2p_route_cmp(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p)
+{
+ rpl_rank_t dag_rank;
+ rpl_rank_t dio_rank;
+
+ dag_rank = DAG_RANK(dag->rank, dag) * NEIGHBOR_INFO_ETX_DIVISOR;

+ if(p != NULL) {
+
dio_rank = DAG_RANK(dio->rank + dag->config.min_hoprankinc, dag) *
NEIGHBOR_INFO_ETX_DIVISOR;
+ } else {
+
dio_rank = DAG_RANK(dio->rank, dag) * NEIGHBOR_INFO_ETX_DIVISOR;
+ }
+
+ if(dio_rank > dag_rank - MIN_DIFFERENCE && dio_rank < dag_rank +
MIN_DIFFERENCE) {
+
return 0;
+ } else if(dio_rank > dag_rank) {
+
return -1;
+ } else {
+
return 1;
+ }
+}
diff --git a/core/net/rpl/rpl-p2p.c b/core/net/rpl/rpl-p2p.c
new file mode 100644
index 0000000..6176e10
--- /dev/null
+++ b/core/net/rpl/rpl-p2p.c
@@ -0,0 +1,691 @@
+/**
+ * \addtogroup uip6
+ * @{
+ */
+/*
+ * Copyright (c) 2011, Institut National de Recherche en Informatique et
en
+ * Automatique (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.
+ */
+/**
+ * \file
+ *
RPL Point to Point (P2P) extension.
+ *
+ * Reactive Discovery of Point-to-Point Routes in Low Power and Lossy
Networks
+ * draft-ietf-roll-p2p-rpl-07
+ *
+ * \author Matthias Philipp <matthias-philipp@gmx.de>
+ * Contributor: Emmanuel Baccelli <emmanuel.baccelli@inria.fr>
+ */
+
+#define DEBUG DEBUG_NONE
+#include "net/uip-debug.h"
+
+#include "net/rpl/rpl.h"
+#include "net/rpl/rpl-p2p.h"
+
+#include "net/uip.h"
+#include "net/uip-ds6.h"
+#include "lib/list.h"
+#include "lib/memb.h"
+#include "sys/ctimer.h"
+
+#include <limits.h>
+#include <string.h>
+
+/***********************************************************************
*/
+int rpl_p2p_event_dro;
+#if WITH_RPL_P2P_MEASUREMENT
+int rpl_p2p_event_mo;
+#endif /* WITH_RPL_P2P_MEASUREMENT */
+/***********************************************************************
*/
+static rpl_dag_p2p_t dag_p2p_table[RPL_MAX_DAG_P2P_ENTRIES];
+MEMB(src_route_addr_memb, rpl_src_route_addr_t,
RPL_MAX_SRC_ROUTE_ADDR_ENTRIES);
+static uint8_t instance = 0;

+rpl_dag_t *latest_p2p_dag = NULL;


+/***********************************************************************
*/
+static void free_addr_list(list_t addr_list);
+static rpl_src_route_addr_t * add_src_route_addr(list_t addr_list,
rpl_cmpr_addr_t *addr);
+/***********************************************************************
*/
+const rpl_dodag_config_t P2P_DEFAULT_DODAG_CONFIG = {
+ DEFAULT_P2P_DIO_INTERVAL_DOUBLINGS,
+ DEFAULT_P2P_DIO_INTERVAL_MIN,
+ DEFAULT_P2P_DIO_REDUNDANCY,
+ 0,
/* Max rank increase */
+ DEFAULT_MIN_HOPRANKINC,
+ 1,
/* OCP */
+ RPL_DEFAULT_LIFETIME,
+ RPL_DEFAULT_LIFETIME_UNIT
+};
+/***********************************************************************
*/
+static void
+free_addr_list(list_t addr_list)
+{
+ rpl_src_route_addr_t *a;
+
+ /* Free memory allocated by source route */
+ for(a = list_pop(addr_list); a != NULL; a = list_pop(addr_list)) {
+
memb_free(&src_route_addr_memb, a);
+ }
+}
+/***********************************************************************
*/
+static rpl_src_route_addr_t *
+add_src_route_addr(list_t addr_list, rpl_cmpr_addr_t *addr)
+{
+ rpl_src_route_addr_t *a;
+
+ a = memb_alloc(&src_route_addr_memb);
+ if (a == NULL) {
+
RPL_STAT(rpl_stats.mem_overflows++);
+
return NULL;
+ }
+ memcpy(&a->addr, addr, sizeof(rpl_cmpr_addr_t));
+ list_add(addr_list, a);
+
+ return a;
+}
+/*--------------------------------------------------------------------------*/
+uint8_t
+rpl_p2p_add_partial_route(rpl_dag_t *dag, rpl_dio_t *dio)
+{
+ uint8_t i, j;
+

+ for(i = 0; i < RPL_P2P_MAX_PARTIAL_ROUTES; i++) {


+
if(list_length(dag->p2p->partial_routes[i]) == 0) {
+
/* Copy the addresses from the packet buffer into static memory */
+
for(j = 0; j < dio->rdo->addr_len; j += 16 - dio->rdo->compr) {
+
if(add_src_route_addr(dag->p2p->partial_routes[i],
(rpl_cmpr_addr_t *)(dio->rdo->addr_start + j)) == NULL) {
+
free_addr_list(dag->p2p->partial_routes[i]);
+
return 0;
+
}
+
}
+
/* If the address vector is empty we add the DODAGID as special
value in
+
* order to being able to tell an unused partial address list
apart from a
+
* one hop route. */
+
if(dio->rdo->addr_len == 0) {
+
if(add_src_route_addr(dag->p2p->partial_routes[i],
(rpl_cmpr_addr_t *)(((uint8_t *)&dag->dag_id) + dio->rdo->compr)) ==
NULL) {
+
free_addr_list(dag->p2p->partial_routes[i]);
+
return 0;
+
}
+
}
+
/* We do not add our compressed global address to the source route
option yet,
+
* since this would unnecessarily block memory. The address is
added when
+
* sending the DIO. */
+
return 1;
+
}
+ }
+ return 0;
+}
+/***********************************************************************
*/
+uip_ipaddr_t*
+rpl_get_own_addr(uint8_t global)
+{
+ int i;
+
+ for (i = 0; i < UIP_DS6_ADDR_NB; i++) {
+
if (uip_ds6_if.addr_list[i].isused &&
+
(uip_ds6_if.addr_list[i].state == ADDR_TENTATIVE ||
+
uip_ds6_if.addr_list[i].state == ADDR_PREFERRED)) {
+
if (global && !
uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
+
return &uip_ds6_if.addr_list[i].ipaddr;
+
} else if(!global &&
uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
+
return &uip_ds6_if.addr_list[i].ipaddr;
+
}
+
}
+ }
+ return NULL;

+}
+/***********************************************************************
*/
+rpl_dag_p2p_t *
+rpl_p2p_alloc_dag(rpl_dag_t *dag)
+{
+ rpl_dag_p2p_t *p2p;
+ rpl_dag_p2p_t *end;
+ uint8_t i;
+
+ for (p2p = &dag_p2p_table[0], end = p2p + RPL_MAX_DAG_P2P_ENTRIES; p2p
< end; p2p++) {
+
if (p2p->dag == NULL || p2p->dag->used == 0) {
+
memset(p2p, 0, sizeof(*p2p));
+
for(i = 0; i < RPL_P2P_MAX_PARTIAL_ROUTES; i++) {
+
p2p->partial_routes[i] = &p2p->partial_routes_lists[i];
+
p2p->partial_routes_lists[i] = NULL;
+
list_init(p2p->partial_routes[i]);
+
}
+
p2p->dag = dag;
+
PRINTF("RPL: Allocated P2P at %p with DAG at %p\n", p2p, dag);
+
latest_p2p_dag = dag;
+
return p2p;
+
}
+ }
+ ANNOTATE("#A err=Store0\n");
+ return NULL;
+}
+/***********************************************************************
*/
+void
+rpl_p2p_free_dag(rpl_dag_p2p_t *p2p)
+{
+ uint8_t i;
+
+ for(i = 0; i < RPL_P2P_MAX_PARTIAL_ROUTES; i++) {
+
free_addr_list(p2p->partial_routes[i]);
+ }
+ /* Free the DAG */
+ p2p->dag->p2p = NULL;
+ rpl_free_dag(p2p->dag);
+ p2p->dag = NULL;
+}
+/***********************************************************************
*/
+void
+rpl_p2p_purge_dags(void)
+{
+ rpl_dag_p2p_t *p2p;
+ rpl_dag_p2p_t *end;
+
+ for (p2p = &dag_p2p_table[0], end = p2p + RPL_MAX_DAG_P2P_ENTRIES; p2p
< end; p2p++) {
+
if (p2p->dag != NULL && p2p->dag->used) {

+#if 0
+
printf("RPL: Lifetime of P2P DAG ");
+
print6addr(&p2p->dag->dag_id);
+
printf(" is %d sec\n", p2p->lifetime);
+#endif
+
if (p2p->lifetime <= 1 && p2p->expired) {
+
PRINTF("RPL: Freeing expired P2P DAG ");
+
PRINT6ADDR(&p2p->dag->dag_id);
+
PRINTF("\n");
+
rpl_p2p_free_dag(p2p);
+
}
+
else if (p2p->lifetime <= 1 && !p2p->expired) {
+
PRINTF("RPL: Lifetime of P2P DAG ");
+
PRINT6ADDR(&p2p->dag->dag_id);
+
PRINTF(" expired\n");
+
/* Stop sending DIOs for this DAG but still keep it in memory
for some
+
* time in order to ignore DIOs from neighbors whose lifetime is
not yet
+
* expired.
+
* XXX This timeout has to be chosen carefully because if we
receive a
+
* DIO for this DAG after we deleted it, the DAG object will be
created
+
* again and new DIOs are emmitted, which will keep the DAG
alive on the
+
* other nodes and so on.
+
* A save value should be the minimum lifetime (which is set
upon receiving a
+
* DIO) plus some fixed propagation time. */
+
p2p->lifetime = rpl_p2p_lt2sec(p2p->rdo_lifetime) + 10;
+
p2p->expired = 1;
+
ctimer_stop(&p2p->dag->dio_timer);
+
/* Parent memory is shared betwee DAGs. Since we only keep the
DAG to
+
* detect and ignore corresponding DIOs, we can safely free the
parents. */
+
rpl_remove_parents(p2p->dag, 0);
+#if (DEBUG) & DEBUG_ANNOTATE
+
rpl_repaint_links();
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
+#ifdef SENSLAB
+
printf("P2P DAG ");
+
print6addr(&p2p->dag->dag_id);
+
printf(" 0x%02x EXPIRED\n", p2p->dag->instance_id);
+#endif /* SENSLAB */
+
}
+
else {
+
p2p->lifetime--;
+
}
+
}
+ }
+}

+/***********************************************************************
*/
+uint16_t
+rpl_p2p_lt2sec(uint8_t lifetime)
+{
+ switch (lifetime) {
+
case RPL_P2P_DAG_LIFETIME_1_SEC:
+
return 1;
+
case RPL_P2P_DAG_LIFETIME_4_SEC:
+
return 4;
+
case RPL_P2P_DAG_LIFETIME_16_SEC:
+
return 16;
+
case RPL_P2P_DAG_LIFETIME_64_SEC:
+
return 64;
+
default:
+
return 0;
+ }
+}
+/***********************************************************************
*/
+uint8_t
+rpl_discover_route(uip_ipaddr_t *target)
+{
+
+ /* create temporary DAG */
+ rpl_dag_t *dag;
+ uint8_t instance_id;
+
+ /* Increase the local RPLInstanceID each time we issue a new request.
*/
+ instance = (instance + 1) % 0x40;
+ instance_id = RPL_LOCAL_DEFAULT_INSTANCE | instance;
+
+ dag = rpl_get_dag(instance_id, rpl_get_own_addr(1));
+ if(dag != NULL) {
+
PRINTF("RPL: Dropping a local DAG when starting route discovery");
+
rpl_free_dag(dag);
+ }
+ dag = rpl_alloc_dag(instance_id);
+ if(dag == NULL) {
+
PRINTF("RPL: Failed to allocate a DAG\n");
+#ifdef SENSLAB
+
puts("ERR MEM dag");
+#endif /* SENSLAB */
+
return 0;
+ }
+
+ dag->p2p = rpl_p2p_alloc_dag(dag);
+ if (dag->p2p == NULL) {
+
PRINTF("RPL: Failed to allocate P2P extension for DAG\n");
+#ifdef SENSLAB
+
puts("ERR MEM p2p");
+#endif /* SENSLAB */
+
rpl_free_dag(dag);

+
return 0;
+ }
+
+ dag->used = 1;
+ dag->joined = 1;
+ dag->version = 0;
+ dag->preferred_parent = NULL;
+ /* set P2P specific DAG configuration options */
+ dag->grounded = 0;
+ dag->mop = RPL_MOP_P2P_ROUTE_DISCOVERY;
+ dag->dtsn_out = 0;
+ dag->preference = 0;
+ memcpy(&dag->dag_id, rpl_get_own_addr(1), sizeof(dag->dag_id));
+ rpl_set_dodag_config(dag, &P2P_DEFAULT_DODAG_CONFIG);
+ /* The ROOT_RANK macro relies on the configuration option being set!
*/
+ dag->rank = ROOT_RANK(dag);
+ dag->of->update_metric_container(dag);
+
+ /* additional attributes needed for the P2P routes */
+ dag->p2p->process = PROCESS_CURRENT();
+ dag->p2p->both_directions = RPL_P2P_DEFAULT_BOTH_DIRECTIONS;
+ dag->p2p->hop_by_hop = RPL_P2P_DEFAULT_HOP_BY_HOP;
+ dag->p2p->num_routes = RPL_P2P_DEFAULT_NUM_ROUTES;
+ /* Lifetime as specified in RDO */
+ dag->p2p->rdo_lifetime = RPL_P2P_DEFAULT_DAG_LIFETIME;
+ dag->p2p->max_rank = RPL_P2P_DEFAULT_MAX_RANK;
+ /* Remaining lifetime of the DAG in seconds */
+ dag->p2p->lifetime = rpl_p2p_lt2sec(dag->p2p->rdo_lifetime);
+ dag->p2p->expired = 0;
+ /* Compression of addresses in RDO target and address vector */
+ dag->p2p->compr = RPL_P2P_RDO_COMPR;
+ /* Compress target */
+ memcpy(&dag->p2p->target, ((uint8_t *)target) + dag->p2p->compr, 16 dag->p2p->compr);
+
+ /* Route discovery DIO may travel as long as this constranint is met
*/
+ dag->p2p->constr.type = dag->mc.type;
+ dag->p2p->constr.flags = RPL_DAG_MC_FLAG_C;
+ dag->p2p->constr.aggr = 0;
+ /* Equals MAX_PATH_COST in OF ETX i.e. no constraint */
+ dag->p2p->constr.obj.etx = 100 * RPL_DAG_MC_ETX_DIVISOR;
+
+ ANNOTATE("#A p2p=?-%u\n", target->u8[15]);
+ PRINTF("RPL: Initialized DAG with instance ID 0x%02x for routediscovery to ", dag->instance_id);
+ PRINT6ADDR(target);
+ PRINTF("\n");
+#if (DEBUG) & DEBUG_ANNOTATE
+ rpl_repaint_links();
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
+#ifdef SENSLAB
+ printf("P2P DAG ");

+ print6addr(&dag->dag_id);
+ printf(" 0x%02x DISCOVER ", dag->instance_id);
+ print6addr(target);
+ putchar('\n');
+#endif /* SENSLAB */
+
+ /* send DIO */
+ rpl_reset_dio_timer(dag, 1);
+
+ return 1;
+}
+/***********************************************************************
*/
+uint8_t
+rpl_p2p_meets_constraints(rpl_metric_container_t *metric,
rpl_metric_container_t *constr)
+{
+ if (constr == NULL) {
+
/* no constraint, whatever metric is fine */
+
return 1;
+ }
+ if (metric->type != constr->type) {
+
PRINTF("RPL: Unable to check constraint, metric not matching\n");
+
return 0;
+ }
+ if (metric->type == RPL_DAG_MC_ETX) {
+
PRINTF("RPL: metric: %d, P2P constraint: %d\n", metric>obj.etx/RPL_DAG_MC_ETX_DIVISOR, constr->obj.etx/RPL_DAG_MC_ETX_DIVISOR);
+
return (metric->obj.etx <= constr->obj.etx);
+ }
+ if (metric->type == RPL_DAG_MC_ENERGY) {
+
/* TODO implement some policy here */
+ }
+ return 1;
+}
+#if (DEBUG) & DEBUG_ANNOTATE
+/***********************************************************************
*/
+void
+rpl_annotate_rdo(uint8_t *rdo, uip_ipaddr_t *dodag_id)
+{
+ ANNOTATE("#A p2p=");
+ rpl_print_rdo(rdo, dodag_id);
+ putchar('\n');
+}
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
+#if (DEBUG) & DEBUG_ANNOTATE || defined(SENSLAB)
+/***********************************************************************
*/
+void
+rpl_print_rdo(uint8_t *rdo, uip_ipaddr_t *dodag_id)
+{
+ uint8_t first, last;
+ uint8_t *a;

+ int a_add;
+
+ uint8_t compr = RPL_BITMASK_READ(P2P_RDO_C, *(rdo + 2));
+ uint8_t *a_first = rdo + 4 + 16 - compr;
+ uint8_t *a_last = rdo + 2 + *(rdo + 1) - 16 + compr;
+
+ if(uip_ds6_is_my_addr(dodag_id)) {
+
/* We are the origin, traverse forward */
+
first = dodag_id->u8[15];
+
last = *(rdo + 4 + 16 - compr - 1);
+
a = a_first;
+
a_add = 16 - compr;
+ } else {
+
/* We are an intermediate node or the target, traverse backward. */
+
first = rpl_get_own_addr(1)->u8[15];
+
last = dodag_id->u8[15];
+
a = a_last;
+
a_add = -(16 - compr);
+ }
+ printf("%u-", first);
+ for(; a >= a_first && a <= a_last; a += a_add) {
+
printf("%u-", *(a + 16 - compr - 1));
+ }
+ printf("%u", last);
+}
+#endif /* (DEBUG) & DEBUG_ANNOTATE || defined(SENSLAB) */
+/***********************************************************************
*/
+void
+rpl_p2p_update_dag(rpl_dag_t *dag, rpl_dio_t *dio)
+{
+ uint8_t i;
+
+ PRINTF("RPL: Updating P2P DAG\n");
+ /*uint8_t offset = 4 + 16 - dio->rdo->compr;
+ print_buffer(dio->rdo->addr_start - offset, dio->rdo->addr_len +
offset);*/
+
+ /* The metric options have already been fully created upon parsing the
DIO, so
+
* just copy them. */
+ if(dio->constr != NULL) {
+
memcpy(&dag->p2p->constr, dio->constr,
sizeof(rpl_metric_container_t));
+ } else {
+
dag->p2p->constr.type = RPL_DAG_MC_NONE;
+ }
+
+ /* Copy values from the route discovery option */
+ dag->p2p->both_directions = dio->rdo->both_directions;
+ dag->p2p->num_routes = dio->rdo->num_routes;
+ dag->p2p->compr = dio->rdo->compr;
+ dag->p2p->hop_by_hop = dio->rdo->hop_by_hop;
+ dag->p2p->rdo_lifetime = dio->rdo->lifetime;

+ dag->p2p->max_rank = dio->rdo->max_rank;
+ /* Copy target */
+ memcpy(&dag->p2p->target, dio->rdo->target, 16 - dio->rdo->compr);
+
+ /* Delete all current partial routes and free memory */
+ for(i = 0; i < RPL_P2P_MAX_PARTIAL_ROUTES; i++) {
+
free_addr_list(dag->p2p->partial_routes[i]);
+ }
+ /* Store route advertised in the DIO */
+ printf("P2P: Partial route ");
+ rpl_print_rdo(dio->rdo->start, &dio->dag_id);
+ if(rpl_p2p_add_partial_route(dag, dio)) {
+
printf(" cached\n");
+ } else {
+
printf(" NOT cached\n");
+ }
+}
+/***********************************************************************
*/
+static void
+send_dros(void *data)
+{
+ rpl_dag_t *dag = (rpl_dag_t *)data;
+ uip_ds6_src_route_t *src_route;
+ rpl_src_route_addr_t *a;
+ uip_ipaddr_t addr;
+ uint8_t i, j;
+ list_t addr_list;
+ void *empty_list = NULL;
+
+
+ /* Send as many DROs as routes were requested, if so many are
available */
+ for(i = 0, j = 0; i < RPL_P2P_MAX_PARTIAL_ROUTES && j <= dag->p2p>num_routes; i++) {
+
addr_list = dag->p2p->partial_routes[i];
+
/* Ignore empty address lists */
+
if(list_length(addr_list) == 0) {
+
continue;
+
}
+
if(list_length(addr_list) == 1 &&
+
memcmp(&((rpl_src_route_addr_t *)list_head(addr_list))->addr,
((uint8_t *)&dag->dag_id) + dag->p2p->compr, 16 - dag->p2p->compr) == 0)
{
+
/* Treat as empty address list */
+
addr_list = &empty_list;
+
}
+
+
/* Store the backward route if necessary */
+
if(j == 0 && dag->p2p->both_directions &&
RPL_P2P_STORE_BACKWARD_ROUTES) {
+
src_route = uip_ds6_src_route_add(&dag->dag_id);
+
if(src_route == NULL) {
+
PRINTF("RPL: Unable to store source route\n");

+
ANNOTATE("#A err=Store1\n");
+#ifdef SENSLAB
+
puts("ERR MEM srcrt");
+#endif /* SENSLAB */
+
} else {
+
src_route->state.lifetime = (unsigned long)(dag>config.default_lifetime * dag->config.lifetime_unit);
+
for(a = list_head(addr_list); a != NULL; a = list_item_next(a))
{
+
/* Decompress address */
+
memcpy(&addr, &dag->dag_id, dag->p2p->compr);
+
memcpy(((uint8_t *)&addr) + dag->p2p->compr, &a->addr, 16 dag->p2p->compr);
+
/* XXX This is a hack! we need link local addresses in the
source route,
+
* since neighbor discovery is not implemented or does not
work. */
+
uip_create_linklocal_prefix(&addr);
+
/* Add intermediate hops */
+
if(uip_ds6_src_route_hop_add(src_route, &addr, 1) == NULL) {
+
uip_ds6_src_route_rm(src_route);
+
src_route = NULL;
+
PRINTF("RPL: Unable to store all addresses of source
route\n");
+
ANNOTATE("#A err=Store2\n");
+#ifdef SENSLAB
+
puts("ERR MEM srcrt entry");
+#endif /* SENSLAB */
+
break;
+
}
+
}
+
if(src_route != NULL) {
+
/* Add the link local address of the origin at the very end.
*/
+
memcpy(&addr, &dag->dag_id, 16);
+
/* XXX This is a hack! we need link local addresses in the
source route,
+
* since neighbor discovery is not implemented or does not
work. */
+
uip_create_linklocal_prefix(&addr);
+
if(uip_ds6_src_route_hop_add(src_route, &addr, 0) == NULL) {
+
uip_ds6_src_route_rm(src_route);
+
PRINTF("RPL: Unable to store last address of source
route\n");
+
ANNOTATE("#A err=Store2\n");
+ #ifdef SENSLAB
+
puts("ERR MEM srcrt entry");
+ #endif /* SENSLAB */
+
}
+
}
+
}
+
}
+
/* Send DRO for this route */
+
dro_output(dag, addr_list);

+
j++;
+ }
+}
+/***********************************************************************
*/
+void
+rpl_p2p_process_target(rpl_dag_t *dag, rpl_dio_t *dio)
+{
+ if(!rpl_p2p_is_target(dag->p2p)) {
+
PRINTF("RPL: We are not the target!\n");
+
return;
+ }
+ /* Stop the DIO timer. */
+ ctimer_stop(&dag->dio_timer);
+
+ if(dag->p2p->dro_timer.f != NULL) {
+
PRINTF("RPL: DRO timer already started!\n");
+
return;
+ }
+ /* Start the DRO timer. */
+ ctimer_set(&dag->p2p->dro_timer, RPL_P2P_DRO_WAIT_TIME, send_dros,
dag);
+
+ PRINTF("----> RPL: Route discovery reached target <----\n");
+#if (DEBUG) & DEBUG_ANNOTATE
+ rpl_annotate_rdo(dio->rdo->start, &dio->dag_id);
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
+#ifdef SENSLAB
+ printf("P2P DAG ");
+ print6addr(&dio->dag_id);
+ printf(" 0x%02x REACHED ", dio->instance_id);
+ rpl_print_rdo(dio->rdo->start, &dio->dag_id);
+ putchar('\n');
+#endif /* SENSLAB */
+}
+/***********************************************************************
*/
+uip_ds6_src_route_t *
+rpl_p2p_add_src_route(uip_ipaddr_t *dest, uint8_t *addr_start, uint8_t
addr_len, uint8_t compr, uint8_t reverse)
+{
+ uip_ds6_src_route_t *src_route;
+ uint8_t i;
+ uip_ipaddr_t addr;
+
+ src_route = uip_ds6_src_route_add(dest);
+ if(src_route == NULL) {
+
PRINTF("RPL: Unable to store source route\n");
+
ANNOTATE("#A err=Store1\n");
+#ifdef SENSLAB
+
puts("ERR MEM srcrt");
+#endif /* SENSLAB */
+
return NULL;
+ }

+ /* TODO take lifetime from DAG configuration */


+ src_route->state.lifetime = (unsigned long)(RPL_DEFAULT_LIFETIME *
RPL_DEFAULT_LIFETIME_UNIT);
+ for(i = 0; i < addr_len; i += 16 - compr) {
+
/* Decompress address */
+
memcpy(&addr, dest, compr);
+
memcpy(((uint8_t *)&addr) + compr, addr_start + i, 16 - compr);
+
/* XXX This is a hack! we need link local addresses in the source
route,
+
* since neighbor discovery is not implemented or does not work. */
+
uip_create_linklocal_prefix(&addr);
+
/* Add intermediate hops in correct order (depending on whether this
is
+
* called on the origin after receiving a DRO or on the target after
receiving
+
* a DIO) */
+
if(uip_ds6_src_route_hop_add(src_route, &addr, reverse) == NULL) {
+
uip_ds6_src_route_rm(src_route);
+
PRINTF("RPL: Unable to store all addresses of source route\n");
+
ANNOTATE("#A err=Store2\n");
+#ifdef SENSLAB
+
puts("ERR MEM srcrt entry");
+#endif /* SENSLAB */
+
return NULL;
+
}
+ }
+ /* Add the link local address of the target at the very end. */
+ /* XXX This is a hack! we need link local addresses in the source
route,
+
* since neighbor discovery is not implemented or does not work. */
+ memcpy(&addr, dest, 16);
+ uip_create_linklocal_prefix(&addr);
+ if(uip_ds6_src_route_hop_add(src_route, &addr, 0) == NULL) {
+
uip_ds6_src_route_rm(src_route);
+
PRINTF("RPL: Unable to store last address of source route\n");
+
ANNOTATE("#A err=Store2\n");
+#ifdef SENSLAB
+
puts("ERR MEM srcrt entry");
+#endif /* SENSLAB */
+
return NULL;
+ }
+ return src_route;
+}
+/***********************************************************************
*/
+uip_ds6_route_t *
+rpl_p2p_add_hbh_route(uint8_t instance, uip_ipaddr_t *dodagid,
uip_ipaddr_t *target, uip_ipaddr_t *nexthop)
+{
+ uip_ds6_route_t *hbhrt;
+ rpl_dag_t *dag;
+
+ dag = rpl_get_dag(instance, dodagid);
+ hbhrt = rpl_add_route(dag, target, 128, nexthop);

+ if(hbhrt != NULL) {
+
hbhrt->state.instance = instance;
+
memcpy(&hbhrt->state.dodagid, dodagid, 16);
+ }
+ return hbhrt;
+}
+/***********************************************************************
*/
+uint8_t
+rpl_p2p_route_differs(rpl_dag_t *dag, rpl_dio_t *dio)
+{
+ uint8_t i, j;
+ rpl_src_route_addr_t *a;
+
+ /* DAG and DIO must belong to the same discovery, i.e. share the same
origin
+
* and target. */
+ for(i = 0; i < RPL_P2P_MAX_PARTIAL_ROUTES; i++) {
+
/* Ignore empty address lists */
+
if(list_length(dag->p2p->partial_routes[i]) == 0) {
+
continue;
+
}
+
/* In the special case where the address vector is empty, a matching
route
+
* contains the DODAGID as only hop. */
+
if(dio->rdo->addr_len == 0) {
+
if(list_length(dag->p2p->partial_routes[i]) != 1 ||
+
memcmp(&((rpl_src_route_addr_t *)list_head(dag->p2p>partial_routes[i]))->addr, ((uint8_t *)&dag->dag_id) + dio->rdo->compr,
16 - dio->rdo->compr) != 0) {
+
continue;
+
} else {
+
return 0;
+
}
+
}
+
/* Route differs if length differs */
+
if(list_length(dag->p2p->partial_routes[i]) != dio->rdo->addr_len) {
+
continue;
+
}
+
/* Compare intermediate hops */
+
for(j = 0, a = list_head(dag->p2p->partial_routes[i]);
+
j < dio->rdo->addr_len && a != NULL;
+
j += 16 - dio->rdo->compr, a = list_item_next(a)) {
+
if(memcmp(dio->rdo->addr_start + j, &a->addr, 16 - dio->rdo>compr) != 0) {
+
break;
+
}
+
}
+
if(a == NULL) {
+
return 0;
+
}
+ }
+ return 1;
+}

diff --git a/core/net/rpl/rpl-p2p.h b/core/net/rpl/rpl-p2p.h


new file mode 100644
index 0000000..91e3684
--- /dev/null
+++ b/core/net/rpl/rpl-p2p.h
@@ -0,0 +1,249 @@
+/**
+ * \addtogroup uip6
+ * @{
+ */
+/*
+ * Copyright (c) 2011, Institut National de Recherche en Informatique et
en
+ * Automatique (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.
+ */
+/**
+ * \file

+ *
RPL Point to Point (P2P) extension.
+ *
+ * Reactive Discovery of Point-to-Point Routes in Low Power and Lossy
Networks
+ * draft-ietf-roll-p2p-rpl-07
+ *
+ * \author Matthias Philipp <matthias-philipp@gmx.de>
+ * Contributor: Emmanuel Baccelli <emmanuel.baccelli@inria.fr>
+ */
+
+#ifndef RPL_P2P_H
+#define RPL_P2P_H
+
+#include "net/uip.h"
+#include "net/rpl/rpl-private.h"
+
+#include "lib/list.h"
+
+/* D flag is always zero in control messages (see draft-ietf-roll-rpl14) */
+#define RPL_LOCAL_DEFAULT_INSTANCE
0x80 /* local ID 0 */
+
+/* Compression as used in route discoveries originated by this node. */
+#define RPL_P2P_RDO_COMPR
15
+/* Minimum RDO compression value that can be handled by this node. This
value
+ * affects the size of the memory being reserved for addresses in the
RDO. If
+ * all nodes use the same compr value this can be safely set to
+ * RPL_P2P_RDO_COMPR. For full interoperability this should be set to
zero. This
+ * reserves 16 byte per address in the SRO and is a waste of memory in
case
+ * compression is used. */
+#define RPL_P2P_RDO_COMPR_MIN
RPL_P2P_RDO_COMPR
+
+/* We use one global DAG for routes to the sink, the remaining DAGs can
be used
+ * by the P2P extension */
+#define RPL_MAX_DAG_P2P_ENTRIES
RPL_MAX_DAG_ENTRIES - 1
+/* This is probably a waste of memory on most nodes and to few for
others. Real
+ * malloc() would be very helpful in this case. */
+#define RPL_MAX_SRC_ROUTE_ADDR_ENTRIES 20
+
+/* We use different Trickle timer parameters for P2P RPL */
+#define DEFAULT_P2P_DIO_INTERVAL_DOUBLINGS 16
+#define DEFAULT_P2P_DIO_INTERVAL_MIN
6
+#define DEFAULT_P2P_DIO_REDUNDANCY
1
+
+#define RPL_DRO_ACK_WAIT_TIME
(CLOCK_SECOND * 10)
+#define RPL_DRO_CACHE_ENTRY_SIZE
64
+#define RPL_MAX_DRO_CACHE_ENTRIES
2
+#define RPL_MAX_DRO_REXMITS
2

+#define RPL_P2P_MO_DEFAULT_VECTOR_SIZE 10
+#define RPL_P2P_MO_MAX_REQUESTS
3
+#define RPL_P2P_MAX_PARTIAL_ROUTES
3
+
+#define RPL_MOP_P2P_ROUTE_DISCOVERY
4
/*
+#define RPL_DIO_SUBOPT_ROUTE_DISCOVERY 10
/*
*/
+#define RPL_CODE_DRO
0x04 /*
*/
+#define RPL_CODE_DRO_ACK
0x05 /*
Acknowledgement */
+#define RPL_CODE_MO
0x06 /*
+
+/* Bitmasks of the route discovery option */
+#define RPL_P2P_RDO_D_FLAG
0x80 /*
directions */
+#define RPL_P2P_RDO_H_FLAG
0x40 /*
desired */
+#define RPL_P2P_RDO_N_MASK
0x30 /*
+#define RPL_P2P_RDO_N_SHIFT
4
+#define RPL_P2P_RDO_C_MASK
0x0f /*
+#define RPL_P2P_RDO_C_SHIFT
0
+
+#define RPL_P2P_RDO_L_MASK
0xc0 /*
*/
+#define RPL_P2P_RDO_L_SHIFT
6
+#define RPL_P2P_RDO_R_MASK
0x3f /*
+#define RPL_P2P_RDO_R_SHIFT
0
+
+/* Bitmasks of the discovery reply object */
+#define RPL_P2P_DRO_Q_MASK
0xC0 /*
+#define RPL_P2P_DRO_Q_SHIFT
6
+#define RPL_P2P_DRO_S_FLAG
0x20 /*
+#define RPL_P2P_DRO_A_FLAG
0x10 /*
+
+/* Bitmasks of the measurement object */
+#define RPL_P2P_MO_C_MASK
0xf0 /*
+#define RPL_P2P_MO_C_SHIFT
4
+#define RPL_P2P_MO_T_FLAG
0x08 /*
+#define RPL_P2P_MO_H_FLAG
0x04 /*
+#define RPL_P2P_MO_A_FLAG
0x02 /*
+#define RPL_P2P_MO_R_FLAG
0x01 /*
+
+#define RPL_P2P_MO_B_FLAG
0x80 /*
+#define RPL_P2P_MO_I_FLAG
0x40 /*
+#define RPL_P2P_MO_S_MASK
0x3f /*
+#define RPL_P2P_MO_S_SHIFT
0
+
+#define RPL_P2P_MO_N_MASK
0xf0 /*
+#define RPL_P2P_MO_N_SHIFT
4
+#define RPL_P2P_MO_I_MASK
0x0f /*
+#define RPL_P2P_MO_I_SHIFT
0
+
+/* Lifetime field in the route discovery option

DAG Mode of Operation */


Route discovery option
Discovery reply object
Discovery reply object
Measurement object */
Optimize route in both
Hop-by-hop routes
Number of routes */
Compression */
Temporary DAG lifetime
Rem */

Sequence Number */
Stop bit */
Acknowledgement */
Compression */
Type */
Hop-by-hop */
Accumulate route */
Reverse */
Back request */
Intermediate reply */
Sequence */
Num */
Index */
*/

+#define RPL_P2P_DAG_LIFETIME_1_SEC
0
+#define RPL_P2P_DAG_LIFETIME_4_SEC
1
+#define RPL_P2P_DAG_LIFETIME_16_SEC
2
+#define RPL_P2P_DAG_LIFETIME_64_SEC
3
+
+/* Direction of the requested routes */
+#define RPL_P2P_DEFAULT_BOTH_DIRECTIONS 1
+/* Request hop-by-hop or source routes */
+#define RPL_P2P_DEFAULT_HOP_BY_HOP
0
+/* Number of requested routes */
+#define RPL_P2P_DEFAULT_NUM_ROUTES
0
+/* Lifetime of the temporary DAG */
+#define RPL_P2P_DEFAULT_DAG_LIFETIME
RPL_P2P_DAG_LIFETIME_16_SEC
+/* Hop limit for P2P DIOs */
+#define RPL_P2P_DEFAULT_MAX_RANK
0
+/* Whether the target should store backward source route */
+#define RPL_P2P_STORE_BACKWARD_ROUTES
1
+/* Whether to set the STOP bit when the number of requested routes has
been reached */
+#define RPL_P2P_SET_STOP_BIT
1
+/* Time to wait for additional/alternative/better routes before sending
DRO(s) */
+#define RPL_P2P_DRO_WAIT_TIME
(CLOCK_SECOND * 3)
+
+/* conveniently read and write bitmasks */
+#define RPL_BITMASK_WRITE(name, b, v)
(b |= ((v << RPL_ ## name ##
_SHIFT) & RPL_ ## name ## _MASK))
+#define RPL_BITMASK_READ(name, b)
((b & RPL_ ## name ## _MASK) >>
RPL_ ## name ## _SHIFT)
+/* conveniently set and get flags */
+#define RPL_FLAG_SET(name, b)
(b |= RPL_ ## name ## _FLAG)
+#define RPL_FLAG_CLR(name, b)
(b &= ~(RPL_ ## name ## _FLAG))
+#define RPL_FLAG_GET(name, b)
(b & RPL_ ## name ## _FLAG)
+/* Check whether this node is the target */
+#define rpl_p2p_is_target(p2p)
(memcmp(((uint8_t
*)rpl_get_own_addr(1)) + (p2p)->compr, &(p2p)->target, 16 - (p2p)->compr)
== 0)
+
+extern int rpl_p2p_event_dro;
+#if WITH_RPL_P2P_MEASUREMENT
+extern int rpl_p2p_event_mo;
+
+typedef struct rpl_mo_result {
+ uip_ipaddr_t target;
+ uint16_t path_metric;
+} rpl_mo_result_t;
+#endif /* WITH_RPL_P2P_MEASUREMENT */
+
+typedef union rpl_cmpr_addr_t {
+ uint8_t u8[16 - RPL_P2P_RDO_COMPR];
+} rpl_cmpr_addr_t;
+
+typedef struct rpl_src_route_addr {
+ struct rpl_src_route_addr *next;

+ rpl_cmpr_addr_t addr;
+} rpl_src_route_addr_t;
+
+typedef struct rpl_dio_rdo {
+ uint8_t *start;
+ uint8_t flags1;
+ uint8_t both_directions;
+ uint8_t num_routes;
+ uint8_t compr;
+ uint8_t hop_by_hop;
+ uint8_t lifetime;
+ uint8_t max_rank;
+ uint8_t *target;
+ uint8_t *addr_start;
+ uint8_t addr_len;
+} rpl_dio_rdo_t;
+
+typedef struct rpl_dag_p2p {
+ struct rpl_dag *dag;
+ struct process *process;
+ uint8_t both_directions;
+ uint8_t hop_by_hop;
+ uint8_t num_routes;
+ uint8_t rdo_lifetime;
+ uint8_t max_rank;
+ uint16_t lifetime;
+ uint8_t expired;
+ uint8_t compr;
+ uint8_t dro_seq;
+ struct ctimer dro_timer;
+ rpl_cmpr_addr_t target;
+ rpl_metric_container_t constr;
+ void *partial_routes_lists[RPL_P2P_MAX_PARTIAL_ROUTES];
+ list_t partial_routes[RPL_P2P_MAX_PARTIAL_ROUTES];
+} rpl_dag_p2p_t;
+
+typedef struct rpl_dro_cache_entry {
+ struct rpl_dro_cache *next;
+ uint8_t rexmits;
+ struct ctimer timer;
+ uint8_t length;
+ uint8_t buffer[RPL_DRO_CACHE_ENTRY_SIZE];
+} rpl_dro_cache_entry_t;
+
+uint8_t rpl_discover_route(uip_ipaddr_t *target);
+
+struct rpl_dag_p2p *rpl_p2p_alloc_dag(rpl_dag_t *dag);
+void rpl_p2p_free_dag_p2p(rpl_dag_p2p_t *p2p);
+void rpl_p2p_purge_dags(void);
+uint8_t rpl_p2p_meets_constraints(rpl_metric_container_t *metric,
rpl_metric_container_t *constr);
+void rpl_p2p_update_dag(struct rpl_dag *dag, struct rpl_dio *dio);
+void rpl_p2p_process_target(struct rpl_dag *dag, struct rpl_dio *dio);
+uint16_t rpl_p2p_lt2sec(uint8_t lifetime);

+uint8_t rpl_p2p_add_partial_route(struct rpl_dag *dag, struct rpl_dio


*dio);
+uint8_t rpl_p2p_route_differs(struct rpl_dag *dag, struct rpl_dio *dio);
+uip_ds6_src_route_t *rpl_p2p_add_src_route(uip_ipaddr_t *dest, uint8_t
*addr_start, uint8_t addr_len, uint8_t compr, uint8_t reverse);
+uip_ds6_route_t *rpl_p2p_add_hbh_route(uint8_t instance, uip_ipaddr_t
*dodagid, uip_ipaddr_t *target, uip_ipaddr_t *nexthop);
+
+void dro_output(rpl_dag_t *dag, list_t addr_list);
+#if WITH_RPL_P2P_MEASUREMENT
+void mo_output(uip_ipaddr_t *target);
+#endif /* WITH_RPL_P2P_MEASUREMENT */
+
+#if (DEBUG) & DEBUG_ANNOTATE
+void rpl_annotate_rdo(uint8_t *rdo, uip_ipaddr_t *dodag_id);
+void rpl_repaint_links(void);
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
+#if (DEBUG) & DEBUG_ANNOTATE || defined(SENSLAB)
+void rpl_print_rdo(uint8_t *rdo, uip_ipaddr_t *dodag_id);
+#endif /* (DEBUG) & DEBUG_ANNOTATE || defined(SENSLAB) */
+
+#endif /* RPL_P2P_H */
diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h
index 5341c06..d08de0b 100644
--- a/core/net/rpl/rpl-private.h
+++ b/core/net/rpl/rpl-private.h
@@ -103,13 +103,18 @@
#define ZERO_LIFETIME
0
/* Default route lifetime unit. */
-#define RPL_DEFAULT_LIFETIME_UNIT
+#if WITH_RPL_P2P
+#define RPL_DEFAULT_LIFETIME_UNIT
+#else
+#define RPL_DEFAULT_LIFETIME_UNIT
+//#define RPL_DEFAULT_LIFETIME_UNIT
+#endif /* WITH_RPL_P2P */

0xffff
0x0002
0x0002
0xffff

/* Default route lifetime as a multiple of the lifetime unit. */


#define RPL_DEFAULT_LIFETIME
0xff
#define RPL_LIFETIME(dag, lifetime) \
((unsigned long)(dag)->lifetime_unit * lifetime)
((unsigned long)(dag)->config.lifetime_unit * lifetime)

#ifndef RPL_CONF_MIN_HOPRANKINC
#define DEFAULT_MIN_HOPRANKINC
@@ -118,13 +123,13 @@
#endif
#define DEFAULT_MAX_RANKINC

256
(3 * DEFAULT_MIN_HOPRANKINC)

-#define DAG_RANK(fixpt_rank, dag) ((fixpt_rank) / (dag)->min_hoprankinc)


+#define DAG_RANK(fixpt_rank, dag) ((fixpt_rank) / (dag)>config.min_hoprankinc)

/* Rank of a virtual root node that coordinates DAG root nodes. */


#define BASE_RANK
0
/* Rank of a root node. */
-#define ROOT_RANK(dag)
+#define ROOT_RANK(dag)
#define INFINITE_RANK

(dag)->min_hoprankinc
(dag)->config.min_hoprankinc
0xffff

@@ -174,9 +179,11 @@
#ifdef RPL_CONF_MOP
#define RPL_MOP_DEFAULT
+#elif WITH_RPL_P2P
+#define RPL_MOP_DEFAULT
#else
#define RPL_MOP_DEFAULT
-#endif
+#endif /* WITH_RPL_P2P */

RPL_CONF_MOP
RPL_MOP_NO_DOWNWARD_ROUTES
RPL_MOP_STORING_NO_MULTICAST

/*
* The ETX in the metric container is expressed as a fixed-point value
@@ -186,18 +193,42 @@
#define RPL_DAG_MC_ETX_DIVISOR
128
/* DIS related */
-#define RPL_DIS_SEND
1
+#if WITH_RPL_P2P
+#define RPL_DIS_SEND
0
+#else
+#define RPL_DIS_SEND
0
+//#define RPL_DIS_SEND
1
+#endif /* WITH_RPL_P2P */
#ifdef RPL_DIS_INTERVAL_CONF
#define RPL_DIS_INTERVAL
RPL_DIS_INTERVAL_CONF
#else
#define RPL_DIS_INTERVAL
60
#endif
-#define RPL_DIS_START_DELAY
5
+#define RPL_DIS_START_DELAY
30
+
+/*--------------------------------------------------------------------------*/
+#ifndef RPL_CONF_GLOBAL_MOP
+#define RPL_GLOBAL_MOP
RPL_MOP_NO_DOWNWARD_ROUTES
+#else
+#define RPL_GLOBAL_MOP
RPL_CONF_GLOBAL_MOP
+#endif /* !RPL_CONF_GLOBAL_MOP */
+
+#ifndef RPL_CONF_MAX_DAG_ENTRIES
+#define RPL_MAX_DAG_ENTRIES
4
+#else
+#define RPL_MAX_DAG_ENTRIES
RPL_CONF_MAX_DAG_ENTRIES

+#endif /* !RPL_CONF_MAX_DAG_ENTRIES */
+
+#ifndef RPL_CONF_MAX_PARENTS
+#define RPL_MAX_PARENTS
+#else
+#define RPL_MAX_PARENTS
+#endif /* !RPL_CONF_MAX_PARENTS */
+

20
RPL_CONF_MAX_PARENTS

/*--------------------------------------------------------------------------*/
/* 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;
@@ -205,16 +236,16 @@ struct rpl_dio {
uint8_t version;
uint8_t instance_id;
uint8_t dtsn;
- uint8_t dag_intdoubl;
- uint8_t dag_intmin;
- uint8_t dag_redund;
- rpl_lifetime_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;
+ /* pointers to optional sub-options */
+ rpl_dodag_config_t *dodag_config;
+ rpl_prefix_t *route_info;
+ rpl_prefix_t *prefix_info;
struct rpl_metric_container mc;
+#if WITH_RPL_P2P
+ /* Additional options for P2P extension */
+ struct rpl_dio_rdo *rdo;
+ struct rpl_metric_container *constr;
+#endif /* WITH_RPL_P2P */
};
typedef struct rpl_dio rpl_dio_t;
@@ -244,8 +275,10 @@ extern rpl_stats_t rpl_stats;
/* ICMPv6 functions for RPL. */
void dis_output(uip_ipaddr_t *addr);
void dio_output(rpl_dag_t *, uip_ipaddr_t *uc_addr);
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
void dao_output(rpl_parent_t *, rpl_lifetime_t lifetime);
void dao_ack_output(rpl_dag_t *, uip_ipaddr_t *, uint8_t);
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */

void uip_rpl_input(void);
/* RPL logic functions. */
@@ -258,6 +291,8 @@ int rpl_process_parent_event(rpl_dag_t *,
rpl_parent_t *);
/* DAG object management. */
rpl_dag_t *rpl_alloc_dag(uint8_t);
void rpl_free_dag(rpl_dag_t *);
+uint8_t rpl_set_dodag_config(rpl_dag_t *dag, const rpl_dodag_config_t
*dcf);
+void rpl_remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank);
/* DAG parent management function. */
rpl_parent_t *rpl_add_parent(rpl_dag_t *, rpl_dio_t *dio, uip_ipaddr_t
*);
@@ -276,11 +311,19 @@ void rpl_purge_routes(void);
rpl_of_t *rpl_find_of(rpl_ocp_t);
/* Timer functions. */
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
void rpl_schedule_dao(rpl_dag_t *);
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
void rpl_reset_dio_timer(rpl_dag_t *, uint8_t);
void rpl_reset_periodic_timer(void);
/* Route poisoning. */
void rpl_poison_routes(rpl_dag_t *, rpl_parent_t *);
+/* Helpers */
+uip_ipaddr_t* rpl_get_own_addr(uint8_t global);
+#if (DEBUG) & DEBUG_ANNOTATE
+void rpl_repaint_links();
+#endif /* (DEBUG) & DEBUG_ANNOTATE */
+
#endif /* RPL_PRIVATE_H */
diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c
index dbb7d23..64f872f 100644
--- a/core/net/rpl/rpl-timers.c
+++ b/core/net/rpl/rpl-timers.c
@@ -41,6 +41,9 @@
#include "contiki-conf.h"
#include "net/rpl/rpl-private.h"
+#if WITH_RPL_P2P
+#include "net/rpl/rpl-p2p.h"
+#endif /* WITH_RPL_P2P */
#include "lib/random.h"
#include "sys/ctimer.h"
@@ -64,12 +67,15 @@ static void
handle_periodic_timer(void *ptr)
{

rpl_purge_routes();
+#if WITH_RPL_P2P
+ rpl_p2p_purge_dags();
+#endif /* WITH_RPL_P2P */
rpl_recalculate_ranks();
/* handle DIS */
-#ifdef RPL_DIS_SEND
+#if RPL_DIS_SEND
next_dis++;
- if(rpl_get_dag(RPL_ANY_INSTANCE) == NULL && next_dis >=
RPL_DIS_INTERVAL) {
+ if(rpl_get_dag(RPL_ANY_INSTANCE, NULL) == NULL && next_dis >=
RPL_DIS_INTERVAL) {
next_dis = 0;
dis_output(NULL);
}
@@ -143,14 +149,14 @@ handle_dio_timer(void *ptr)
if(dag->dio_send) {
/* send DIO if counter is less than desired redundancy */
if(dag->dio_counter < dag->dio_redundancy) {
+
if(dag->dio_counter < dag->config.dio_redund) {
#if RPL_CONF_STATS
dag->dio_totsend++;
#endif /* RPL_CONF_STATS */
dio_output(dag, NULL);
} else {
PRINTF("RPL: Supressing DIO transmission (%d >= %d)\n",
dag->dio_counter, dag->dio_redundancy);
+
dag->dio_counter, dag->config.dio_redund);
}
dag->dio_send = 0;
PRINTF("RPL: Scheduling DIO timer %u ticks in future (sent)\n",
@@ -158,7 +164,7 @@ handle_dio_timer(void *ptr)
ctimer_set(&dag->dio_timer, dag->dio_next_delay, handle_dio_timer,
dag);
} else {
/* check if we need to double interval */
if(dag->dio_intcurrent < dag->dio_intmin + dag->dio_intdoubl) {
+
if(dag->dio_intcurrent < dag->config.dio_intmin + dag>config.dio_intdoubl) {
dag->dio_intcurrent++;
PRINTF("RPL: DIO Timer interval doubled %d\n", dag>dio_intcurrent);
}
@@ -178,9 +184,9 @@ void
rpl_reset_dio_timer(rpl_dag_t *dag, uint8_t force)
{
/* only reset if not just reset or started */
- if(force || dag->dio_intcurrent > dag->dio_intmin) {
+ if(force || dag->dio_intcurrent > dag->config.dio_intmin) {
dag->dio_counter = 0;
dag->dio_intcurrent = dag->dio_intmin;

dag->dio_intcurrent = dag->config.dio_intmin;
new_dio_interval(dag);

}
#if RPL_CONF_STATS
@@ -188,6 +194,7 @@ rpl_reset_dio_timer(rpl_dag_t *dag, uint8_t force)
#endif
}
/************************************************************************
/
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST || RPL_MOP_DEFAULT
== RPL_MOP_NON_STORING
static void
handle_dao_timer(void *ptr)
{
@@ -205,7 +212,7 @@ handle_dao_timer(void *ptr)
if(dag->preferred_parent != NULL) {
PRINTF("RPL: handle_dao_timer - sending DAO\n");
/* Set the route lifetime to the default value. */
dao_output(dag->preferred_parent, dag->default_lifetime);
+
dao_output(dag->preferred_parent, dag->config.default_lifetime);
} else {
PRINTF("RPL: No suitable DAO parent\n");
}
@@ -230,4 +237,4 @@ rpl_schedule_dao(rpl_dag_t *dag)
handle_dao_timer, dag);
}
}
-/***********************************************************************
*/
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING_NO_MULTICAST ||
RPL_MOP_DEFAULT == RPL_MOP_NON_STORING */
diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c
index 7c5e05d..b8d62fe 100644
--- a/core/net/rpl/rpl.c
+++ b/core/net/rpl/rpl.c
@@ -37,8 +37,14 @@
*
ContikiRPL, an implementation of IETF ROLL RPL.
*
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes
<nvt@sics.se>
+ * Contributor: Matthias Philipp <matthias-philipp@gmx.de>
*/
+#if WITH_RPL_P2P
+#include "net/rpl/rpl-p2p.h"
+#include "sys/process.h"
+#endif /* WITH_RPL_P2P */
+
#include "net/uip.h"
#include "net/tcpip.h"
#include "net/uip-ds6.h"
@@ -57,6 +63,10 @@ rpl_stats_t rpl_stats;

/************************************************************************
/
extern uip_ds6_route_t uip_ds6_routing_table[UIP_DS6_ROUTE_NB];
+extern struct rpl_dag dag_table[RPL_MAX_DAG_ENTRIES];
+#if WITH_RPL_P2P
+extern uip_ds6_src_route_t
uip_ds6_src_routing_table[UIP_DS6_SRC_ROUTE_NB];
+#endif /* WITH_RPL_P2P */
/************************************************************************
/
void
rpl_purge_routes(void)
@@ -72,6 +82,22 @@ rpl_purge_routes(void)
}
}
}
+#if WITH_RPL_P2P
+ /* Do the same for source routes */
+ for (i = 0; i < UIP_DS6_SRC_ROUTE_NB; i++) {
+
if (uip_ds6_src_routing_table[i].isused) {
+
if (uip_ds6_src_routing_table[i].state.lifetime <= 1) {
+
PRINTF("RPL: purging source route to ");
+
PRINT6ADDR(&uip_ds6_src_routing_table[i].ipaddr);
+
PRINTF("\n");
+
uip_ds6_src_route_rm(&uip_ds6_src_routing_table[i]);
+
}
+
else {
+
uip_ds6_src_routing_table[i].state.lifetime--;
+
}
+
}
+ }
+#endif /* WITH_RPL_P2P */
}
/************************************************************************
/
void
@@ -91,12 +117,26 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix,
int prefix_len,
uip_ipaddr_t *next_hop)
{
uip_ds6_route_t *rep;
+ uint8_t i, i_min;
rep = uip_ds6_route_lookup(prefix);
if(rep == NULL) {
if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop, 0)) ==
NULL) {
PRINTF("RPL: No space for more route entries\n");
return NULL;
+
/* No space for more route entries, remove the one that is to
expire next. */

+
for(i = 0, i_min = 0; i < UIP_DS6_ROUTE_NB; i++) {
+
if(uip_ds6_routing_table[i].state.lifetime <
uip_ds6_routing_table[i_min].state.lifetime) {
+
i_min = i;
+
}
+
}
+
PRINTF("RPL: No space for new route entry, removing old route to
");
+
PRINT6ADDR(&uip_ds6_routing_table[i_min].ipaddr);
+
PRINTF("\n");
+
uip_ds6_route_rm(&uip_ds6_routing_table[i_min]);
+
/* Try again to add the route */
+
if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop, 0)) ==
NULL) {
+
PRINTF("RPL: No space for more route entries\n");
+
return NULL;
+
}
}
} else {
PRINTF("RPL: Updated the next hop for prefix ");
@@ -107,7 +147,11 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix,
int prefix_len,
uip_ipaddr_copy(&rep->nexthop, next_hop);
}
rep->state.dag = dag;
- rep->state.lifetime = RPL_LIFETIME(dag, dag->default_lifetime);
+ if(dag == NULL) {
+
rep->state.lifetime = RPL_DEFAULT_LIFETIME *
RPL_DEFAULT_LIFETIME_UNIT;
+ } else {
+
rep->state.lifetime = RPL_LIFETIME(dag, dag>config.default_lifetime);
+ }
rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL;
PRINTF("RPL: Added a route to ");
@@ -132,36 +176,42 @@ rpl_link_neighbor_callback(const rimeaddr_t *addr,
int known, int etx)
PRINT6ADDR(&ipaddr);
PRINTF(" is %sknown. ETX = %u\n", known ? "" : "no longer ",
NEIGHBOR_INFO_FIX2ETX(etx));
- dag = rpl_get_dag(RPL_DEFAULT_INSTANCE);
- if(dag == NULL) {
return;
- }
+ /* Update all the DAGs */
+ for(dag = &dag_table[0]; dag <= &dag_table[RPL_MAX_DAG_ENTRIES - 1];
dag++) {
+
if (!dag->joined
+#if WITH_RPL_P2P
+
|| (dag->mop == RPL_MOP_P2P_ROUTE_DISCOVERY && dag->p2p>expired)
+#endif /* WITH_RPL_P2P */

+
+
+

) {
continue;
}

+
+
+
+
+
+
+
+
+
-

parent = rpl_find_parent(dag, &ipaddr);


if(parent == NULL) {
if(!known) {
PRINTF("RPL: Deleting routes installed by DAOs received from ");
PRINT6ADDR(&ipaddr);
PRINTF("\n");
uip_ds6_route_rm_by_nexthop(&ipaddr);
parent = rpl_find_parent(dag, &ipaddr);
if(parent == NULL) {
if(!known) {
PRINTF("RPL: Deleting routes installed by DAOs received from ");
PRINT6ADDR(&ipaddr);
PRINTF("\n");
uip_ds6_route_rm_by_nexthop(&ipaddr);
}
continue;
}
return;
}

+
+

/* Trigger DAG rank recalculation. */


parent->updated = 1;
/* Trigger DAG rank recalculation. */
parent->updated = 1;

parent->link_metric = etx;
parent->link_metric = etx;

+
+
+

if(dag->of->parent_state_callback != NULL) {
dag->of->parent_state_callback(parent, known, etx);
}
if(dag->of->parent_state_callback != NULL) {
dag->of->parent_state_callback(parent, known, etx);
}

+
+
+
+
+
+

if(!known) {
PRINTF("RPL: Removing parent ");
PRINT6ADDR(&parent->addr);
PRINTF(" because of bad connectivity (ETX %d)\n", etx);
parent->rank = INFINITE_RANK;
if(!known) {
PRINTF("RPL: Removing parent ");
PRINT6ADDR(&parent->addr);
PRINTF(" because of bad connectivity (ETX %d)\n", etx);
parent->rank = INFINITE_RANK;
}
}
}

/************************************************************************
/
@@ -171,8 +221,8 @@ rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr)
rpl_dag_t *dag;
rpl_parent_t *p;
+
+

/* This only handles one DODAG - if multiple we need to check all */


dag = rpl_get_dag(RPL_ANY_INSTANCE);
/* Local DAGs by the P2P extension are only updated by DIOs */
dag = rpl_get_dag(RPL_ANY_INSTANCE, NULL);
if(dag == NULL) {
return;
}
@@ -212,5 +262,11 @@ rpl_init(void)
#if RPL_CONF_STATS
memset(&rpl_stats, 0, sizeof(rpl_stats));
#endif
+#if WITH_RPL_P2P
+ rpl_p2p_event_dro = process_alloc_event();
+#if WITH_RPL_P2P_MEASUREMENT
+ rpl_p2p_event_mo = process_alloc_event();
+#endif /* WITH_RPL_P2P_MEASUREMENT */
+#endif /* WITH_RPL_P2P */
}
/************************************************************************
/
diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h
index bcc600b..000a2f6 100644
--- a/core/net/rpl/rpl.h
+++ b/core/net/rpl/rpl.h
@@ -140,6 +140,7 @@ struct rpl_metric_container {
typedef struct rpl_metric_container rpl_metric_container_t;
/*--------------------------------------------------------------------------*/
struct rpl_dag;
+struct rpl_dio;
/*--------------------------------------------------------------------------*/
struct rpl_parent {
struct rpl_parent *next;
@@ -183,6 +184,15 @@ typedef struct rpl_parent rpl_parent_t;
* Updates the metric container for outgoing DIOs in a certain DAG.
* If the objective function of the DAG does not use metric containers,
* the function should set the object type to RPL_DAG_MC_NONE.
+ *
+ * p2p_route_cmp(dag, dio, parent)
+ *
+ * Compares the P2P route currently advertised by this node with route
+ * advertised in the DIO. If the parent argument is not NULL, the link
metric

+ * to that parent is included in the comparison.


+ * Returns an integer less than, equal to, or greater than zero if the
route
+ * advertised in the DIO is found, respectively, to be worse, be equal,
or be
+ * better than the route currently advertised.
*/
struct rpl_of {
void (*reset)(struct rpl_dag *);
@@ -191,9 +201,24 @@ struct rpl_of {
rpl_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_t);
void (*update_metric_container)(struct rpl_dag *);
rpl_ocp_t ocp;
+ int (*p2p_route_cmp)(struct rpl_dag *, struct rpl_dio *, rpl_parent_t
*);
};
typedef struct rpl_of rpl_of_t;
/*--------------------------------------------------------------------------*/
+/* 6.7.6. DODAG Configuration */
+struct rpl_dodag_config {
+ /* TODO Security and Path Control currently not implemented */
+ uint8_t dio_intdoubl;
+ uint8_t dio_intmin;
+ uint8_t dio_redund;
+ rpl_rank_t max_rankinc;
+ rpl_rank_t min_hoprankinc;
+ rpl_ocp_t ocp;
+ uint8_t default_lifetime;
+ uint16_t lifetime_unit; /* lifetime in seconds = l_u * d_l */
+};
+typedef struct rpl_dodag_config rpl_dodag_config_t;
+
/* RPL DIO prefix suboption */
struct rpl_prefix {
uip_ipaddr_t prefix;
@@ -219,14 +244,9 @@ struct rpl_dag {
uint8_t grounded;
uint8_t mop;
uint8_t preference;
- uint8_t dio_intdoubl;
- uint8_t dio_intmin;
- uint8_t dio_redundancy;
- rpl_rank_t max_rankinc;
- rpl_rank_t min_hoprankinc;
+ /* inferred from DIO with DODAG Configuration option */
+ rpl_dodag_config_t config;
uint8_t used;
- uint8_t default_lifetime;
- uint16_t lifetime_unit; /* lifetime in seconds = l_u * d_l */
/* live data for the DAG */
uint8_t joined;
uint8_t dio_intcurrent;

@@ -240,11 +260,17 @@ struct rpl_dag {


#endif /* RPL_CONF_STATS */
uint32_t dio_next_delay; /* delay for completion of dio interval */
struct ctimer dio_timer;
+#if RPL_MOP_DEFAULT == RPL_MOP_STORING || RPL_MOP_DEFAULT ==
RPL_MOP_NON_STORING
struct ctimer dao_timer;
+#endif /* RPL_MOP_DEFAULT == RPL_MOP_STORING || RPL_MOP_DEFAULT ==
RPL_MOP_NON_STORING */
rpl_parent_t *preferred_parent;
void *parent_list;
list_t parents;
rpl_prefix_t prefix_info;
+#if WITH_RPL_P2P
+ /* additional state information for P2P routes */
+ struct rpl_dag_p2p *p2p;
+#endif /* WITH_RPL_P2P */
};
typedef struct rpl_dag rpl_dag_t;
/*--------------------------------------------------------------------------*/
@@ -254,6 +280,7 @@ rpl_dag_t *rpl_set_root(uip_ipaddr_t *);
int rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, int len);
int rpl_repair_dag(rpl_dag_t *dag);
int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from);
-rpl_dag_t *rpl_get_dag(int instance_id);
+rpl_dag_t *rpl_get_dag(int instance_id, uip_ipaddr_t *dodag_id);
+
/*--------------------------------------------------------------------------*/
#endif /* RPL_H */
diff --git a/core/net/sicslowpan.c b/core/net/sicslowpan.c
index 9760572..797e086 100644
--- a/core/net/sicslowpan.c
+++ b/core/net/sicslowpan.c
@@ -1368,6 +1368,7 @@ output(uip_lladdr_t *localdest)
*/
PRINTFO("Fragmentation sending packet len %d\n", uip_len);
+
printf("FRAG %d-%d > %u-%u\n", uip_len, uncomp_hdr_len,
MAC_MAX_PAYLOAD, rime_hdr_len);
/* Create 1st Fragment */
PRINTFO("sicslowpan output: 1rst fragment ");
@@ -1455,6 +1456,7 @@ output(uip_lladdr_t *localdest)
* The packet does not need to be fragmented
* copy "payload" and send
*/
+
//printf("NOFRAG %d-%d <= %u-%u\n", uip_len, uncomp_hdr_len,
MAC_MAX_PAYLOAD, rime_hdr_len);
memcpy(rime_ptr + rime_hdr_len, (uint8_t *)UIP_IP_BUF +
uncomp_hdr_len,

uip_len - uncomp_hdr_len);
packetbuf_set_datalen(uip_len - uncomp_hdr_len + rime_hdr_len);
diff --git a/core/net/tcpip.c b/core/net/tcpip.c
index 79b01b8..a817716 100644
--- a/core/net/tcpip.c
+++ b/core/net/tcpip.c
@@ -38,6 +38,7 @@
* \author Adam Dunkels <adam@sics.se>\author
* \author Mathilde Durvy <mdurvy@cisco.com> (IPv6 related code)
* \author Julien Abeille <jabeille@cisco.com> (IPv6 related code)
+ * \author Matthias Philipp <matthias-philipp@gmx.de> (Source routing
header)
*/
#include "contiki-net.h"
@@ -61,6 +62,7 @@
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
+#define print6addr(addr) printf(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:
%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ((u8_t *)addr)[0], ((u8_t *)addr)
[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t
*)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8],
((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)
[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15])
#endif
#if UIP_LOGGING
@@ -552,11 +554,22 @@ tcpip_ipv6_output(void)
{
uip_ds6_nbr_t *nbr = NULL;
uip_ipaddr_t* nexthop;
+ uip_ds6_src_route_t *locsrcrt;
+ uint8_t pos;
+ uint8_t addr_count;
+ uint8_t addr_vector_len;
+ uint8_t hdr_ext_len;
+ uint8_t pad;
+ uint8_t rh_len;
+ uip_ds6_src_route_addr_t *a;
if(uip_len == 0) {
return;
}
+
+
+

PRINTF("sending packet to");


PRINT6ADDR(&UIP_IP_BUF->destipaddr);

if(uip_len > UIP_LINK_MTU) {


UIP_LOG("tcpip_ipv6_output: Packet to big");
uip_len = 0;
@@ -572,6 +585,48 @@ tcpip_ipv6_output(void)
nbr = NULL;
if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){

nexthop = &UIP_IP_BUF->destipaddr;
+
} else if((locsrcrt = uip_ds6_src_route_lookup(&UIP_IP_BUF>destipaddr)) != NULL) {
+
PRINTF("tcpip_ipv6_output: Using source route\n");
+
/* Add extension header and set next hop */
+
pos = UIP_LLIPH_LEN + uip_ext_len;
+
addr_count = list_length(locsrcrt->addr_list);
+
addr_vector_len = ((addr_count - 1) * (16 - UIP_RH4_CMPRI)) + (16
- UIP_RH4_CMPRE);
+
hdr_ext_len = (addr_vector_len + 7) / 8; /* in 8-octet units */
+
pad = (hdr_ext_len * 8) - addr_vector_len;
+
rh_len = (hdr_ext_len * 8) + 8;
+
/* Make room for the extension header */
+
memmove(&uip_buf[pos + rh_len], &uip_buf[pos], uip_len uip_l3_hdr_len);
+
/* Set next hop as destination address */
+
nexthop = &((uip_ds6_src_route_addr_t *)list_head(locsrcrt>addr_list))->addr;
+
memcpy(&UIP_IP_BUF->destipaddr, &((uip_ds6_src_route_addr_t
*)list_head(locsrcrt->addr_list))->addr, 16);
+
/* Add source routing header RH4 after IP header */
+
uip_buf[pos++] = UIP_IP_BUF->proto;
+
UIP_IP_BUF->proto = UIP_PROTO_ROUTING;
+
/* Length of the header in 8-octet units */
+
uip_buf[pos++] = hdr_ext_len;
+
uip_buf[pos++] = 4;
+
uip_buf[pos++] = addr_count;
+
uip_buf[pos++] = UIP_RH4_CMPRI << 4 | (UIP_RH4_CMPRE & 0x0f);
+
uip_buf[pos++] = pad << 4;
+
uip_buf[pos++] = 0;
+
uip_buf[pos++] = 0;
+
/* Copy addresses of intermediate hops (the next hop is skipped,
since it
+
* is already specified in the destination address field). */
+
for (a = list_item_next(list_head(locsrcrt->addr_list)); a !=
NULL; a = list_item_next(a)) {
+
memcpy(&uip_buf[pos], ((uint8_t *)&a->addr) + UIP_RH4_CMPRI, 16
- UIP_RH4_CMPRI);
+
pos += 16 - UIP_RH4_CMPRI;
+
}
+
/* Add the global address of the final destination as last hop */
+
memcpy(&uip_buf[pos], ((uint8_t *)&locsrcrt->ipaddr) +
UIP_RH4_CMPRE, 16 - UIP_RH4_CMPRE);
+
pos += 16 - UIP_RH4_CMPRE;
+
/* Add padding */
+
memset(&uip_buf[pos], 0, pad);
+
pos += pad;
+
/* Update length */
+
uip_ext_len += rh_len;
+
uip_len += rh_len;
+
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
+
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
} else {
uip_ds6_route_t* locrt;

locrt = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
@@ -581,6 +636,9 @@ tcpip_ipv6_output(void)
UIP_FALLBACK_INTERFACE.output();
#else
PRINTF("tcpip_ipv6_output: Destination off-link but no
route\n");
+#ifdef SENSLAB
+
puts("ERR TCPIP no route");
+#endif /* SENSLAB */
#endif
uip_len = 0;
return;
@@ -673,6 +731,7 @@ tcpip_ipv6_output(void)
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/
+

uip_len = 0;
uip_ext_len = 0;
return;

}
}
diff --git a/core/net/uip-debug.h b/core/net/uip-debug.h
index 8015c03..69d315a 100644
--- a/core/net/uip-debug.h
+++ b/core/net/uip-debug.h
@@ -78,11 +78,17 @@ void uip_debug_lladdr_print(const uip_lladdr_t
*addr);
#define PRINTF(...) printf(__VA_ARGS__)
#endif
#define PRINT6ADDR(addr) uip_debug_ipaddr_print(addr)
+#define print6addr(addr) uip_debug_ipaddr_print(addr)
#define PRINTLLADDR(lladdr) uip_debug_lladdr_print(lladdr)
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(lladdr)
+#define print6addr(addr) uip_debug_ipaddr_print(addr)
+#define printlladdr(lladdr) uip_debug_lladdr_print(lladdr)
+#ifdef SENSLAB
+#include <stdio.h>
+#endif /* SENSLAB */
#endif /* (DEBUG) & DEBUG_PRINT */
#endif
diff --git a/core/net/uip-ds6.c b/core/net/uip-ds6.c
index 7e3cf18..ada9edc 100644
--- a/core/net/uip-ds6.c
+++ b/core/net/uip-ds6.c
@@ -10,6 +10,7 @@
*
and auto configuration (RFC 4862 )state machines
* \author Mathilde Durvy <mdurvy@cisco.com>
* \author Julien Abeille <jabeille@cisco.com>
+ * \author Matthias Philipp <matthias-philipp@gmx.de> (Source routing
header)
*/

/*
* Copyright (c) 2006, Swedish Institute of Computer Science.
@@ -43,6 +44,7 @@
#include <string.h>
#include <stdlib.h>
#include "lib/random.h"
+#include "lib/memb.h"
#include "net/uip-nd6.h"
#include "net/uip-ds6.h"
#include "net/uip-packetqueue.h"
@@ -77,6 +79,8 @@ uip_ds6_nbr_t uip_ds6_nbr_cache[UIP_DS6_NBR_NB];
/** \brief Nei
uip_ds6_defrt_t uip_ds6_defrt_list[UIP_DS6_DEFRT_NB];
/**
\brief Default rt list */
uip_ds6_prefix_t uip_ds6_prefix_list[UIP_DS6_PREFIX_NB];
/**
\brief Prefix list */
uip_ds6_route_t uip_ds6_routing_table[UIP_DS6_ROUTE_NB];
/**
\brief Routing table */
+uip_ds6_src_route_t uip_ds6_src_routing_table[UIP_DS6_SRC_ROUTE_NB]; /**
\brief Source routing table */
+MEMB(src_route_addr_memb, struct uip_ds6_src_route_addr,
UIP_DS6_SRC_ROUTE_ADDR_NB);
/** @} */
@@ -92,6 +96,7 @@ static uip_ds6_prefix_t *locprefix;
static uip_ds6_nbr_t *locnbr;
static uip_ds6_defrt_t *locdefrt;
static uip_ds6_route_t *locroute;
+static uip_ds6_src_route_t *locsrcroute;
/*--------------------------------------------------------------------------*/
void
@@ -106,6 +111,8 @@ uip_ds6_init(void)
memset(uip_ds6_prefix_list, 0, sizeof(uip_ds6_prefix_list));
memset(&uip_ds6_if, 0, sizeof(uip_ds6_if));
memset(uip_ds6_routing_table, 0, sizeof(uip_ds6_routing_table));
+ memset(uip_ds6_src_routing_table, 0,
sizeof(uip_ds6_src_routing_table));
+ memb_init(&src_route_addr_memb);
/* Set interface parameters */
uip_ds6_if.link_mtu = UIP_LINK_MTU;
@@ -802,7 +809,96 @@ uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
}
ANNOTATE("#L %u 0\n",nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
}
+/*--------------------------------------------------------------------------*/
+uip_ds6_src_route_t *
+uip_ds6_src_route_add(uip_ipaddr_t *ipaddr)
+{

+ uint8_t state;
+ state = (uip_ds6_list_loop
+
((uip_ds6_element_t *) uip_ds6_src_routing_table,
UIP_DS6_SRC_ROUTE_NB,
+
sizeof(uip_ds6_src_route_t), ipaddr, 128,
+
(uip_ds6_element_t **) & locsrcroute));
+ if(state == FREESPACE) {
+
locsrcroute->isused = 1;
+
uip_ipaddr_copy(&(locsrcroute->ipaddr), ipaddr);
+
LIST_STRUCT_INIT(locsrcroute, addr_list);
+
+
PRINTF("DS6: adding source route: ");
+
PRINT6ADDR(ipaddr);
+
PRINTF("\n");
+ } else if(state == FOUND) {
+
/* Like all the other DS6 routines we only allow for one route to
each
+
* destination. We need to clear the hop-list if the route was
found. */
+
uip_ds6_src_route_rm(locsrcroute);
+
locsrcroute->isused = 1;
+ }
+ return locsrcroute;
+}
+/*--------------------------------------------------------------------------*/
+uip_ds6_src_route_addr_t *
+uip_ds6_src_route_hop_add(uip_ds6_src_route_t *route, uip_ipaddr_t *hop,
u8_t push)
+{
+ uip_ds6_src_route_addr_t *a;
+
+ a = memb_alloc(&src_route_addr_memb);
+ if (a == NULL) {
+
return NULL;
+ }
+ uip_ipaddr_copy(&a->addr, hop);
+ if(push) {
+
list_push(route->addr_list, a);
+ } else {
+
list_add(route->addr_list, a);
+ }
+ return a;
+}
+/*--------------------------------------------------------------------------*/
+void
+uip_ds6_src_route_rm(uip_ds6_src_route_t *route)
+{
+ uip_ds6_src_route_addr_t *a;
+
+ /* Free memory allocated by source route addresses */

+ for(a = list_pop(route->addr_list); a != NULL; a = list_pop(route>addr_list)) {


+
memb_free(&src_route_addr_memb, a);
+ }
+
+ route->isused = 0;
+ PRINTF("DS6: removed source route to ");
+ PRINT6ADDR(&route->ipaddr);
+ PRINTF("\n");
+}
+/*--------------------------------------------------------------------------*/
+uip_ds6_src_route_t *
+uip_ds6_src_route_lookup(uip_ipaddr_t * destipaddr)
+{
+ uip_ds6_src_route_t *locsrcrt = NULL;
+
+ PRINTF("DS6: Looking up source route for ");
+ PRINT6ADDR(destipaddr);
+ PRINTF("\n");
+
+ for(locsrcroute = uip_ds6_src_routing_table;
+
locsrcroute < uip_ds6_src_routing_table + UIP_DS6_SRC_ROUTE_NB;
locsrcroute++) {
+
if((locsrcroute->isused) && (uip_ipaddr_cmp(destipaddr,
&locsrcroute->ipaddr))) {
+
locsrcrt = locsrcroute;
+
break;
+
}
+ }
+
+ if(locsrcrt != NULL) {
+
PRINTF("DS6: Found source route: ");
+
PRINT6ADDR(destipaddr);
+
PRINTF(" via ");
+
PRINT6ADDR(&((uip_ds6_src_route_addr_t *)list_head(locsrcroute>addr_list))->addr);
+
PRINTF("\n");
+ } else {
+
PRINTF("DS6: No source route found.\n");
+ }
+
+ return locsrcrt;
+}
/*--------------------------------------------------------------------------*/
void
uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
diff --git a/core/net/uip-ds6.h b/core/net/uip-ds6.h
index 064587a..417eff9 100644
--- a/core/net/uip-ds6.h
+++ b/core/net/uip-ds6.h
@@ -44,6 +44,7 @@

#include "net/uip.h"
#include "sys/stimer.h"
+#include "lib/list.h"
/*--------------------------------------------------*/
/** Configuration. For all tables (Neighbor cache, Prefix List, Routing
Table,
@@ -89,6 +90,24 @@
#endif
#define UIP_DS6_ROUTE_NB UIP_DS6_ROUTE_NBS + UIP_DS6_ROUTE_NBU
+/* Source routing table */
+#define UIP_DS6_SRC_ROUTE_NBS 0
+#ifndef UIP_CONF_DS6_SRC_ROUTE_NBU
+#define UIP_DS6_SRC_ROUTE_NBU 3
+#else
+#define UIP_DS6_SRC_ROUTE_NBU UIP_CONF_DS6_SRC_ROUTE_NBU
+#endif
+#define UIP_DS6_SRC_ROUTE_NB UIP_DS6_SRC_ROUTE_NBS +
UIP_DS6_SRC_ROUTE_NBU
+
+/* Total number of source route addresses */
+#define UIP_DS6_SRC_ROUTE_ADDR_NBS 0
+#ifndef UIP_CONF_DS6_SRC_ROUTE_ADDR_NBU
+#define UIP_DS6_SRC_ROUTE_ADDR_NBU 8
+#else
+#define UIP_DS6_SRC_ROUTE_ADDR_NBU UIP_CONF_DS6_SRC_ROUTE_ADDR_NBU
+#endif
+#define UIP_DS6_SRC_ROUTE_ADDR_NB UIP_DS6_SRC_ROUTE_ADDR_NBS +
UIP_DS6_SRC_ROUTE_ADDR_NBU
+
/* Unicast address list*/
#define UIP_DS6_ADDR_NBS 1
#ifndef UIP_CONF_DS6_ADDR_NBU
@@ -168,7 +187,7 @@ typedef struct uip_ds6_nbr {
uint8_t state;
#if UIP_CONF_IPV6_QUEUE_PKT
struct uip_packetqueue_handle packethandle;
-#define UIP_DS6_NBR_PACKET_LIFETIME CLOCK_SECOND * 4
+#define UIP_DS6_NBR_PACKET_LIFETIME CLOCK_SECOND * 15
#endif
/*UIP_CONF_QUEUE_PKT */
} uip_ds6_nbr_t;
@@ -235,6 +254,10 @@ typedef struct rpl_route_entry {
uint32_t saved_lifetime;
void *dag;
uint8_t learned_from;
+#if WITH_RPL_P2P
+ uint8_t instance;
+ uip_ipaddr_t dodagid;
+#endif /* WITH_RPL_P2P */
} rpl_route_entry_t;
#endif /* UIP_DS6_ROUTE_STATE_TYPE */

@@ -245,7 +268,21 @@ typedef struct rpl_route_entry {


#endif /* UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED */
#endif /* UIP_CONF_IPV6_RPL */
+/** \brief An entry in the source routing table */
+typedef struct uip_ds6_src_route {
+ uint8_t isused;
+ uip_ipaddr_t ipaddr;
+ LIST_STRUCT(addr_list);
+#ifdef UIP_DS6_ROUTE_STATE_TYPE
+ UIP_DS6_ROUTE_STATE_TYPE state;
+#endif
+} uip_ds6_src_route_t;
+/** \brief An item in the source route address list */
+typedef struct uip_ds6_src_route_addr {
+ struct uip_ds6_src_route_addr *next;
+ uip_ipaddr_t addr;
+} uip_ds6_src_route_addr_t;
/** \brief An entry in the routing table */
typedef struct uip_ds6_route {
@@ -379,6 +416,17 @@ void uip_ds6_route_rm_by_nexthop(uip_ipaddr_t
*nexthop);
/** @} */
+/** \name Source routing table basic routines */
+/** @{ */
+uip_ds6_src_route_t * uip_ds6_src_route_lookup(uip_ipaddr_t *
destipaddr);
+uip_ds6_src_route_t * uip_ds6_src_route_add(uip_ipaddr_t *ipaddr);
+uip_ds6_src_route_addr_t * uip_ds6_src_route_hop_add(uip_ds6_src_route_t
*route,
+
uip_ipaddr_t *hop,
+
u8_t push);
+void uip_ds6_src_route_rm(uip_ds6_src_route_t *route);
+
+/** @} */
+
/** \brief set the last 64 bits of an IP address based on the MAC
address */
void uip_ds6_set_addr_iid(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr);
diff --git a/core/net/uip-nd6.c b/core/net/uip-nd6.c
index 1874cec..4668ea7 100644
--- a/core/net/uip-nd6.c
+++ b/core/net/uip-nd6.c
@@ -154,6 +154,8 @@ create_llao(uint8_t *llao, uint8_t type) {
void
uip_nd6_ns_input(void)
{
+ u8_t flags;

+
PRINTF("Received NS from");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("to");
@@ -163,8 +165,6 @@ uip_nd6_ns_input(void)
PRINTF("\n");
UIP_STAT(++uip_stat.nd6.recv);
-

u8_t flags;

#if UIP_CONF_IPV6_CHECKS
if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) ||
(uip_is_addr_mcast(&UIP_ND6_NS_BUF->tgtipaddr)) ||
@@ -388,6 +388,11 @@ uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t *
dest, uip_ipaddr_t * tgt)
void
uip_nd6_na_input(void)
{
+ u8_t is_llchange;
+ u8_t is_router;
+ u8_t is_solicited;
+ u8_t is_override;
+
PRINTF("Received NA from");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("to");
@@ -401,11 +406,11 @@ uip_nd6_na_input(void)
* booleans. the three last one are not 0 or 1 but 0 or 0x80, 0x40,
0x20
* but it works. Be careful though, do not use tests such as is_router
== 1
*/
- u8_t is_llchange = 0;
- u8_t is_router = ((UIP_ND6_NA_BUF->flagsreserved &
UIP_ND6_NA_FLAG_ROUTER));
- u8_t is_solicited =
+ is_llchange = 0;
+ is_router = ((UIP_ND6_NA_BUF->flagsreserved &
UIP_ND6_NA_FLAG_ROUTER));
+ is_solicited =
((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_SOLICITED));
- u8_t is_override =
+ is_override =
((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_OVERRIDE));
#if UIP_CONF_IPV6_CHECKS
diff --git a/core/net/uip-udp-packet.c b/core/net/uip-udp-packet.c
index 3ef0fb3..eaf3593 100644
--- a/core/net/uip-udp-packet.c
+++ b/core/net/uip-udp-packet.c
@@ -53,6 +53,8 @@ uip_udp_packet_send(struct uip_udp_conn *c, const void
*data, int len)
#if UIP_UDP
if(data != NULL) {

+
*/
+

uip_udp_conn = c;
/* extension header length might still be set from incoming packet

uip_ext_len = 0;
uip_slen = len;
memcpy(&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN], data,
len > UIP_BUFSIZE? UIP_BUFSIZE: len);
diff --git a/core/net/uip.h b/core/net/uip.h
index 449b084..c646c6f 100644
--- a/core/net/uip.h
+++ b/core/net/uip.h
@@ -1745,6 +1745,10 @@ typedef struct uip_routing_hdr {
u8_t len;
u8_t routing_type;
u8_t seg_left;
+ u8_t cmpr;
+ u8_t pad;
+ u16_t rsvd;
+ u8_t addr;
} uip_routing_hdr;
/* fragmentation header */
diff --git a/core/net/uip6.c b/core/net/uip6.c
index 7a054dc..f099c6a 100644
--- a/core/net/uip6.c
+++ b/core/net/uip6.c
@@ -10,6 +10,7 @@
* \author Adam Dunkels <adam@sics.se>
* \author Julien Abeille <jabeille@cisco.com> (IPv6 related code)
* \author Mathilde Durvy <mdurvy@cisco.com> (IPv6 related code)
+ * \author Matthias Philipp <matthias-philipp@gmx.de> (Source routing
header)
*/
/*
* Copyright (c) 2001-2003, Adam Dunkels.
@@ -92,6 +93,7 @@
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
+#define print6addr(addr) printf(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:
%02x%02x:%02x%02x:%02x%02x:%02x%02x \n", ((u8_t *)addr)[0], ((u8_t
*)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4],
((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)
[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t
*)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15])
#endif
#if UIP_CONF_IPV6_RPL
@@ -870,6 +872,13 @@ ext_hdr_options_process(void)
void
uip_process(u8_t flag)
{
+ uint8_t i;
+ uip_ipaddr_t addr_i;

+
+
+
+
+

uint8_t cmpr;
uint8_t ii;
uint8_t il;
uint8_t cmpr_ii;
uip_ipaddr_t addr_ii;
#if UIP_TCP
register struct uip_conn *uip_connr = uip_conn;
#endif /* UIP_TCP */
@@ -1229,14 +1238,83 @@ uip_process(u8_t flag)
*/
PRINTF("Processing Routing header\n");
if(UIP_ROUTING_BUF->seg_left > 0) {
+
if(UIP_ROUTING_BUF->seg_left == 0) {
+
uip_next_hdr = &UIP_EXT_BUF->next;
+
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
+
} else if(UIP_ROUTING_BUF->routing_type == 4) {
+
/* Number of addresses in the routing header */
+
uint8_t n = ((UIP_EXT_BUF->len * 8) - (UIP_ROUTING_BUF->pad >>
4) - 16 + (UIP_ROUTING_BUF->cmpr & 0x0f)) / (16 - (UIP_ROUTING_BUF->cmpr
>> 4)) + 1;
+
if(UIP_ROUTING_BUF->seg_left > n) {
+
uip_icmp6_error_output(ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER, UIP_IPH_LEN + uip_ext_len + 3);
+
UIP_STAT(++uip_stat.ip.drop);
+
UIP_LOG("ip6: segments left greater than number of
addresses");
+
goto send;
+
}
+
UIP_ROUTING_BUF->seg_left--;
+
/* Index of the next address to be visited */
+
i = n - UIP_ROUTING_BUF->seg_left;
+
/* Next address to be visited */
+
/* Compression value for the address */
+
cmpr = (i == n ? UIP_ROUTING_BUF->cmpr & 0x0f :
UIP_ROUTING_BUF->cmpr >> 4);
+
/* Copy common prefix octets from IPv6 destination address */
+
memcpy(&addr_i, &UIP_IP_BUF->destipaddr, cmpr);
+
/* Copy remaining octets from the address in the RH4 address
vector (index starts at 1 !) */
+
memcpy(((uint8_t *)&addr_i) + cmpr, &UIP_ROUTING_BUF->addr +
((i - 1) * (16 - (UIP_ROUTING_BUF->cmpr >> 4))), 16 - cmpr);
+
if(uip_is_addr_mcast(&addr_i) ||
uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
+
UIP_STAT(++uip_stat.ip.drop);
+
UIP_LOG("ip6: multicast address in source route");
+
goto drop;
+
}
+
/* Check if two entries are assigned to local interfaces and
are
+
* separated by an address not assigned to a local interface
*/
+
il = 0;
+
for (ii = 1; ii <= n; ii++) {

+
/* Decompress address at index ii */
+
cmpr_ii = (ii == n ? UIP_ROUTING_BUF->cmpr & 0x0f :
UIP_ROUTING_BUF->cmpr >> 4);
+
memcpy(&addr_ii, &UIP_IP_BUF->destipaddr, cmpr_ii);
+
memcpy(((uint8_t *)&addr_ii) + cmpr_ii, &UIP_ROUTING_BUF>addr + ((ii - 1) * (16 - (UIP_ROUTING_BUF->cmpr >> 4))), 16 - cmpr_ii);
+
if(uip_ds6_is_my_addr(&addr_ii)) {
+
if(il > 0 && ii > il + 1) {
+
UIP_STAT(++uip_stat.ip.drop);
+
UIP_LOG("ip6: detected loop in source routing header");
+
goto drop;
+
}
+
il = ii;
+
}
+
}
+
/* Check if next hop is onlink */
+
if(i < n && !uip_ds6_is_addr_onlink(&addr_i)) {
+
uip_icmp6_error_output(ICMP6_DST_UNREACH, 7, 0);
+
UIP_STAT(++uip_stat.ip.drop);
+
UIP_LOG("ip6: next address in RH4 is not onlink");
+
goto send;
+
}
+
/* Check hop limit */
+
if(UIP_IP_BUF->ttl <= 1) {
+
uip_icmp6_error_output(ICMP6_TIME_EXCEEDED,
ICMP6_TIME_EXCEED_TRANSIT, 0);
+
UIP_STAT(++uip_stat.ip.drop);
+
UIP_LOG("ip6: hop limit exceeded upon RH4 forwarding");
+
goto send;
+
}
+
UIP_IP_BUF->ttl--;
+
/* Swap IPv6 destination address and address[i] */
+
memcpy(&addr_ii, &UIP_IP_BUF->destipaddr, 16);
+
memcpy(&UIP_IP_BUF->destipaddr, &addr_i, 16);
+
memcpy(&UIP_ROUTING_BUF->addr + ((i - 1) * (16 (UIP_ROUTING_BUF->cmpr >> 4))), (uint8_t *)&addr_ii + cmpr, 16 - cmpr);
+
/* If we also own the address of the next hop, process the
packet
+
* again right away without sending it. */
+
if (uip_ds6_is_my_addr(&UIP_IP_BUF->destipaddr)) {
+
uip_process(flag);
+
return;
+
}
+
PRINTF("Forwarding RH4\n");
+
goto send;
+
} else {
uip_icmp6_error_output(ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER, UIP_IPH_LEN + uip_ext_len + 2);
UIP_STAT(++uip_stat.ip.drop);
UIP_LOG("ip6: unrecognized routing type");
goto send;
}
uip_next_hdr = &UIP_EXT_BUF->next;
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;

break;
case UIP_PROTO_FRAG:
/* Fragmentation header:call the reassembly function, then leave
*/
@@ -1428,7 +1506,10 @@ uip_process(u8_t flag)
uip_conn = NULL;
uip_flags = UIP_NEWDATA;
- uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
+ uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN +
uip_ext_len];
+ /* uip_datalen() is defined as uip_len, therefore we need to substract
the
+
* extension header length */
+ uip_len -= uip_ext_len;
uip_slen = 0;
UIP_UDP_APPCALL();
diff --git a/core/net/uipopt.h b/core/net/uipopt.h
index b409bbd..de9435f 100644
--- a/core/net/uipopt.h
+++ b/core/net/uipopt.h
@@ -678,6 +678,34 @@ void uip_log(char *msg);
*/
/** @} */
+/**
+ * Routing Header 4 compression (CmprI).
+ *
+ * Number of prefix octets that are shared with the IPv6 destination
address.
+ * (For addresses 1..N-1 in the adress vector.)
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_RH4_CMPRI
+#define UIP_RH4_CMPRI 0
+#else /* UIP_CONF_RH4_CMPRI */
+#define UIP_RH4_CMPRI (UIP_CONF_RH4_CMPRI)
+#endif /* UIP_CONF_RH4_CMPRI */
+
+/**
+ * Routing Header 4 compression (CmprE).
+ *
+ * Number of prefix octets that are shared with the IPv6 destination
address.
+ * (For address N in the adress vector.)
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_RH4_CMPRE
+#define UIP_RH4_CMPRE 0
+#else /* UIP_CONF_RH4_CMPRE */
+#define UIP_RH4_CMPRE (UIP_CONF_RH4_CMPRE)

+#endif /* UIP_CONF_RH4_CMPRE */
+
#endif /* __UIPOPT_H__ */
/** @} */
/** @} */
diff --git a/examples/ipv6/rh4/Makefile b/examples/ipv6/rh4/Makefile
new file mode 100644
index 0000000..e4dc39c
--- /dev/null
+++ b/examples/ipv6/rh4/Makefile
@@ -0,0 +1,29 @@
+CONTIKI = $(HIPTBDIR)/support/contiki-wsn430
+TARGET = sky
+
+WITH_UIP6=1
+UIP_CONF_IPV6=1
+SMALL=1
+
+# Disable RPL
+CFLAGS += -DUIP_CONF_IPV6_RPL=0
+# Queue and retransmit packets that are sent before neighbor discovery
has finished
+CFLAGS += -DUIP_CONF_IPV6_QUEUE_PKT=1
+# Generate simple link-local addresses fe80::<node-id>
+CFLAGS += -DIEEE_802154_MAC_ADDRESS={2,0,0,0,0,0,0,0}
+# All addresses use the same scheme, we can compress them down to one
byte
+CFLAGS += -DUIP_CONF_RH4_CMPRI=15
+CFLAGS += -DUIP_CONF_RH4_CMPRE=15
+# Maximum number of entries in the source route table
+CFLAGS += -DUIP_CONF_DS6_SRC_ROUTE_NBU=4
+# Maximum number of hops of all source routes in total
+CFLAGS += -DUIP_CONF_DS6_SRC_ROUTE_ADDR_NBU=10
+# The UDP checksum incorporates the IPv6 destination address. Since RH4
changes
+# this field, checksum verification will always fail and is thus
disabled.
+# XXX This is already defined in platform/sky/contiki-conf.h and thus
needs to
+#
be changed there.
+#CFLAGS += -DUIP_CONF_UDP_CHECKSUMS=0
+
+all: rh4-sim
+
+include $(CONTIKI)/Makefile.include
diff --git a/examples/ipv6/rh4/rh4-sim.c b/examples/ipv6/rh4/rh4-sim.c
new file mode 100644
index 0000000..26ec366
--- /dev/null
+++ b/examples/ipv6/rh4/rh4-sim.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2011, Institut National de Recherche en Informatique et
en

+ * Automatique (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.
+ */
+/**
+ * \file
+ *
Example how to use the IPv6 Routing Header for Source Routes with
RPL
+ *
draft-ietf-6man-rpl-routing-header-03
+ *
+ * Generation of IPv6 addresses from node IDs is hard-coded and requires
+ * the mac address to be 02:00:00:00:00:00:00:<node-id> this can be
achieved by
+ * setting '#define IEEE_802154_MAC_ADDRESS {2,0,0,0,0,0,0,0}' in
+ * platform/xxx/contiki-conf.h or via CFLAGS in the Makefile
+ *
+ * \author Matthias Philipp <matthias-philipp@gmx.de>
+ *
+ */

+
+#include "contiki.h"
+#include "lib/random.h"
+#include "sys/ctimer.h"
+#include "net/uip.h"
+#include "net/uip-ds6.h"
+#include "net/uip-udp-packet.h"
+#include "sys/ctimer.h"
+#include "dev/button-sensor.h"
+
+#include "net/netstack.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define UDP_CLIENT_PORT 0xcccc
+#define UDP_SERVER_PORT 0xbbbb
+
+#define DEBUG DEBUG_FULL
+#include "net/uip-debug.h"
+
+#define SEND_INTERVAL
(60 * CLOCK_SECOND)
+#define SEND_TIME
(random_rand() % (SEND_INTERVAL))
+#define MAX_PAYLOAD_LEN
30
+
+#define UIP_IP_BUF
((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+#define NUM_NODES 5
+#define MAX_PINGS 3
+
+static struct uip_udp_conn *out_conn;
+static struct uip_udp_conn *in_conn;
+static uip_ipaddr_t remote_ipaddr;
+static uip_ipaddr_t own_ipaddr;
+static uint8_t pings_sent = 0;
+static struct ctimer color_timer;
+static uint8_t recv_seq;
+static struct ctimer pong_timer;
+/*--------------------------------------------------------------------------*/
+PROCESS(udp_client_process, "UDP client process");
+AUTOSTART_PROCESSES(&udp_client_process);
+/*--------------------------------------------------------------------------*/
+static void
+send_udp_ping()
+{
+ char buf[MAX_PAYLOAD_LEN];
+
+ ANNOTATE("#A S=ping#%u->%u\n", pings_sent, remote_ipaddr.u8[15]);
+ sprintf(buf, "ping %d", pings_sent);
+ PRINTF("Sending '%s' to %d\n", buf, remote_ipaddr.u8[15]);
+ uip_udp_packet_sendto(out_conn, buf, strlen(buf),

+
&remote_ipaddr, UIP_HTONS(UDP_SERVER_PORT));
+}
+/*--------------------------------------------------------------------------*/
+static void
+send_udp_pong(void *ptr)
+{
+ char buf[MAX_PAYLOAD_LEN];
+
+ ANNOTATE("#A S=pong#%u->%u\n", recv_seq, in_conn->ripaddr.u8[15]);
+ sprintf(buf, "pong %d", recv_seq);
+ PRINTF("Sending '%s' to %d\n", buf, in_conn->ripaddr.u8[15]);
+ uip_udp_packet_send(in_conn, buf, strlen(buf));
+ memset(&in_conn->ripaddr, 0, 16);
+}
+/*--------------------------------------------------------------------------*/
+static void
+reset_color(void *ptr)
+{
+ ANNOTATE("#A color=white\n");
+}
+/*--------------------------------------------------------------------------*/
+static void
+tcpip_handler(void)
+{
+ char *str;
+
+ if(uip_newdata()) {
+
str = uip_appdata;
+
str[uip_datalen()] = '\0';
+
if(strncmp(str, "ping", 4) == 0 || strncmp(str, "pong", 4) == 0) {
+
recv_seq = atoi(&str[4]);
+
PRINTF("Received '%s' from %d\n", str, UIP_IP_BUF>srcipaddr.u8[15]);
+
str[4] = 0;
+
ANNOTATE("#A color=red\n");
+
ANNOTATE("#A R=%s#%u<-%u\n", str, recv_seq, UIP_IP_BUF>srcipaddr.u8[15]);
+
ctimer_set(&color_timer, CLOCK_SECOND*4, reset_color, NULL);
+
if(strncmp(str, "ping", 4) == 0) {
+
uip_ipaddr_copy(&in_conn->ripaddr, &UIP_IP_BUF->srcipaddr);
+
in_conn->rport = UIP_HTONS(UDP_CLIENT_PORT);
+
ctimer_set(&pong_timer, CLOCK_SECOND*4, send_udp_pong, NULL);
+
}
+
}
+ }
+}
+/*--------------------------------------------------------------------------*/
+static void
+print_local_addresses(void)
+{

+ int i;
+ uint8_t state;
+
+ PRINTF("Client 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)) {
+
PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
+
PRINTF("\n");
+
/* hack to make address "final" */
+
if (state == ADDR_TENTATIVE) {
+
uip_ds6_if.addr_list[i].state = ADDR_PREFERRED;
+
}
+
}
+ }
+}
+/*--------------------------------------------------------------------------*/
+static void
+set_global_address(void)
+{
+ uip_ip6addr(&own_ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
+ uip_ds6_set_addr_iid(&own_ipaddr, &uip_lladdr);
+ uip_ds6_addr_add(&own_ipaddr, 0, ADDR_AUTOCONF);
+ /* Initialize server address */
+ uip_ipaddr_copy(&remote_ipaddr, &own_ipaddr);
+}
+/*--------------------------------------------------------------------------*/
+static void
+set_server_address(void)
+{
+ uint8_t target_id;
+
+ /* Omit own address and the current server */
+ do {
+
target_id = (random_rand() % NUM_NODES) + 1;
+ } while(target_id == remote_ipaddr.u8[15] ||\
+
target_id == own_ipaddr.u8[15]);
+ remote_ipaddr.u8[15] = target_id;
+ PRINTF("Set server to node %d (", target_id);
+ PRINT6ADDR(&remote_ipaddr);
+ PRINTF(")\n");
+ /* Make sure the connection is only created once. */
+ if(out_conn == NULL) {
+
out_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL);
+ }
+ udp_bind(out_conn, UIP_HTONS(UDP_CLIENT_PORT));
+}
+/*--------------------------------------------------------------------------*/
+static void
+set_routes(void)

+{
+ uip_ds6_src_route_t *srcrt;
+ uip_ipaddr_t ip;
+
+ uint8_t target;
+ uint8_t i;
+ int add;
+
+ /* Generate static routes for simple chain topology */
+ for(target = 1; target <= NUM_NODES; target++) {
+
if(target == own_ipaddr.u8[15]) {
+
continue;
+
}
+
if(target < own_ipaddr.u8[15]) {
+
add = -1;
+
} else {
+
add = 1;
+
}
+
uip_ipaddr_copy(&ip, &own_ipaddr);
+
ip.u8[15] = target;
+
/* Create source route to target */
+
if((srcrt = uip_ds6_src_route_add(&ip)) == NULL) {
+
PRINTF("ERROR: No memory to store source route\n");
+
return;
+
}
+
PRINTF("Source route to ");
+
PRINT6ADDR(&ip);
+
PRINTF(" is: ");
+
/* Add intermediate hops */
+
for(i = own_ipaddr.u8[15] + add; i != target; i += add) {
+
ip.u8[15] = i;
+
uip_create_linklocal_prefix(&ip);
+
if(uip_ds6_src_route_hop_add(srcrt, &ip, 0) == NULL) {
+
PRINTF("ERROR: No memory to store source route hop\n");
+
return;
+
}
+
PRINT6ADDR(&ip);
+
PRINTF(" - ");
+
}
+
/* Since neighbor discovery does not work, we need to add the linklocal
+
* address of the target as last hop. */
+
ip.u8[15] = target;
+
uip_create_linklocal_prefix(&ip);
+
if(uip_ds6_src_route_hop_add(srcrt, &ip, 0) == NULL) {
+
PRINTF("ERROR: No memory to store source route hop\n");
+
return;
+
}
+
PRINT6ADDR(&ip);
+
PRINTF("\n");
+ }
+}
+/*--------------------------------------------------------------------------*/

+PROCESS_THREAD(udp_client_process, ev, data)


+{
+ PROCESS_BEGIN();
+
+ PROCESS_PAUSE();
+ SENSORS_ACTIVATE(button_sensor);
+
+ set_global_address();
+ print_local_addresses();
+ set_server_address();
+ set_routes();
+ /* The data sink runs with a 100% duty cycle in order to ensure high
+
packet reception rates. */
+ NETSTACK_MAC.off(1);
+
+ in_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL);
+ udp_bind(in_conn, UIP_HTONS(UDP_SERVER_PORT));
+
+ PRINTF("Listening for connections on ");
+ PRINT6ADDR(&in_conn->ripaddr);
+ PRINTF(" local/remote port %u/%u\n",
+
UIP_HTONS(in_conn->lport), UIP_HTONS(in_conn->rport));
+
+ while(1) {
+
PROCESS_YIELD();
+
if(ev == tcpip_event) {
+
tcpip_handler();
+
} else if(ev == sensors_event && data == &button_sensor) {
+
if(pings_sent >= MAX_PINGS) {
+
set_server_address();
+
pings_sent = 0;
+
}
+
pings_sent++;
+
send_udp_ping();
+
}
+ }
+
+ PROCESS_END();
+}
+/*--------------------------------------------------------------------------*/
diff --git a/examples/ipv6/rh4/rh4-sim.csc b/examples/ipv6/rh4/rh4sim.csc
new file mode 100644
index 0000000..169a8f8
--- /dev/null
+++ b/examples/ipv6/rh4/rh4-sim.csc
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simconf>
+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>

+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/collectview</project>
+ <simulation>
+
<title>RH4 Example</title>
+
<delaytime>-13</delaytime>
+
<randomseed>123456</randomseed>
+
<motedelay_us>1000000</motedelay_us>
+
<radiomedium>
+
se.sics.cooja.radiomediums.UDGMConstantLoss
+
<transmitting_range>50.0</transmitting_range>
+
<interference_range>0.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>
+
se.sics.cooja.mspmote.SkyMoteType
+
<identifier>sky1</identifier>
+
<description>Sky Mote Type #sky1</description>
+
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipv6/rh4/rh4sim.c</source>
+
<commands EXPORT="discard">make rh4-sim.sky TARGET=sky</commands>
+
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rh4/rh4sim.sky</firmware>
+
<moteinterface>se.sics.cooja.interfaces.Position</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.RimeAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.IPAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.Mote2MoteRelations</moteinterface
>
+
<moteinterface>se.sics.cooja.interfaces.MoteAttributes</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspClock</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspMoteID</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</mote
interface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterfa
ce>

+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinter
face>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyTemperature</moteinter
face>
+
</motetype>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>81.16180768000919</x>
+
<y>32.815575039438514</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>1</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>114.78702180352792</x>
+
<y>11.578597698268785</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>2</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>140.1890688061851</x>
+
<y>37.0118805839431</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>3</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>

+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>141.38031124891998</x>
+
<y>76.7199620084384</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>4</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>117.15838157997784</x>
+
<y>104.91269981983007</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>5</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+ </simulation>
+ <plugin>
+
se.sics.cooja.plugins.SimControl
+
<width>318</width>
+
<z>0</z>
+
<height>192</height>
+
<location_x>0</location_x>
+
<location_y>0</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.Visualizer
+
<plugin_config>
+
<skin>se.sics.cooja.plugins.skins.IDVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.UDGMVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.AttributeVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.TrafficVisualizerSkin</skin>
+
<viewport>4.52041731070154 0.0 0.0 4.52041731070154
-213.8852404045427 -34.34009346890323</viewport>
+
</plugin_config>
+
<width>581</width>
+
<z>1</z>
+
<height>521</height>
+
<location_x>637</location_x>
+
<location_y>4</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

<mote_arg>4</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>685</width>
<z>2</z>
<height>542</height>
<location_x>1223</location_x>
<location_y>566</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>1</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>617</width>
<z>6</z>
<height>446</height>
<location_x>2</location_x>
<location_y>665</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>0</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>620</width>
<z>5</z>
<height>460</height>
<location_x>-3</location_x>
<location_y>197</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>2</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>597</width>
<z>4</z>
<height>542</height>
<location_x>622</location_x>
<location_y>564</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>3</mote_arg>
<plugin_config>

+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>692</width>
+
<z>3</z>
+
<height>553</height>
+
<location_x>1223</location_x>
+
<location_y>5</location_y>
+ </plugin>
+</simconf>
+
diff --git a/examples/ipv6/rpl-p2p/Makefile b/examples/ipv6/rplp2p/Makefile
new file mode 100644
index 0000000..0bb60e9
--- /dev/null
+++ b/examples/ipv6/rpl-p2p/Makefile
@@ -0,0 +1,20 @@
+CONTIKI=../../..
+TARGET = sky
+
+WITH_UIP6=1
+UIP_CONF_IPV6=1
+CFLAGS += -DSENSLAB
+WITH_RPL_P2P=1
+SMALL=1
+
+ifdef WITH_RPL_P2P
+CFLAGS += -DWITH_RPL_P2P
+CFLAGS += -DWITH_RPL_P2P_MEASUREMENT
+CFLAGS += -DUIP_CONF_DS6_ROUTE_NBU=8
+endif
+
+CFLAGS += -DRPL_CONF_MOP=2
+
+all: p2p-sim
+
+include $(CONTIKI)/Makefile.include
diff --git a/examples/ipv6/rpl-p2p/p2p-sim-large.csc b/examples/ipv6/rplp2p/p2p-sim-large.csc
new file mode 100644
index 0000000..c94c7d6
--- /dev/null
+++ b/examples/ipv6/rpl-p2p/p2p-sim-large.csc
@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simconf>
+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>

+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/collectview</project>
+ <simulation>
+
<title>P2P-RPL v06 large</title>
+
<delaytime>24</delaytime>
+
<randomseed>123456</randomseed>
+
<motedelay_us>1000000</motedelay_us>
+
<radiomedium>
+
se.sics.cooja.radiomediums.UDGM
+
<transmitting_range>40.0</transmitting_range>
+
<interference_range>80.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>
+
se.sics.cooja.mspmote.SkyMoteType
+
<identifier>sky1</identifier>
+
<description>Sky Mote Type #sky1</description>
+
<source EXPORT="discard">[CONFIG_DIR]/p2p-sim.c</source>
+
<commands EXPORT="discard">make p2p-sim.sky TARGET=sky</commands>
+
<firmware EXPORT="copy">[CONFIG_DIR]/p2p-sim.sky</firmware>
+
<moteinterface>se.sics.cooja.interfaces.Position</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.RimeAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.IPAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.Mote2MoteRelations</moteinterface
>
+
<moteinterface>se.sics.cooja.interfaces.MoteAttributes</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspClock</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspMoteID</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</mote
interface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterfa
ce>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinter
face>

+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyTemperature</moteinter
face>
+
</motetype>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>81.60638132921417</x>
+
<y>129.99652346297373</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>1</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>106.17180394876435</x>
+
<y>50.949639409722344</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>2</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>127.88979821860876</x>
+
<y>44.67537219677969</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>3</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>72.1058882544568</x>
+
<y>105.10818212072152</y>
+
<z>0.0</z>
+
</interface_config>

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>4</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>118.45812790493001</x>
<y>88.61912379901209</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>5</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>1.8948735798606842</x>
<y>147.7507940585003</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>6</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>87.55556477809392</x>
<y>13.328713330922797</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>7</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>6.723515513676576</x>
<y>21.073132448196258</y>

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>8</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>36.38055343458657</x>
<y>77.15254822362894</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>9</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>-1.794939868458505</x>
<y>90.55868940826029</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>10</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>90.93607851114463</x>
<y>73.11752990201795</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>11</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

<x>37.573458599648205</x>
<y>141.3908095586603</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>12</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>59.6305502789489</x>
<y>67.43202009551744</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>13</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>32.98900117420258</x>
<y>59.51174051409303</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>14</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>129.77226062554453</x>
<y>120.29869541673273</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>15</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

<interface_config>
se.sics.cooja.interfaces.Position
<x>133.99378952377762</x>
<y>68.6978145430918</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>16</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>70.71906785960951</x>
<y>90.8186001014951</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>17</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>44.75463475349834</x>
<y>24.290197758946718</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>18</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>23.117733510821314</x>
<y>115.68917806838304</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>19</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>

+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>39.92981718333251</x>
+
<y>121.11546181525988</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>20</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+ </simulation>
+ <plugin>
+
se.sics.cooja.plugins.SimControl
+
<width>318</width>
+
<z>1</z>
+
<height>192</height>
+
<location_x>0</location_x>
+
<location_y>0</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.Visualizer
+
<plugin_config>
+
<skin>se.sics.cooja.plugins.skins.IDVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.AttributeVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.UDGMVisualizerSkin</skin>
+
<viewport>3.093476173938591 0.0 0.0 3.093476173938591
73.55260371672885 -20.141148027558227</viewport>
+
</plugin_config>
+
<width>581</width>
+
<z>0</z>
+
<height>519</height>
+
<location_x>302</location_x>
+
<location_y>560</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.LogListener
+
<plugin_config>
+
<filter />
+
</plugin_config>
+
<width>700</width>
+
<z>2</z>
+
<height>446</height>
+
<location_x>337</location_x>
+
<location_y>31</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer
+
<mote_arg>7</mote_arg>
+
<plugin_config>
+
<interface>Serial port</interface>

+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>722</width>
+
<z>4</z>
+
<height>339</height>
+
<location_x>1077</location_x>
+
<location_y>41</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer
+
<mote_arg>2</mote_arg>
+
<plugin_config>
+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>725</width>
+
<z>3</z>
+
<height>305</height>
+
<location_x>1077</location_x>
+
<location_y>385</location_y>
+ </plugin>
+</simconf>
+
diff --git a/examples/ipv6/rpl-p2p/p2p-sim-medium.csc
b/examples/ipv6/rpl-p2p/p2p-sim-medium.csc
new file mode 100644
index 0000000..6bebd67
--- /dev/null
+++ b/examples/ipv6/rpl-p2p/p2p-sim-medium.csc
@@ -0,0 +1,262 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simconf>
+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/collectview</project>
+ <simulation>
+
<title>P2P-RPL v06 medium</title>
+
<delaytime>-13</delaytime>
+
<randomseed>123456</randomseed>
+
<motedelay_us>1000000</motedelay_us>
+
<radiomedium>
+
se.sics.cooja.radiomediums.UDGMConstantLoss
+
<transmitting_range>50.0</transmitting_range>
+
<interference_range>0.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>
+
se.sics.cooja.mspmote.SkyMoteType
+
<identifier>sky1</identifier>
+
<description>Sky Mote Type #sky1</description>
+
<source EXPORT="discard">[CONFIG_DIR]/p2p-sim.c</source>
+
<commands EXPORT="discard">make p2p-sim.sky TARGET=sky</commands>
+
<firmware EXPORT="copy">[CONFIG_DIR]/p2p-sim.sky</firmware>
+
<moteinterface>se.sics.cooja.interfaces.Position</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.RimeAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.IPAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.Mote2MoteRelations</moteinterface
>
+
<moteinterface>se.sics.cooja.interfaces.MoteAttributes</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspClock</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspMoteID</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</mote
interface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterfa
ce>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinter
face>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyTemperature</moteinter
face>
+
</motetype>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>111.59925018054851</x>
+
<y>11.598708472266114</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>1</id>

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>72.75550414912952</x>
<y>17.330279061502235</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>2</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>99.96538136750321</x>
<y>44.76137479384649</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>3</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>157.7034135138084</x>
<y>18.878808659295885</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>4</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>69.93798815025724</x>
<y>57.526074589392294</y>
<z>0.0</z>
</interface_config>
<interface_config>

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

se.sics.cooja.mspmote.interfaces.MspMoteID
<id>5</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>106.7919694895167</x>
<y>76.33964548286043</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>6</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>140.29558888884353</x>
<y>59.33011563397143</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>7</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>151.3775553055439</x>
<y>65.51539921538561</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>8</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>192.01474205777868</x>
<y>45.29478832305462</y>
<z>0.0</z>

+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>9</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+ </simulation>
+ <plugin>
+
se.sics.cooja.plugins.SimControl
+
<width>318</width>
+
<z>0</z>
+
<height>192</height>
+
<location_x>10</location_x>
+
<location_y>3</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.Visualizer
+
<plugin_config>
+
<skin>se.sics.cooja.plugins.skins.IDVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.UDGMVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.AttributeVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.TrafficVisualizerSkin</skin>
+
<viewport>4.2521683488090085 0.0 0.0 4.2521683488090085
-271.9335541373579 45.03565733282371</viewport>
+
</plugin_config>
+
<width>581</width>
+
<z>2</z>
+
<height>521</height>
+
<location_x>637</location_x>
+
<location_y>4</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer
+
<mote_arg>0</mote_arg>
+
<plugin_config>
+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>620</width>
+
<z>6</z>
+
<height>384</height>
+
<location_x>8</location_x>
+
<location_y>196</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer
+
<mote_arg>2</mote_arg>
+
<plugin_config>
+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>597</width>
+
<z>5</z>

+
<height>409</height>
+
<location_x>10</location_x>
+
<location_y>581</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer
+
<mote_arg>3</mote_arg>
+
<plugin_config>
+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>692</width>
+
<z>3</z>
+
<height>519</height>
+
<location_x>1223</location_x>
+
<location_y>5</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer
+
<mote_arg>5</mote_arg>
+
<plugin_config>
+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>580</width>
+
<z>4</z>
+
<height>468</height>
+
<location_x>634</location_x>
+
<location_y>528</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer
+
<mote_arg>8</mote_arg>
+
<plugin_config>
+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>697</width>
+
<z>1</z>
+
<height>468</height>
+
<location_x>1220</location_x>
+
<location_y>529</location_y>
+ </plugin>
+</simconf>
+
diff --git a/examples/ipv6/rpl-p2p/p2p-sim-small.csc b/examples/ipv6/rplp2p/p2p-sim-small.csc
new file mode 100644
index 0000000..65c7e28
--- /dev/null
+++ b/examples/ipv6/rpl-p2p/p2p-sim-small.csc
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simconf>

+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
+ <project
EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
+ <project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/collectview</project>
+ <simulation>
+
<title>P2P-RPL v06 small</title>
+
<delaytime>-13</delaytime>
+
<randomseed>123456</randomseed>
+
<motedelay_us>1000000</motedelay_us>
+
<radiomedium>
+
se.sics.cooja.radiomediums.UDGMConstantLoss
+
<transmitting_range>50.0</transmitting_range>
+
<interference_range>0.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>
+
se.sics.cooja.mspmote.SkyMoteType
+
<identifier>sky1</identifier>
+
<description>Sky Mote Type #sky1</description>
+
<source EXPORT="discard">[CONFIG_DIR]/p2p-sim.c</source>
+
<commands EXPORT="discard">make p2p-sim.sky TARGET=sky</commands>
+
<firmware EXPORT="copy">[CONFIG_DIR]/p2p-sim.sky</firmware>
+
<moteinterface>se.sics.cooja.interfaces.Position</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.RimeAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.IPAddress</moteinterface>
+
<moteinterface>se.sics.cooja.interfaces.Mote2MoteRelations</moteinterface
>
+
<moteinterface>se.sics.cooja.interfaces.MoteAttributes</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspClock</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspMoteID</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</mote
interface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterfa
ce>

+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinter
face>
+
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyTemperature</moteinter
face>
+
</motetype>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>111.59925018054851</x>
+
<y>11.598708472266114</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>1</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>80.22986585519722</x>
+
<y>31.45274918451376</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>2</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>140.1890688061851</x>
+
<y>37.0118805839431</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>3</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>

+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>141.38031124891998</x>
+
<y>76.7199620084384</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>4</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+
<mote>
+
<breakpoints />
+
<interface_config>
+
se.sics.cooja.interfaces.Position
+
<x>117.15838157997784</x>
+
<y>104.91269981983007</y>
+
<z>0.0</z>
+
</interface_config>
+
<interface_config>
+
se.sics.cooja.mspmote.interfaces.MspMoteID
+
<id>5</id>
+
</interface_config>
+
<motetype_identifier>sky1</motetype_identifier>
+
</mote>
+ </simulation>
+ <plugin>
+
se.sics.cooja.plugins.SimControl
+
<width>318</width>
+
<z>1</z>
+
<height>192</height>
+
<location_x>0</location_x>
+
<location_y>0</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.Visualizer
+
<plugin_config>
+
<skin>se.sics.cooja.plugins.skins.IDVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.UDGMVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.AttributeVisualizerSkin</skin>
+
<skin>se.sics.cooja.plugins.skins.TrafficVisualizerSkin</skin>
+
<viewport>4.52041731070154 0.0 0.0 4.52041731070154
-215.88524040454277 -47.34009346890323</viewport>
+
</plugin_config>
+
<width>581</width>
+
<z>0</z>
+
<height>521</height>
+
<location_x>637</location_x>
+
<location_y>4</location_y>
+ </plugin>
+ <plugin>
+
se.sics.cooja.plugins.MoteInterfaceViewer

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

<mote_arg>4</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>685</width>
<z>2</z>
<height>542</height>
<location_x>1223</location_x>
<location_y>566</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>1</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>617</width>
<z>6</z>
<height>446</height>
<location_x>2</location_x>
<location_y>665</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>0</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>620</width>
<z>5</z>
<height>460</height>
<location_x>-3</location_x>
<location_y>197</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>2</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>597</width>
<z>4</z>
<height>542</height>
<location_x>622</location_x>
<location_y>564</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.MoteInterfaceViewer
<mote_arg>3</mote_arg>
<plugin_config>

+
<interface>Serial port</interface>
+
<scrollpos>0,0</scrollpos>
+
</plugin_config>
+
<width>692</width>
+
<z>3</z>
+
<height>553</height>
+
<location_x>1223</location_x>
+
<location_y>5</location_y>
+ </plugin>
+</simconf>
+
diff --git a/examples/ipv6/rpl-p2p/p2p-sim.c b/examples/ipv6/rpl-p2p/p2psim.c
new file mode 100644
index 0000000..de92c34
--- /dev/null
+++ b/examples/ipv6/rpl-p2p/p2p-sim.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2011, Institut National de Recherche en Informatique et
en
+ * Automatique (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.
+ */
+/**
+ * \file
+ *
Example how to use the RPL Point to Point (P2P) extension.
+ *
+ * This program has been written for Cooja and Sky motes as it makes
heavy use
+ * of annotations and node attributes to visualize what is going on. But
+ * nevertheless it should run on real nodes as well.
+ *
+ * Make sure to set DEBUG_ANNOTATE in rpl-icmp6.c, rpl-p2p.c, and rpldag.c
+ *
+ * Generation of IPv6 addresses from node IDs is hard-coded and requires
+ * the mac address to be 02:00:00:00:00:00:00:<node-id> this can be
achieved by
+ * seting '#define IEEE_802154_MAC_ADDRESS {2,0,0,0,0,0,0,0}' in
+ * platform/xxx/contiki-conf.h
+ *
+ * \author Matthias Philipp <matthias-philipp@gmx.de>
+ *
+ */
+
+#include "contiki.h"
+#include "lib/random.h"
+#include "sys/ctimer.h"
+#include "net/uip.h"
+#include "net/uip-ds6.h"
+#include "net/uip-udp-packet.h"
+#include "sys/ctimer.h"
+#include "dev/button-sensor.h"
+
+#include "net/netstack.h"
+#include "net/rpl/rpl-p2p.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define UDP_CLIENT_PORT 0xcafe
+#define UDP_SERVER_PORT 0xf00d
+
+#define DEBUG DEBUG_FULL
+#include "net/uip-debug.h"
+
+#define MAX_PAYLOAD_LEN
10
+
+#define UIP_IP_BUF
((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
+

+#define NUM_NODES 9
+#define MAX_PINGS 3
+/* RPL_P2P_STORE_BACKWARD_ROUTES has to be enabled in rpl-p2p.h in oder
to make replies work. */
+#define WITH_UDP_PONG 1
+#define WITH_GLOBAL_DAG 1
+
+static struct uip_udp_conn *out_conn;
+static struct uip_udp_conn *in_conn;
+static uip_ipaddr_t remote_ipaddr;
+static uip_ipaddr_t own_ipaddr;
+static uint8_t pings_sent = 0;
+static struct ctimer color_timer;
+static struct ctimer timeout;
+
+static enum app_state{IDLE, MEASURE_BEFORE, DISCOVER, MEASURE_AFTER,
PING} state = IDLE;
+
+/*--------------------------------------------------------------------------*/
+PROCESS(udp_client_process, "UDP client process");
+AUTOSTART_PROCESSES(&udp_client_process);
+/*--------------------------------------------------------------------------*/
+static void
+send_udp_ping()
+{
+ char buf[MAX_PAYLOAD_LEN];
+
+ ANNOTATE("#A ping=S->%u#%u\n", remote_ipaddr.u8[15], pings_sent);
+ sprintf(buf, "ping %d", pings_sent);
+ PRINTF("Sending '%s' to %d\n", buf, remote_ipaddr.u8[15]);
+ uip_udp_packet_sendto(out_conn, buf, strlen(buf),
+
&remote_ipaddr, UIP_HTONS(UDP_SERVER_PORT));
+}
+/*--------------------------------------------------------------------------*/
+#if WITH_UDP_PONG
+static void
+send_udp_pong(uint8_t seq, uip_ipaddr_t *dest)
+{
+ char buf[MAX_PAYLOAD_LEN];
+
+ ANNOTATE("#A ping=S->%u#%u\n", dest->u8[15], seq);
+ sprintf(buf, "pong %d", seq);
+ PRINTF("Sending '%s' to %d\n", buf, dest->u8[15]);
+ uip_udp_packet_sendto(in_conn, buf, strlen(buf),
+
dest, UIP_HTONS(UDP_CLIENT_PORT));
+}
+#endif /* WITH_UDP_PONG */
+/*--------------------------------------------------------------------------*/
+static void
+reset_color(void *ptr)

+{
+ ANNOTATE("#A color=white\n");
+}
+/*--------------------------------------------------------------------------*/
+static void
+tcpip_handler(void)
+{
+ char *str;
+ uint8_t seq;
+
+ if(uip_newdata()) {
+
str = uip_appdata;
+
str[uip_datalen()] = '\0';
+
if(strncmp(str, "ping", 4) == 0 || strncmp(str, "pong", 4) == 0) {
+
seq = atoi(&str[4]);
+
PRINTF("Received '%s' from %d\n", str, UIP_IP_BUF>srcipaddr.u8[15]);
+
ANNOTATE("#A color=cyan\n");
+
ANNOTATE("#A ping=R<-%u#%u\n", UIP_IP_BUF->srcipaddr.u8[15], seq);
+
ctimer_set(&color_timer, CLOCK_SECOND/8, reset_color, NULL);
+#if WITH_UDP_PONG
+
if(strncmp(str, "ping", 4) == 0) {
+
send_udp_pong(seq, &UIP_IP_BUF->srcipaddr);
+
}
+#endif /* WITH_UDP_PONG */
+
}
+ }
+}
+/*--------------------------------------------------------------------------*/
+static void
+print_local_addresses(void)
+{
+ int i;
+ uint8_t state;
+
+ PRINTF("Client 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)) {
+
PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
+
PRINTF("\n");
+
/* hack to make address "final" */
+
if (state == ADDR_TENTATIVE) {
+
uip_ds6_if.addr_list[i].state = ADDR_PREFERRED;
+
}
+
}
+ }
+}
+/*--------------------------------------------------------------------------*/
+static void

+set_global_address(void)
+{
+ uip_ip6addr(&own_ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
+ uip_ds6_set_addr_iid(&own_ipaddr, &uip_lladdr);
+ uip_ds6_addr_add(&own_ipaddr, 0, ADDR_AUTOCONF);
+ /* Initialize server address */
+ uip_ipaddr_copy(&remote_ipaddr, &own_ipaddr);
+}
+/*--------------------------------------------------------------------------*/
+static void
+set_server_address(void)
+{
+ uint8_t target_id;
+
+ /* Omit own address and the current server */
+ do {
+
target_id = (random_rand() % NUM_NODES) + 1;
+ } while(target_id == remote_ipaddr.u8[15] ||\
+
target_id == own_ipaddr.u8[15]);
+
+ if(own_ipaddr.u8[15] == 2) {
+
target_id = 3;
+ }
+
+ remote_ipaddr.u8[15] = target_id;
+ PRINTF("Set server to node %d (", target_id);
+ PRINT6ADDR(&remote_ipaddr);
+ PRINTF(")\n");
+ /* Make sure the connection is only created once. */
+ if(out_conn == NULL) {
+
out_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL);
+ }
+ udp_bind(out_conn, UIP_HTONS(UDP_CLIENT_PORT));
+}
+/*--------------------------------------------------------------------------*/
+static void
+timed_out(void *ptr)
+{
+ printf("[%d] Operation timed out\n", state);
+ if(state == MEASURE_BEFORE) {
+
PRINTF("[%d] Sending P2P route request for ", state);
+
PRINT6ADDR(&remote_ipaddr);
+
PRINTF("\n");
+
state = DISCOVER;
+
ctimer_set(&timeout, CLOCK_SECOND * 120, timed_out, NULL);
+
rpl_discover_route(&remote_ipaddr);
+ } else {
+
state = IDLE;
+ }
+}
+/*--------------------------------------------------------------------------*/

+PROCESS_THREAD(udp_client_process, ev, data)


+{
+ PROCESS_BEGIN();
+
+ PROCESS_PAUSE();
+ SENSORS_ACTIVATE(button_sensor);
+
+ set_global_address();
+ print_local_addresses();
+ /* The data sink runs with a 100% duty cycle in order to ensure high
+
packet reception rates. */
+ NETSTACK_MAC.off(1);
+
+ in_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL);
+ udp_bind(in_conn, UIP_HTONS(UDP_SERVER_PORT));
+
+ PRINTF("Listening for connections on ");
+ PRINT6ADDR(&in_conn->ripaddr);
+ PRINTF(" local/remote port %u/%u\n",
+
UIP_HTONS(in_conn->lport), UIP_HTONS(in_conn->rport));
+
+#if WITH_GLOBAL_DAG
+ if(own_ipaddr.u8[15] == 1) {
+
rpl_set_root(&own_ipaddr);
+ }
+#endif /* WITH_GLOBAL_DAG */
+
+ state = IDLE;
+ while(1) {
+
PROCESS_YIELD();
+
/* UDP packet received */
+
if(ev == tcpip_event) {
+
tcpip_handler();
+
/* Button pressed */
+
} else if(ev == sensors_event && data == &button_sensor) {
+
if(state == IDLE) {
+
set_server_address();
+
PRINTF("[%d] Measuring route to ", state);
+
PRINT6ADDR(&remote_ipaddr);
+
PRINTF("\n");
+
state = MEASURE_BEFORE;
+#if WITH_GLOBAL_DAG
+
ctimer_set(&timeout, CLOCK_SECOND * 60, timed_out, NULL);
+
mo_output(&remote_ipaddr);
+#else
+
timed_out(NULL);
+#endif /* WITH_GLOBAL_DAG */
+
} else if (state == PING) {
+
if(pings_sent++ < MAX_PINGS) {
+
send_udp_ping();
+
if(pings_sent == MAX_PINGS) {
+
state = IDLE;
+
}
+
}

+
}
+
/* Received reply for P2P route measurement */
+
} else if(ev == rpl_p2p_event_mo) {
+
ctimer_stop(&timeout);
+
printf("[%d] ETX for route to ", state);
+
print6addr(&((rpl_mo_result_t *)data)->target);
+
printf(" is %u.%u\n", ((rpl_mo_result_t *)data)->path_metric /
+
RPL_DAG_MC_ETX_DIVISOR, (((rpl_mo_result_t *)data)>path_metric %
+
RPL_DAG_MC_ETX_DIVISOR * 100) / RPL_DAG_MC_ETX_DIVISOR);
+
if(state == MEASURE_BEFORE) {
+
PRINTF("[%d] Sending P2P route request for ", state);
+
PRINT6ADDR(&remote_ipaddr);
+
PRINTF("\n");
+
state = DISCOVER;
+
ctimer_set(&timeout, CLOCK_SECOND * 60, timed_out, NULL);
+
rpl_discover_route(&remote_ipaddr);
+
} else if(state == MEASURE_AFTER) {
+
pings_sent = 0;
+
state = PING;
+
}
+
/* Received reply for P2P route discovery */
+
} else if(ev == rpl_p2p_event_dro) {
+
ctimer_stop(&timeout);
+
if(state == DISCOVER) {
+
PRINTF("[%d] Measuring route to ", state);
+
PRINT6ADDR(&remote_ipaddr);
+
PRINTF("\n");
+
state = MEASURE_AFTER;
+
ctimer_set(&timeout, CLOCK_SECOND * 60, timed_out, NULL);
+
mo_output(&remote_ipaddr);
+
}
+
}
+ }
+
+ PROCESS_END();
+}
+/*--------------------------------------------------------------------------*/
diff --git a/platform/sky/contiki-conf.h b/platform/sky/contiki-conf.h
index 9794f39..4889557 100644
--- a/platform/sky/contiki-conf.h
+++ b/platform/sky/contiki-conf.h
@@ -10,12 +10,20 @@
#include "platform-conf.h"
#endif /* PLATFORM_CONF_H */
+#define IEEE_802154_MAC_ADDRESS {2,0,0,0,0,0,0,0}
+
+/* The process names are not used to save RAM */
+#define PROCESS_CONF_NO_PROCESS_NAMES 1
+#define UIP_CONF_TCP 0
+#define UIP_CONF_RH4_CMPRI 15
+

#ifndef NETSTACK_CONF_MAC
#define NETSTACK_CONF_MAC
csma_driver
#endif /* NETSTACK_CONF_MAC */
#ifndef NETSTACK_CONF_RDC
-#define NETSTACK_CONF_RDC
contikimac_driver
+//#define NETSTACK_CONF_RDC
contikimac_driver
+#define NETSTACK_CONF_RDC
nullrdc_driver
#endif /* NETSTACK_CONF_RDC */
#ifndef NETSTACK_CONF_RDC_CHANNEL_CHECK_RATE
@@ -138,10 +146,10 @@
/* configure number of neighbors and routes */
#ifndef UIP_CONF_DS6_NBR_NBU
-#define UIP_CONF_DS6_NBR_NBU
30
+#define UIP_CONF_DS6_NBR_NBU
10
#endif /* UIP_CONF_DS6_NBR_NBU */
#ifndef UIP_CONF_DS6_ROUTE_NBU
-#define UIP_CONF_DS6_ROUTE_NBU
30
+#define UIP_CONF_DS6_ROUTE_NBU
3
#endif /* UIP_CONF_DS6_ROUTE_NBU */
#define UIP_CONF_ND6_SEND_RA
@@ -152,12 +160,12 @@
#ifndef UIP_CONF_IPV6_QUEUE_PKT
#define UIP_CONF_IPV6_QUEUE_PKT
#endif /* UIP_CONF_IPV6_QUEUE_PKT */
-#define UIP_CONF_IPV6_CHECKS
+#define UIP_CONF_IPV6_CHECKS
#define UIP_CONF_IPV6_REASSEMBLY
#define UIP_CONF_NETIF_MAX_ADDRESSES
#define UIP_CONF_ND6_MAX_PREFIXES
#define UIP_CONF_ND6_MAX_NEIGHBORS
-#define UIP_CONF_ND6_MAX_DEFROUTERS
+#define UIP_CONF_ND6_MAX_DEFROUTERS
#define UIP_CONF_IP_FORWARD
#ifndef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE
@@ -191,14 +199,14 @@
#ifndef UIP_CONF_TCP_MSS
#define UIP_CONF_TCP_MSS
48
#endif
-#define UIP_CONF_MAX_CONNECTIONS 4
-#define UIP_CONF_MAX_LISTENPORTS 8
-#define UIP_CONF_UDP_CONNS
12
-#define UIP_CONF_FWCACHE_SIZE
30
+#define UIP_CONF_MAX_CONNECTIONS 2
+#define UIP_CONF_MAX_LISTENPORTS 2
+#define UIP_CONF_UDP_CONNS
2
+#define UIP_CONF_FWCACHE_SIZE
5
#define UIP_CONF_BROADCAST
1
#define UIP_ARCH_IPCHKSUM
1
#define UIP_CONF_UDP
1

0
0
1
0
0
3
3
4
2
1
0
240

-#define
+#define
#define
#define

UIP_CONF_UDP_CHECKSUMS
UIP_CONF_UDP_CHECKSUMS
UIP_CONF_PINGADDRCONF
UIP_CONF_LOGGING

1
0
0
0

diff --git a/platform/sky/contiki-sky-main.c b/platform/sky/contiki-skymain.c


index f7f847d..d39b74d 100644
--- a/platform/sky/contiki-sky-main.c
+++ b/platform/sky/contiki-sky-main.c
@@ -159,6 +159,7 @@ set_rime_addr(void)
static void
print_processes(struct process * const processes[])
{
+#if !PROCESS_CONF_NO_PROCESS_NAMES
/* const struct process * const * p = processes;*/
printf("Starting");
while(*processes != NULL) {
@@ -166,6 +167,7 @@ print_processes(struct process * const processes[])
processes++;
}
putchar('\n');
+#endif /* !PROCESS_CONF_NO_PROCESS_NAMES */
}
/*-------------------------------------------------------------------------*/
#if WITH_UIP
diff --git a/tools/cooja/java/se/sics/cooja/GUI.java
b/tools/cooja/java/se/sics/cooja/GUI.java
index 1362578..1965373 100644
--- a/tools/cooja/java/se/sics/cooja/GUI.java
+++ b/tools/cooja/java/se/sics/cooja/GUI.java
@@ -29,6 +29,7 @@
package se.sics.cooja;
+import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -40,6 +41,7 @@ import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.Stroke;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
@@ -342,11 +344,42 @@ public class GUI extends Observable {
public Mote source;
public Mote dest;
public Color color;
public MoteRelation(Mote source, Mote dest, Color color) {

+
private String attrs;
+
private static Stroke dashedStroke = new BasicStroke(1,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{9}, 0);
+
public MoteRelation(Mote source, Mote dest, String attrs, Color
color) {
this.source = source;
this.dest = dest;
+
this.attrs = attrs;
this.color = color;
}
+
public Stroke getStroke() {
+
if (attrs != null && attrs.contains("dashed")) {
+
return MoteRelation.dashedStroke;
+
}
+
return null;
+
}
+
public Color getColor() {
+
if (attrs == null) {
+
return null;
+
} else if (attrs.contains("red")) {
+
return Color.RED;
+
} else if (attrs.contains("green")) {
+
return Color.GREEN;
+
} else if (attrs.contains("blue")) {
+
return Color.BLUE;
+
} else if (attrs.contains("orange")) {
+
return Color.ORANGE;
+
} else if (attrs.contains("pink")) {
+
return Color.PINK;
+
}
+
return null;
+
}
+
public boolean isOverlay() {
+
if (attrs != null && attrs.contains("overlay")) {
+
return true;
+
}
+
return false;
+
}
}
private ArrayList<MoteRelation> moteRelations = new
ArrayList<MoteRelation>();
@@ -3795,8 +3828,8 @@ public class GUI extends Observable {
* @param source Source mote
* @param dest Destination mote
*/
- public void addMoteRelation(Mote source, Mote dest) {
addMoteRelation(source, dest, null);
+ public void addMoteRelation(Mote source, Mote dest, String attrs) {
+
addMoteRelation(source, dest, attrs, null);
}
/**
@@ -3806,12 +3839,12 @@ public class GUI extends Observable {

* @param dest Destination mote


* @param color The color to use when visualizing the mote relation
*/
- public void addMoteRelation(Mote source, Mote dest, Color color) {
+ public void addMoteRelation(Mote source, Mote dest, String attrs,
Color color) {
if (source == null || dest == null) {
return;
}
removeMoteRelation(source, dest); /* Unique relations */
moteRelations.add(new MoteRelation(source, dest, color));
+
moteRelations.add(new MoteRelation(source, dest, attrs, color));
moteRelationObservable.setChangedAndNotify();
}
diff --git
a/tools/cooja/java/se/sics/cooja/interfaces/Mote2MoteRelations.java
b/tools/cooja/java/se/sics/cooja/interfaces/Mote2MoteRelations.java
index 50943de..5518947 100644
--- a/tools/cooja/java/se/sics/cooja/interfaces/Mote2MoteRelations.java
+++ b/tools/cooja/java/se/sics/cooja/interfaces/Mote2MoteRelations.java
@@ -150,7 +150,7 @@ public class Mote2MoteRelations extends MoteInterface
{
msg = msg.substring(0, colorIndex).trim();
}
String[] args = msg.split(" ");
if (args.length != 3) {
+
if (args.length < 3) {
return;
}
@@ -162,6 +162,10 @@ public class Mote2MoteRelations extends
MoteInterface {
return;
}
String state = args[2];
+
String attrs = null;
+
if (args.length >= 4) {
+
attrs = args[3];
+
}
/* Locate destination mote */
/* TODO Use Rime address interface instead of mote ID? */
@@ -181,7 +185,7 @@ public class Mote2MoteRelations extends MoteInterface
{
return;
}
relations.add(destinationMote);
gui.addMoteRelation(mote, destinationMote,
decodeColor(colorName));
+
gui.addMoteRelation(mote, destinationMote, attrs,
decodeColor(colorName));
} else {
relations.remove(destinationMote);

gui.removeMoteRelation(mote, destinationMote);
diff --git a/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java
b/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java
index 4a65f34..2470a49 100644
--- a/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java
+++ b/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java
@@ -41,6 +41,7 @@ import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
+import java.awt.Stroke;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
@@ -411,6 +412,9 @@ public class Visualizer extends VisPlugin {
if (e.isPopupTrigger()) {
handlePopupRequest(e.getPoint().x, e.getPoint().y);
}
+
else if (e.getClickCount() == 2) {
+
handleDoubleClick(e.getPoint().x, e.getPoint().y);
+
}
handleMouseMove(e, true);
repaint();
@@ -611,6 +615,15 @@ public class Visualizer extends VisPlugin {
visualizerSkins.remove(skin);
}
+
+
+
+
+
+
+
+
+

private void handleDoubleClick(final int x, final int y) {


final Mote[] motes = findMotesAtPosition(x, y);
if (motes != null && motes.length > 0) {
for (final Mote mote : motes) {
mote.getInterfaces().getButton().clickButton();
}
}
}

private void handlePopupRequest(final int x, final int y) {


JPopupMenu menu = new JPopupMenu();
menu.add(new JLabel("Select action:"));
@@ -850,6 +863,7 @@ public class Visualizer extends VisPlugin {
Mote[] allMotes = simulation.getMotes();
/* Paint mote relations */
Stroke defaultStroke = ((Graphics2D)g).getStroke();
MoteRelation[] relations = simulation.getGUI().getMoteRelations();
for (MoteRelation r: relations) {
Position sourcePos = r.source.getInterfaces().getPosition();
@@ -858,9 +872,27 @@ public class Visualizer extends VisPlugin {
Point sourcePoint = transformPositionToPixel(sourcePos);
Point destPoint = transformPositionToPixel(destPos);
+

g.setColor(r.color == null ? Color.black : r.color);


if (r.isOverlay()) {

+
g.setColor(Color.BLACK);
+
((Graphics2D)g).setStroke(defaultStroke);
+
drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x,
destPoint.y, MOTE_RADIUS + 1);
+
}
+
if (r.getStroke() != null) {
+
((Graphics2D)g).setStroke(r.getStroke());
+
}
+
else {
+
((Graphics2D)g).setStroke(defaultStroke);
+
}
+
if (r.getColor() != null) {
+
g.setColor(r.getColor());
+
}
+
else {
+
g.setColor(Color.BLACK);
+
}
drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x,
destPoint.y, MOTE_RADIUS + 1);
}
+
((Graphics2D)g).setStroke(defaultStroke);
+
g.setColor(Color.BLACK);
for (Mote mote: allMotes) {
@@ -922,6 +954,7 @@ public class Visualizer extends VisPlugin {
len -= delta;
xDest = xSource - (int) (dx * len);
yDest = ySource - (int) (dy * len);
+
g.drawLine(xDest, yDest, xSource, ySource);
final int size = 8;
diff --git
a/tools/cooja/java/se/sics/cooja/plugins/skins/AttributeVisualizerSkin.ja
va
b/tools/cooja/java/se/sics/cooja/plugins/skins/AttributeVisualizerSkin.ja
va
index c189a86..a54c1fc 100644
--a/tools/cooja/java/se/sics/cooja/plugins/skins/AttributeVisualizerSkin.ja
va
+++
b/tools/cooja/java/se/sics/cooja/plugins/skins/AttributeVisualizerSkin.ja
va
@@ -129,6 +129,10 @@ public class AttributeVisualizerSkin implements
VisualizerSkin {
return Color.ORANGE;
} else if (colorString.equalsIgnoreCase("pink")) {
return Color.PINK;
+
} else if (colorString.equalsIgnoreCase("cyan")) {
+
return Color.CYAN;
+
} else if (colorString.equalsIgnoreCase("white")) {
+
return Color.WHITE;

} else {
try {
return Color.decode(colorString);

Вам также может понравиться