Contiki 3.x
rpl-ns.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, Inria.
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  * RPL non-storing mode specific functions. Includes support for
35  * source routing.
36  *
37  * \author Simon Duquennoy <simon.duquennoy@inria.fr>
38  */
39 
40 #include "net/rpl/rpl-conf.h"
41 
42 #include "net/ip/uip.h"
43 #include "net/ip/tcpip.h"
44 #include "net/ipv6/uip-ds6.h"
45 #include "net/ipv6/uip-icmp6.h"
46 #include "net/rpl/rpl-private.h"
47 #include "net/rpl/rpl-ns.h"
48 #include "lib/list.h"
49 #include "lib/memb.h"
50 
51 #if RPL_WITH_NON_STORING
52 
53 #define DEBUG DEBUG_NONE
54 #include "net/ip/uip-debug.h"
55 
56 #include <limits.h>
57 #include <string.h>
58 
59 /* Total number of nodes */
60 static int num_nodes;
61 
62 /* Every known node in the network */
63 LIST(nodelist);
64 MEMB(nodememb, rpl_ns_node_t, RPL_NS_LINK_NUM);
65 
66 /*---------------------------------------------------------------------------*/
67 int
68 rpl_ns_num_nodes(void)
69 {
70  return num_nodes;
71 }
72 /*---------------------------------------------------------------------------*/
73 static int
74 node_matches_address(const rpl_dag_t *dag, const rpl_ns_node_t *node, const uip_ipaddr_t *addr)
75 {
76  return addr != NULL
77  && node != NULL
78  && dag != NULL
79  && dag == node->dag
80  && !memcmp(addr, &node->dag->dag_id, 8)
81  && !memcmp(((const unsigned char *)addr) + 8, node->link_identifier, 8);
82 }
83 /*---------------------------------------------------------------------------*/
84 rpl_ns_node_t *
85 rpl_ns_get_node(const rpl_dag_t *dag, const uip_ipaddr_t *addr)
86 {
87  rpl_ns_node_t *l;
88  for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
89  /* Compare prefix and node identifier */
90  if(node_matches_address(dag, l, addr)) {
91  return l;
92  }
93  }
94  return NULL;
95 }
96 /*---------------------------------------------------------------------------*/
97 int
98 rpl_ns_is_node_reachable(const rpl_dag_t *dag, const uip_ipaddr_t *addr)
99 {
100  int max_depth = RPL_NS_LINK_NUM;
101  rpl_ns_node_t *node = rpl_ns_get_node(dag, addr);
102  rpl_ns_node_t *root_node = rpl_ns_get_node(dag, dag != NULL ? &dag->dag_id : NULL);
103  while(node != NULL && node != root_node && max_depth > 0) {
104  node = node->parent;
105  max_depth--;
106  }
107  return node != NULL && node == root_node;
108 }
109 /*---------------------------------------------------------------------------*/
110 void
111 rpl_ns_expire_parent(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent)
112 {
113  rpl_ns_node_t *l = rpl_ns_get_node(dag, child);
114  /* Check if parent matches */
115  if(l != NULL && node_matches_address(dag, l->parent, parent)) {
116  l->lifetime = RPL_NOPATH_REMOVAL_DELAY;
117  }
118 }
119 /*---------------------------------------------------------------------------*/
120 rpl_ns_node_t *
121 rpl_ns_update_node(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime)
122 {
123  rpl_ns_node_t *child_node = rpl_ns_get_node(dag, child);
124  rpl_ns_node_t *parent_node = rpl_ns_get_node(dag, parent);
125  rpl_ns_node_t *old_parent_node;
126 
127  if(parent != NULL) {
128  /* No node for the parent, add one with infinite lifetime */
129  if(parent_node == NULL) {
130  parent_node = rpl_ns_update_node(dag, parent, NULL, 0xffffffff);
131  if(parent_node == NULL) {
132  return NULL;
133  }
134  }
135  }
136 
137  /* No node for this child, add one */
138  if(child_node == NULL) {
139  child_node = memb_alloc(&nodememb);
140  /* No space left, abort */
141  if(child_node == NULL) {
142  return NULL;
143  }
144  child_node->parent = NULL;
145  list_add(nodelist, child_node);
146  num_nodes++;
147  }
148 
149  /* Initialize node */
150  child_node->dag = dag;
151  child_node->lifetime = lifetime;
152  memcpy(child_node->link_identifier, ((const unsigned char *)child) + 8, 8);
153 
154  /* Is the node reachable before the update? */
155  if(rpl_ns_is_node_reachable(dag, child)) {
156  old_parent_node = child_node->parent;
157  /* Update node */
158  child_node->parent = parent_node;
159  /* Has the node become unreachable? May happen if we create a loop. */
160  if(!rpl_ns_is_node_reachable(dag, child)) {
161  /* The new parent makes the node unreachable, restore old parent.
162  * We will take the update next time, with chances we know more of
163  * the topology and the loop is gone. */
164  child_node->parent = old_parent_node;
165  }
166  } else {
167  child_node->parent = parent_node;
168  }
169 
170  return child_node;
171 }
172 /*---------------------------------------------------------------------------*/
173 void
174 rpl_ns_init(void)
175 {
176  num_nodes = 0;
177  memb_init(&nodememb);
178  list_init(nodelist);
179 }
180 /*---------------------------------------------------------------------------*/
181 rpl_ns_node_t *
182 rpl_ns_node_head(void)
183 {
184  return list_head(nodelist);
185 }
186 /*---------------------------------------------------------------------------*/
187 rpl_ns_node_t *
188 rpl_ns_node_next(rpl_ns_node_t *item)
189 {
190  return list_item_next(item);
191 }
192 /*---------------------------------------------------------------------------*/
193 void
194 rpl_ns_get_node_global_addr(uip_ipaddr_t *addr, rpl_ns_node_t *node)
195 {
196  if(addr != NULL && node != NULL && node->dag != NULL) {
197  memcpy(addr, &node->dag->dag_id, 8);
198  memcpy(((unsigned char *)addr) + 8, &node->link_identifier, 8);
199  }
200 }
201 /*---------------------------------------------------------------------------*/
202 void
203 rpl_ns_periodic(void)
204 {
205  rpl_ns_node_t *l;
206  /* First pass, decrement lifetime for all nodes with non-infinite lifetime */
207  for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
208  /* Don't touch infinite lifetime nodes */
209  if(l->lifetime != 0xffffffff && l->lifetime > 0) {
210  l->lifetime--;
211  }
212  }
213  /* Second pass, for all expire nodes, deallocate them iff no child points to them */
214  for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
215  if(l->lifetime == 0) {
216  rpl_ns_node_t *l2;
217  for(l2 = list_head(nodelist); l2 != NULL; l2 = list_item_next(l2)) {
218  if(l2->parent == l) {
219  break;
220  }
221  }
222  /* No child found, deallocate node */
223  list_remove(nodelist, l);
224  memb_free(&nodememb, l);
225  num_nodes--;
226  }
227  }
228 }
229 
230 #endif /* RPL_WITH_NON_STORING */
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
#define LIST(name)
Declare a linked list.
Definition: list.h:86
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
Header file for IPv6-related data structures.
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
Header for the Contiki/uIP interface.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
#define NULL
The null pointer.
Header file for ICMPv6 message and error handing (RFC 4443)
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
Linked list manipulation routines.
Header file for the uIP TCP/IP stack.
Memory block allocation routines.
A set of debugging macros for the IP stack
RPL non-storing mode specific functions.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:79