Contiki 3.x
rpl-dag-root.c
1 /*
2  * Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
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 copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 
32 #include "contiki.h"
33 #include "contiki-net.h"
34 
35 #include "net/rpl/rpl.h"
36 #include "net/rpl/rpl-private.h"
37 #include "net/rpl/rpl-dag-root.h"
38 
39 #include <string.h>
40 
41 #define DEBUG DEBUG_NONE
42 #include "net/ip/uip-debug.h"
43 
44 #define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1)
45 
46 #if (UIP_CONF_MAX_ROUTES != 0)
47 static struct uip_ds6_notification n;
48 #endif /* (UIP_CONF_MAX_ROUTES != 0) */
49 static uint8_t to_become_root;
50 static struct ctimer c;
51 /*---------------------------------------------------------------------------*/
52 static const uip_ipaddr_t *
53 dag_root(void)
54 {
55  rpl_dag_t *dag;
56 
57  dag = rpl_get_any_dag();
58  if(dag != NULL) {
59  return &dag->dag_id;
60  }
61 
62  return NULL;
63 }
64 /*---------------------------------------------------------------------------*/
65 static const uip_ipaddr_t *
66 get_global_address(void)
67 {
68  int i;
69  uint8_t state;
70  uip_ipaddr_t *ipaddr = NULL;
71 
72  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
73  state = uip_ds6_if.addr_list[i].state;
74  if(uip_ds6_if.addr_list[i].isused &&
75  state == ADDR_PREFERRED &&
76  !uip_is_addr_linklocal(&uip_ds6_if.addr_list[i].ipaddr)) {
77  ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
78  }
79  }
80  return ipaddr;
81 }
82 /*---------------------------------------------------------------------------*/
83 static void
84 create_dag_callback(void *ptr)
85 {
86  const uip_ipaddr_t *root, *ipaddr;
87 
88  root = dag_root();
89  ipaddr = get_global_address();
90 
91  if(root == NULL || uip_ipaddr_cmp(root, ipaddr)) {
92  /* The RPL network we are joining is one that we created, so we
93  become root. */
94  if(to_become_root) {
95  rpl_dag_root_init_dag_immediately();
96  to_become_root = 0;
97  }
98  } else {
99  rpl_dag_t *dag;
100 
101  dag = rpl_get_any_dag();
102 #if DEBUG
103  printf("Found a network we did not create\n");
104  printf("version %d grounded %d preference %d used %d joined %d rank %d\n",
105  dag->version, dag->grounded,
106  dag->preference, dag->used,
107  dag->joined, dag->rank);
108 #endif /* DEBUG */
109 
110  /* We found a RPL network that we did not create so we just join
111  it without becoming root. But if the network has an infinite
112  rank, we assume the network has broken, and we become the new
113  root of the network. */
114 
115  if(dag->rank == INFINITE_RANK) {
116  if(to_become_root) {
117  rpl_dag_root_init_dag_immediately();
118  to_become_root = 0;
119  }
120  }
121 
122  /* Try again after the grace period */
123  ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
124  }
125 }
126 #if (UIP_CONF_MAX_ROUTES != 0)
127 /*---------------------------------------------------------------------------*/
128 static void
129 route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
130  int numroutes)
131 {
132  if(event == UIP_DS6_NOTIFICATION_DEFRT_ADD) {
133  if(route != NULL && ipaddr != NULL &&
134  !uip_is_addr_unspecified(route) &&
135  !uip_is_addr_unspecified(ipaddr)) {
136  if(to_become_root) {
137  ctimer_set(&c, 0, create_dag_callback, NULL);
138  }
139  }
140  }
141 }
142 #endif /* (UIP_CONF_MAX_ROUTES != 0) */
143 /*---------------------------------------------------------------------------*/
144 static uip_ipaddr_t *
145 set_global_address(void)
146 {
147  static uip_ipaddr_t ipaddr;
148  int i;
149  uint8_t state;
150 
151  /* Assign a unique local address (RFC4193,
152  http://tools.ietf.org/html/rfc4193). */
153  uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
154  uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
155  uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
156 
157  printf("IPv6 addresses: ");
158  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
159  state = uip_ds6_if.addr_list[i].state;
160  if(uip_ds6_if.addr_list[i].isused &&
161  (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
162  uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
163  printf("\n");
164  }
165  }
166 
167  return &ipaddr;
168 }
169 /*---------------------------------------------------------------------------*/
170 void
171 rpl_dag_root_init(void)
172 {
173  static uint8_t initialized = 0;
174 
175  if(!initialized) {
176  to_become_root = 0;
177  set_global_address();
178 #if (UIP_CONF_MAX_ROUTES != 0)
179  uip_ds6_notification_add(&n, route_callback);
180 #endif /* (UIP_CONF_MAX_ROUTES != 0) */
181  initialized = 1;
182  }
183 }
184 /*---------------------------------------------------------------------------*/
185 int
186 rpl_dag_root_init_dag_immediately(void)
187 {
188  struct uip_ds6_addr *root_if;
189  int i;
190  uint8_t state;
191  uip_ipaddr_t *ipaddr = NULL;
192 
193  rpl_dag_root_init();
194 
195  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
196  state = uip_ds6_if.addr_list[i].state;
197  if(uip_ds6_if.addr_list[i].isused &&
198  state == ADDR_PREFERRED &&
199  !uip_is_addr_linklocal(&uip_ds6_if.addr_list[i].ipaddr)) {
200  ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
201  }
202  }
203 
204  if(ipaddr != NULL) {
205  root_if = uip_ds6_addr_lookup(ipaddr);
206  if(root_if != NULL) {
207  rpl_dag_t *dag;
208  uip_ipaddr_t prefix;
209 
210  rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr);
211  dag = rpl_get_any_dag();
212 
213  /* If there are routes in this dag, we remove them all as we are
214  from now on the new dag root and the old routes are wrong */
215  if(RPL_IS_STORING(dag->instance)) {
216  rpl_remove_routes(dag);
217  }
218  if(dag->instance != NULL &&
219  dag->instance->def_route != NULL) {
220  uip_ds6_defrt_rm(dag->instance->def_route);
221  dag->instance->def_route = NULL;
222  }
223 
224  uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
225  rpl_set_prefix(dag, &prefix, 64);
226  PRINTF("rpl_dag_root_init_dag: created a new RPL dag\n");
227  return 0;
228  } else {
229  PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG\n");
230  return -1;
231  }
232  } else {
233  PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG, no preferred IP address found\n");
234  return -2;
235  }
236 }
237 /*---------------------------------------------------------------------------*/
238 void
239 rpl_dag_root_init_dag(void)
240 {
241  rpl_dag_root_init();
242 
243  ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
244  to_become_root = 1;
245 
246  /* Send a DIS packet to request RPL info from neighbors. */
247  dis_output(NULL);
248 }
249 /*---------------------------------------------------------------------------*/
250 int
251 rpl_dag_root_is_root(void)
252 {
253  rpl_instance_t *instance;
254 
255  instance = rpl_get_default_instance();
256 
257  if(instance == NULL) {
258  return 0;
259  }
260 
261  if(instance->current_dag &&
262  instance->current_dag->rank == ROOT_RANK(instance)) {
263  return 1;
264  }
265 
266  return 0;
267 }
268 /*---------------------------------------------------------------------------*/
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:129
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Definition: uip.h:1978
static uip_ds6_route_t * route
The next route to use.
Definition: res_routes.c:31
Unicast address structure.
Definition: uip-ds6.h:202
#define NULL
The null pointer.
#define ADDR_TENTATIVE
Possible states for the an address (RFC 4862)
Definition: uip-ds6.h:153
#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
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
uip_ds6_addr_t * uip_ds6_addr_add(uip_ipaddr_t *ipaddr, unsigned long vlifetime, uint8_t type)
Add a unicast address to the interface.
Definition: uip-ds6.c:326
A set of debugging macros for the IP stack
CCIF uip_lladdr_t uip_lladdr
Host L2 address.
Definition: uip.c:118
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC3513 i.e.
Definition: uip.h:2019
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:71
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