Contiki 3.x
rpl.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 /**
33  * \file
34  * ContikiRPL, an implementation of RPL: IPv6 Routing Protocol
35  * for Low-Power and Lossy Networks (IETF RFC 6550)
36  *
37  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
38  */
39 
40 /**
41  * \addtogroup uip6
42  * @{
43  */
44 
45 #include "net/ip/uip.h"
46 #include "net/ip/tcpip.h"
47 #include "net/ipv6/uip-ds6.h"
48 #include "net/ipv6/uip-icmp6.h"
49 #include "net/rpl/rpl-private.h"
50 #include "net/rpl/rpl-ns.h"
52 
53 #define DEBUG DEBUG_NONE
54 #include "net/ip/uip-debug.h"
55 
56 #include <limits.h>
57 #include <string.h>
58 
59 #if RPL_CONF_STATS
60 rpl_stats_t rpl_stats;
61 #endif
62 
63 static enum rpl_mode mode = RPL_MODE_MESH;
64 /*---------------------------------------------------------------------------*/
65 enum rpl_mode
67 {
68  return mode;
69 }
70 /*---------------------------------------------------------------------------*/
71 enum rpl_mode
72 rpl_set_mode(enum rpl_mode m)
73 {
74  enum rpl_mode oldmode = mode;
75 
76  /* We need to do different things depending on what mode we are
77  switching to. */
78  if(m == RPL_MODE_MESH) {
79 
80  /* If we switch to mesh mode, we should send out a DAO message to
81  inform our parent that we now are reachable. Before we do this,
82  we must set the mode variable, since DAOs will not be sent if
83  we are in feather mode. */
84  PRINTF("RPL: switching to mesh mode\n");
85  mode = m;
86 
87  if(default_instance != NULL) {
88  rpl_schedule_dao_immediately(default_instance);
89  }
90  } else if(m == RPL_MODE_FEATHER) {
91 
92  PRINTF("RPL: switching to feather mode\n");
93  if(default_instance != NULL) {
94  PRINTF("rpl_set_mode: RPL sending DAO with zero lifetime\n");
95  if(default_instance->current_dag != NULL) {
96  dao_output(default_instance->current_dag->preferred_parent, RPL_ZERO_LIFETIME);
97  }
98  rpl_cancel_dao(default_instance);
99  } else {
100  PRINTF("rpl_set_mode: no default instance\n");
101  }
102 
103  mode = m;
104  } else {
105  mode = m;
106  }
107 
108  return oldmode;
109 }
110 /*---------------------------------------------------------------------------*/
111 void
112 rpl_purge_routes(void)
113 {
114  uip_ds6_route_t *r;
115  uip_ipaddr_t prefix;
116  rpl_dag_t *dag;
117 #if RPL_CONF_MULTICAST
118  uip_mcast6_route_t *mcast_route;
119 #endif
120 
121  /* First pass, decrement lifetime */
122  r = uip_ds6_route_head();
123 
124  while(r != NULL) {
125  if(r->state.lifetime >= 1) {
126  /*
127  * If a route is at lifetime == 1, set it to 0, scheduling it for
128  * immediate removal below. This achieves the same as the original code,
129  * which would delete lifetime <= 1
130  */
131  r->state.lifetime--;
132  }
133  r = uip_ds6_route_next(r);
134  }
135 
136  /* Second pass, remove dead routes */
137  r = uip_ds6_route_head();
138 
139  while(r != NULL) {
140  if(r->state.lifetime < 1) {
141  /* Routes with lifetime == 1 have only just been decremented from 2 to 1,
142  * thus we want to keep them. Hence < and not <= */
143  uip_ipaddr_copy(&prefix, &r->ipaddr);
144  uip_ds6_route_rm(r);
145  r = uip_ds6_route_head();
146  PRINTF("No more routes to ");
147  PRINT6ADDR(&prefix);
148  dag = default_instance->current_dag;
149  /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */
150  if(dag->rank != ROOT_RANK(default_instance)) {
151  PRINTF(" -> generate No-Path DAO\n");
152  dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME);
153  /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */
154  return;
155  }
156  PRINTF("\n");
157  } else {
158  r = uip_ds6_route_next(r);
159  }
160  }
161 
162 #if RPL_CONF_MULTICAST
163  mcast_route = uip_mcast6_route_list_head();
164 
165  while(mcast_route != NULL) {
166  if(mcast_route->lifetime <= 1) {
167  uip_mcast6_route_rm(mcast_route);
168  mcast_route = uip_mcast6_route_list_head();
169  } else {
170  mcast_route->lifetime--;
171  mcast_route = list_item_next(mcast_route);
172  }
173  }
174 #endif
175 }
176 /*---------------------------------------------------------------------------*/
177 void
178 rpl_remove_routes(rpl_dag_t *dag)
179 {
180  uip_ds6_route_t *r;
181 #if RPL_CONF_MULTICAST
182  uip_mcast6_route_t *mcast_route;
183 #endif
184 
185  r = uip_ds6_route_head();
186 
187  while(r != NULL) {
188  if(r->state.dag == dag) {
189  uip_ds6_route_rm(r);
190  r = uip_ds6_route_head();
191  } else {
192  r = uip_ds6_route_next(r);
193  }
194  }
195 
196 #if RPL_CONF_MULTICAST
197  mcast_route = uip_mcast6_route_list_head();
198 
199  while(mcast_route != NULL) {
200  if(mcast_route->dag == dag) {
201  uip_mcast6_route_rm(mcast_route);
202  mcast_route = uip_mcast6_route_list_head();
203  } else {
204  mcast_route = list_item_next(mcast_route);
205  }
206  }
207 #endif
208 }
209 /*---------------------------------------------------------------------------*/
210 void
211 rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag)
212 {
213  uip_ds6_route_t *r;
214 
215  r = uip_ds6_route_head();
216 
217  while(r != NULL) {
218  if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), nexthop) &&
219  r->state.dag == dag) {
220  r->state.lifetime = 0;
221  }
222  r = uip_ds6_route_next(r);
223  }
224  ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
225 }
226 /*---------------------------------------------------------------------------*/
228 rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len,
229  uip_ipaddr_t *next_hop)
230 {
231  uip_ds6_route_t *rep;
232 
233  if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop)) == NULL) {
234  PRINTF("RPL: No space for more route entries\n");
235  return NULL;
236  }
237 
238  rep->state.dag = dag;
239  rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime);
240  /* always clear state flags for the no-path received when adding/refreshing */
241  RPL_ROUTE_CLEAR_NOPATH_RECEIVED(rep);
242 
243  PRINTF("RPL: Added a route to ");
244  PRINT6ADDR(prefix);
245  PRINTF("/%d via ", prefix_len);
246  PRINT6ADDR(next_hop);
247  PRINTF("\n");
248 
249  return rep;
250 }
251 /*---------------------------------------------------------------------------*/
252 void
253 rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
254 {
255  uip_ipaddr_t ipaddr;
256  rpl_parent_t *parent;
257  rpl_instance_t *instance;
258  rpl_instance_t *end;
259 
260  uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0);
261  uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr);
262 
263  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
264  if(instance->used == 1 ) {
265  parent = rpl_find_parent_any_dag(instance, &ipaddr);
266  if(parent != NULL) {
267  /* Trigger DAG rank recalculation. */
268  PRINTF("RPL: rpl_link_neighbor_callback triggering update\n");
269  parent->flags |= RPL_PARENT_FLAG_UPDATED;
270  }
271  }
272  }
273 }
274 /*---------------------------------------------------------------------------*/
275 void
276 rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr)
277 {
278  rpl_parent_t *p;
279  rpl_instance_t *instance;
280  rpl_instance_t *end;
281 
282  PRINTF("RPL: Neighbor state changed for ");
283  PRINT6ADDR(&nbr->ipaddr);
284 #if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA
285  PRINTF(", nscount=%u, state=%u\n", nbr->nscount, nbr->state);
286 #else /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA */
287  PRINTF(", state=%u\n", nbr->state);
288 #endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA */
289  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
290  if(instance->used == 1 ) {
291  p = rpl_find_parent_any_dag(instance, &nbr->ipaddr);
292  if(p != NULL) {
293  p->rank = INFINITE_RANK;
294  /* Trigger DAG rank recalculation. */
295  PRINTF("RPL: rpl_ipv6_neighbor_callback infinite rank\n");
296  p->flags |= RPL_PARENT_FLAG_UPDATED;
297  }
298  }
299  }
300 }
301 /*---------------------------------------------------------------------------*/
302 void
303 rpl_purge_dags(void)
304 {
305  rpl_instance_t *instance;
306  rpl_instance_t *end;
307  int i;
308 
309  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
310  instance < end; ++instance) {
311  if(instance->used) {
312  for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) {
313  if(instance->dag_table[i].used) {
314  if(instance->dag_table[i].lifetime == 0) {
315  if(!instance->dag_table[i].joined) {
316  PRINTF("Removing dag ");
317  PRINT6ADDR(&instance->dag_table[i].dag_id);
318  PRINTF("\n");
319  rpl_free_dag(&instance->dag_table[i]);
320  }
321  } else {
322  instance->dag_table[i].lifetime--;
323  }
324  }
325  }
326  }
327  }
328 }
329 /*---------------------------------------------------------------------------*/
330 void
331 rpl_init(void)
332 {
333  uip_ipaddr_t rplmaddr;
334  PRINTF("RPL started\n");
335  default_instance = NULL;
336 
337  rpl_dag_init();
338  rpl_reset_periodic_timer();
339  rpl_icmp6_register_handlers();
340 
341  /* add rpl multicast address */
342  uip_create_linklocal_rplnodes_mcast(&rplmaddr);
343  uip_ds6_maddr_add(&rplmaddr);
344 
345 #if RPL_CONF_STATS
346  memset(&rpl_stats, 0, sizeof(rpl_stats));
347 #endif
348 
349 #if RPL_WITH_NON_STORING
350  rpl_ns_init();
351 #endif /* RPL_WITH_NON_STORING */
352 }
353 /*---------------------------------------------------------------------------*/
354 
355 /** @}*/
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:129
void * dag
Pointer to an rpl_dag_t struct.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
Header file for IPv6-related data structures.
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1027
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:70
uip_mcast6_route_t * uip_mcast6_route_list_head(void)
Retrieve a pointer to the start of the multicast routes list.
Header for the Contiki/uIP interface.
void uip_mcast6_route_rm(uip_mcast6_route_t *route)
Remove a multicast route.
This header file contains configuration directives for uIPv6 multicast support.
#define NULL
The null pointer.
802.3 address
Definition: uip.h:129
Header file for ICMPv6 message and error handing (RFC 4443)
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:122
enum rpl_mode rpl_set_mode(enum rpl_mode m)
Set the RPL mode.
Definition: rpl.c:72
#define uip_ip6addr(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7)
Construct an IPv6 address from eight 16-bit words.
Definition: uip.h:970
An entry in the multicast routing table.
Header file for the uIP TCP/IP stack.
A set of debugging macros for the IP stack
enum rpl_mode rpl_get_mode(void)
Get the RPL mode.
Definition: rpl.c:66
RPL non-storing mode specific functions.
An entry in the routing table.
void uip_ds6_set_addr_iid(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr)
set the last 64 bits of an IP address based on the MAC address
Definition: uip-ds6.c:542
uint32_t lifetime
Entry lifetime seconds.