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"
51 
52 #define DEBUG DEBUG_NONE
53 #include "net/ip/uip-debug.h"
54 
55 #include <limits.h>
56 #include <string.h>
57 
58 #if UIP_CONF_IPV6
59 
60 #if RPL_CONF_STATS
61 rpl_stats_t rpl_stats;
62 #endif
63 
64 static enum rpl_mode mode = RPL_MODE_MESH;
65 /*---------------------------------------------------------------------------*/
66 enum rpl_mode
68 {
69  return mode;
70 }
71 /*---------------------------------------------------------------------------*/
72 enum rpl_mode
73 rpl_set_mode(enum rpl_mode m)
74 {
75  enum rpl_mode oldmode = mode;
76 
77  /* We need to do different things depending on what mode we are
78  switching to. */
79  if(m == RPL_MODE_MESH) {
80 
81  /* If we switcht to mesh mode, we should send out a DAO message to
82  inform our parent that we now are reachable. Before we do this,
83  we must set the mode variable, since DAOs will not be send if
84  we are in feather mode. */
85  PRINTF("RPL: switching to mesh mode\n");
86  mode = m;
87 
88  if(default_instance != NULL) {
89  rpl_schedule_dao_immediately(default_instance);
90  }
91  } else if(m == RPL_MODE_FEATHER) {
92 
93  PRINTF("RPL: switching to feather mode\n");
94  mode = m;
95  if(default_instance != NULL) {
96  rpl_cancel_dao(default_instance);
97  }
98 
99  } else {
100  mode = m;
101  }
102 
103  return oldmode;
104 }
105 /*---------------------------------------------------------------------------*/
106 void
107 rpl_purge_routes(void)
108 {
109  uip_ds6_route_t *r;
110  uip_ipaddr_t prefix;
111  rpl_dag_t *dag;
112 #if RPL_CONF_MULTICAST
113  uip_mcast6_route_t *mcast_route;
114 #endif
115 
116  /* First pass, decrement lifetime */
117  r = uip_ds6_route_head();
118 
119  while(r != NULL) {
120  if(r->state.lifetime >= 1) {
121  /*
122  * If a route is at lifetime == 1, set it to 0, scheduling it for
123  * immediate removal below. This achieves the same as the original code,
124  * which would delete lifetime <= 1
125  */
126  r->state.lifetime--;
127  }
128  r = uip_ds6_route_next(r);
129  }
130 
131  /* Second pass, remove dead routes */
132  r = uip_ds6_route_head();
133 
134  while(r != NULL) {
135  if(r->state.lifetime < 1) {
136  /* Routes with lifetime == 1 have only just been decremented from 2 to 1,
137  * thus we want to keep them. Hence < and not <= */
138  uip_ipaddr_copy(&prefix, &r->ipaddr);
139  uip_ds6_route_rm(r);
140  r = uip_ds6_route_head();
141  PRINTF("No more routes to ");
142  PRINT6ADDR(&prefix);
143  dag = default_instance->current_dag;
144  /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */
145  if(dag->rank != ROOT_RANK(default_instance)) {
146  PRINTF(" -> generate No-Path DAO\n");
147  dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME);
148  /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */
149  return;
150  }
151  PRINTF("\n");
152  } else {
153  r = uip_ds6_route_next(r);
154  }
155  }
156 
157 #if RPL_CONF_MULTICAST
158  mcast_route = uip_mcast6_route_list_head();
159 
160  while(mcast_route != NULL) {
161  if(mcast_route->lifetime <= 1) {
162  uip_mcast6_route_rm(mcast_route);
163  mcast_route = uip_mcast6_route_list_head();
164  } else {
165  mcast_route->lifetime--;
166  mcast_route = list_item_next(mcast_route);
167  }
168  }
169 #endif
170 }
171 /*---------------------------------------------------------------------------*/
172 void
173 rpl_remove_routes(rpl_dag_t *dag)
174 {
175  uip_ds6_route_t *r;
176 #if RPL_CONF_MULTICAST
177  uip_mcast6_route_t *mcast_route;
178 #endif
179 
180  r = uip_ds6_route_head();
181 
182  while(r != NULL) {
183  if(r->state.dag == dag) {
184  uip_ds6_route_rm(r);
185  r = uip_ds6_route_head();
186  } else {
187  r = uip_ds6_route_next(r);
188  }
189  }
190 
191 #if RPL_CONF_MULTICAST
192  mcast_route = uip_mcast6_route_list_head();
193 
194  while(mcast_route != NULL) {
195  if(mcast_route->dag == dag) {
196  uip_mcast6_route_rm(mcast_route);
197  mcast_route = uip_mcast6_route_list_head();
198  } else {
199  mcast_route = list_item_next(mcast_route);
200  }
201  }
202 #endif
203 }
204 /*---------------------------------------------------------------------------*/
205 void
206 rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag)
207 {
208  uip_ds6_route_t *r;
209 
210  r = uip_ds6_route_head();
211 
212  while(r != NULL) {
213  if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), nexthop) &&
214  r->state.dag == dag) {
215  uip_ds6_route_rm(r);
216  r = uip_ds6_route_head();
217  } else {
218  r = uip_ds6_route_next(r);
219  }
220  }
221  ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
222 }
223 /*---------------------------------------------------------------------------*/
225 rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len,
226  uip_ipaddr_t *next_hop)
227 {
228  uip_ds6_route_t *rep;
229 
230  if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop)) == NULL) {
231  PRINTF("RPL: No space for more route entries\n");
232  return NULL;
233  }
234 
235  rep->state.dag = dag;
236  rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime);
237  rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL;
238 
239  PRINTF("RPL: Added a route to ");
240  PRINT6ADDR(prefix);
241  PRINTF("/%d via ", prefix_len);
242  PRINT6ADDR(next_hop);
243  PRINTF("\n");
244 
245  return rep;
246 }
247 /*---------------------------------------------------------------------------*/
248 void
249 rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
250 {
251  uip_ipaddr_t ipaddr;
252  rpl_parent_t *parent;
253  rpl_instance_t *instance;
254  rpl_instance_t *end;
255 
256  uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0);
257  uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr);
258 
259  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
260  if(instance->used == 1 ) {
261  parent = rpl_find_parent_any_dag(instance, &ipaddr);
262  if(parent != NULL) {
263  /* Trigger DAG rank recalculation. */
264  PRINTF("RPL: rpl_link_neighbor_callback triggering update\n");
265  parent->flags |= RPL_PARENT_FLAG_UPDATED;
266  if(instance->of->neighbor_link_callback != NULL) {
267  instance->of->neighbor_link_callback(parent, status, numtx);
268  }
269  }
270  }
271  }
272 }
273 /*---------------------------------------------------------------------------*/
274 void
275 rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr)
276 {
277  rpl_parent_t *p;
278  rpl_instance_t *instance;
279  rpl_instance_t *end;
280 
281  PRINTF("RPL: Removing neighbor ");
282  PRINT6ADDR(&nbr->ipaddr);
283  PRINTF("\n");
284  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
285  if(instance->used == 1 ) {
286  p = rpl_find_parent_any_dag(instance, &nbr->ipaddr);
287  if(p != NULL) {
288  p->rank = INFINITE_RANK;
289  /* Trigger DAG rank recalculation. */
290  PRINTF("RPL: rpl_ipv6_neighbor_callback infinite rank\n");
291  p->flags |= RPL_PARENT_FLAG_UPDATED;
292  }
293  }
294  }
295 }
296 /*---------------------------------------------------------------------------*/
297 void
298 rpl_init(void)
299 {
300  uip_ipaddr_t rplmaddr;
301  PRINTF("RPL started\n");
302  default_instance = NULL;
303 
304  rpl_dag_init();
305  rpl_reset_periodic_timer();
306  rpl_icmp6_register_handlers();
307 
308  /* add rpl multicast address */
309  uip_create_linklocal_rplnodes_mcast(&rplmaddr);
310  uip_ds6_maddr_add(&rplmaddr);
311 
312 #if RPL_CONF_STATS
313  memset(&rpl_stats, 0, sizeof(rpl_stats));
314 #endif
315 
316  RPL_OF.reset(NULL);
317 }
318 /*---------------------------------------------------------------------------*/
319 #endif /* UIP_CONF_IPV6 */
320 
321 /** @}*/
An entry in the routing table.
This header file contains configuration directives for uIPv6 multicast support.
Header file for the uIP TCP/IP stack.
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:535
Header for the Contiki/uIP interface.
Network interface and stateless autoconfiguration (RFC 4862)
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
#define NULL
The null pointer.
An entry in the multicast routing table.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
ICMPv6 echo request and error messages (RFC 4443)
enum rpl_mode rpl_get_mode(void)
Get the RPL mode.
Definition: rpl.c:67
802.3 address
Definition: uip.h:135
enum rpl_mode rpl_set_mode(enum rpl_mode m)
Set the RPL mode.
Definition: rpl.c:73
A set of debugging macros.
#define uip_ip6addr(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7)
Construct an IPv6 address from eight 16-bit words.
Definition: uip.h:969
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:70