Contiki-Inga 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>
38  * \author Nicolas Tsiftes <nvt@sics.se>
39  */
40 
41 /**
42  * \addtogroup uip6
43  * @{ */
44 #include "net/ip/uip.h"
45 #include "net/ip/tcpip.h"
46 #include "net/ipv6/uip-ds6.h"
47 
48 #include "net/rpl/rpl-private.h"
50 
51 #define DEBUG DEBUG_NONE
52 #include "net/ip/uip-debug.h"
53 
54 #include <limits.h>
55 #include <string.h>
56 
57 #if UIP_CONF_IPV6
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
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 switcht 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 send 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  mode = m;
94  if(default_instance != NULL) {
95  rpl_cancel_dao(default_instance);
96  }
97 
98  } else {
99  mode = m;
100  }
101 
102  return oldmode;
103 }
104 /*---------------------------------------------------------------------------*/
105 void
106 rpl_purge_routes(void)
107 {
108  uip_ds6_route_t *r;
109  uip_ipaddr_t prefix;
110  rpl_dag_t *dag;
111 #if RPL_CONF_MULTICAST
112  uip_mcast6_route_t *mcast_route;
113 #endif
114 
115  /* First pass, decrement lifetime */
116  r = uip_ds6_route_head();
117 
118  while(r != NULL) {
119  if(r->state.lifetime >= 1) {
120  /*
121  * If a route is at lifetime == 1, set it to 0, scheduling it for
122  * immediate removal below. This achieves the same as the original code,
123  * which would delete lifetime <= 1
124  */
125  r->state.lifetime--;
126  }
127  r = uip_ds6_route_next(r);
128  }
129 
130  /* Second pass, remove dead routes */
131  r = uip_ds6_route_head();
132 
133  while(r != NULL) {
134  if(r->state.lifetime < 1) {
135  /* Routes with lifetime == 1 have only just been decremented from 2 to 1,
136  * thus we want to keep them. Hence < and not <= */
137  uip_ipaddr_copy(&prefix, &r->ipaddr);
138  uip_ds6_route_rm(r);
139  r = uip_ds6_route_head();
140  PRINTF("No more routes to ");
141  PRINT6ADDR(&prefix);
142  dag = default_instance->current_dag;
143  /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */
144  if(dag->rank != ROOT_RANK(default_instance)) {
145  PRINTF(" -> generate No-Path DAO\n");
146  dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME);
147  /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */
148  return;
149  }
150  PRINTF("\n");
151  } else {
152  r = uip_ds6_route_next(r);
153  }
154  }
155 
156 #if RPL_CONF_MULTICAST
157  mcast_route = uip_mcast6_route_list_head();
158 
159  while(mcast_route != NULL) {
160  if(mcast_route->lifetime <= 1) {
161  uip_mcast6_route_rm(mcast_route);
162  mcast_route = uip_mcast6_route_list_head();
163  } else {
164  mcast_route->lifetime--;
165  mcast_route = list_item_next(mcast_route);
166  }
167  }
168 #endif
169 }
170 /*---------------------------------------------------------------------------*/
171 void
172 rpl_remove_routes(rpl_dag_t *dag)
173 {
174  uip_ds6_route_t *r;
175 #if RPL_CONF_MULTICAST
176  uip_mcast6_route_t *mcast_route;
177 #endif
178 
179  r = uip_ds6_route_head();
180 
181  while(r != NULL) {
182  if(r->state.dag == dag) {
183  uip_ds6_route_rm(r);
184  r = uip_ds6_route_head();
185  } else {
186  r = uip_ds6_route_next(r);
187  }
188  }
189 
190 #if RPL_CONF_MULTICAST
191  mcast_route = uip_mcast6_route_list_head();
192 
193  while(mcast_route != NULL) {
194  if(mcast_route->dag == dag) {
195  uip_mcast6_route_rm(mcast_route);
196  mcast_route = uip_mcast6_route_list_head();
197  } else {
198  mcast_route = list_item_next(mcast_route);
199  }
200  }
201 #endif
202 }
203 /*---------------------------------------------------------------------------*/
204 void
205 rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag)
206 {
207  uip_ds6_route_t *r;
208 
209  r = uip_ds6_route_head();
210 
211  while(r != NULL) {
212  if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), nexthop) &&
213  r->state.dag == dag) {
214  uip_ds6_route_rm(r);
215  r = uip_ds6_route_head();
216  } else {
217  r = uip_ds6_route_next(r);
218  }
219  }
220  ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
221 }
222 /*---------------------------------------------------------------------------*/
224 rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len,
225  uip_ipaddr_t *next_hop)
226 {
227  uip_ds6_route_t *rep;
228 
229  if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop)) == NULL) {
230  PRINTF("RPL: No space for more route entries\n");
231  return NULL;
232  }
233 
234  rep->state.dag = dag;
235  rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime);
236  rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL;
237 
238  PRINTF("RPL: Added a route to ");
239  PRINT6ADDR(prefix);
240  PRINTF("/%d via ", prefix_len);
241  PRINT6ADDR(next_hop);
242  PRINTF("\n");
243 
244  return rep;
245 }
246 /*---------------------------------------------------------------------------*/
247 void
248 rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
249 {
250  uip_ipaddr_t ipaddr;
251  rpl_parent_t *parent;
252  rpl_instance_t *instance;
253  rpl_instance_t *end;
254 
255  uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0);
256  uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr);
257 
258  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
259  if(instance->used == 1 ) {
260  parent = rpl_find_parent_any_dag(instance, &ipaddr);
261  if(parent != NULL) {
262  /* Trigger DAG rank recalculation. */
263  PRINTF("RPL: rpl_link_neighbor_callback triggering update\n");
264  parent->updated = 1;
265  if(instance->of->neighbor_link_callback != NULL) {
266  instance->of->neighbor_link_callback(parent, status, numtx);
267  }
268  }
269  }
270  }
271 }
272 /*---------------------------------------------------------------------------*/
273 void
274 rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr)
275 {
276  rpl_parent_t *p;
277  rpl_instance_t *instance;
278  rpl_instance_t *end;
279 
280  PRINTF("RPL: Removing neighbor ");
281  PRINT6ADDR(&nbr->ipaddr);
282  PRINTF("\n");
283  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
284  if(instance->used == 1 ) {
285  p = rpl_find_parent_any_dag(instance, &nbr->ipaddr);
286  if(p != NULL) {
287  p->rank = INFINITE_RANK;
288  /* Trigger DAG rank recalculation. */
289  PRINTF("RPL: rpl_ipv6_neighbor_callback infinite rank\n");
290  p->updated = 1;
291  }
292  }
293  }
294 }
295 /*---------------------------------------------------------------------------*/
296 void
297 rpl_init(void)
298 {
299  uip_ipaddr_t rplmaddr;
300  PRINTF("RPL started\n");
301  default_instance = NULL;
302 
303  rpl_dag_init();
304  rpl_reset_periodic_timer();
305 
306  /* add rpl multicast address */
307  uip_create_linklocal_rplnodes_mcast(&rplmaddr);
308  uip_ds6_maddr_add(&rplmaddr);
309 
310 #if RPL_CONF_STATS
311  memset(&rpl_stats, 0, sizeof(rpl_stats));
312 #endif
313 
314  RPL_OF.reset(NULL);
315 }
316 /*---------------------------------------------------------------------------*/
317 /** @} */
318 #endif /* UIP_CONF_IPV6 */