Contiki 3.x
rpl-icmp6.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, 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 /**
34  * \file
35  * ICMP6 I/O for RPL control messages.
36  *
37  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
38  * Contributors: Niclas Finne <nfi@sics.se>, Joel Hoglund <joel@sics.se>,
39  * Mathieu Pouillot <m.pouillot@watteco.com>
40  * George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
41  */
42 
43 /**
44  * \addtogroup uip6
45  * @{
46  */
47 
48 #include "net/ip/tcpip.h"
49 #include "net/ip/uip.h"
50 #include "net/ipv6/uip-ds6.h"
51 #include "net/ipv6/uip-nd6.h"
52 #include "net/ipv6/uip-icmp6.h"
53 #include "net/rpl/rpl-private.h"
54 #include "net/packetbuf.h"
56 
57 #include <limits.h>
58 #include <string.h>
59 
60 #define DEBUG DEBUG_NONE
61 
62 #include "net/ip/uip-debug.h"
63 
64 #if UIP_CONF_IPV6
65 /*---------------------------------------------------------------------------*/
66 #define RPL_DIO_GROUNDED 0x80
67 #define RPL_DIO_MOP_SHIFT 3
68 #define RPL_DIO_MOP_MASK 0x3c
69 #define RPL_DIO_PREFERENCE_MASK 0x07
70 
71 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
72 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
73 #define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len])
74 /*---------------------------------------------------------------------------*/
75 static void dis_input(void);
76 static void dio_input(void);
77 static void dao_input(void);
78 static void dao_ack_input(void);
79 
80 /* some debug callbacks useful when debugging RPL networks */
81 #ifdef RPL_DEBUG_DIO_INPUT
82 void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *);
83 #endif
84 
85 #ifdef RPL_DEBUG_DAO_OUTPUT
86 void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
87 #endif
88 
89 static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
90 
91 extern rpl_of_t RPL_OF;
92 
93 #if RPL_CONF_MULTICAST
94 static uip_mcast6_route_t *mcast_group;
95 #endif
96 /*---------------------------------------------------------------------------*/
97 /* Initialise RPL ICMPv6 message handlers */
98 UIP_ICMP6_HANDLER(dis_handler, ICMP6_RPL, RPL_CODE_DIS, dis_input);
99 UIP_ICMP6_HANDLER(dio_handler, ICMP6_RPL, RPL_CODE_DIO, dio_input);
100 UIP_ICMP6_HANDLER(dao_handler, ICMP6_RPL, RPL_CODE_DAO, dao_input);
101 UIP_ICMP6_HANDLER(dao_ack_handler, ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_input);
102 /*---------------------------------------------------------------------------*/
103 static int
104 get_global_addr(uip_ipaddr_t *addr)
105 {
106  int i;
107  int state;
108 
109  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
110  state = uip_ds6_if.addr_list[i].state;
111  if(uip_ds6_if.addr_list[i].isused &&
112  (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
113  if(!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
114  memcpy(addr, &uip_ds6_if.addr_list[i].ipaddr, sizeof(uip_ipaddr_t));
115  return 1;
116  }
117  }
118  }
119  return 0;
120 }
121 /*---------------------------------------------------------------------------*/
122 static uint32_t
123 get32(uint8_t *buffer, int pos)
124 {
125  return (uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
126  (uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3];
127 }
128 /*---------------------------------------------------------------------------*/
129 static void
130 set32(uint8_t *buffer, int pos, uint32_t value)
131 {
132  buffer[pos++] = value >> 24;
133  buffer[pos++] = (value >> 16) & 0xff;
134  buffer[pos++] = (value >> 8) & 0xff;
135  buffer[pos++] = value & 0xff;
136 }
137 /*---------------------------------------------------------------------------*/
138 static uint16_t
139 get16(uint8_t *buffer, int pos)
140 {
141  return (uint16_t)buffer[pos] << 8 | buffer[pos + 1];
142 }
143 /*---------------------------------------------------------------------------*/
144 static void
145 set16(uint8_t *buffer, int pos, uint16_t value)
146 {
147  buffer[pos++] = value >> 8;
148  buffer[pos++] = value & 0xff;
149 }
150 /*---------------------------------------------------------------------------*/
151 static void
152 dis_input(void)
153 {
154  rpl_instance_t *instance;
155  rpl_instance_t *end;
156 
157  /* DAG Information Solicitation */
158  PRINTF("RPL: Received a DIS from ");
159  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
160  PRINTF("\n");
161 
162  for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
163  instance < end; ++instance) {
164  if(instance->used == 1) {
165 #if RPL_LEAF_ONLY
166  if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
167  PRINTF("RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n");
168 #else /* !RPL_LEAF_ONLY */
169  if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
170  PRINTF("RPL: Multicast DIS => reset DIO timer\n");
171  rpl_reset_dio_timer(instance);
172  } else {
173 #endif /* !RPL_LEAF_ONLY */
174  PRINTF("RPL: Unicast DIS, reply to sender\n");
175  dio_output(instance, &UIP_IP_BUF->srcipaddr);
176  }
177  }
178  }
179  uip_len = 0;
180 }
181 /*---------------------------------------------------------------------------*/
182 void
183 dis_output(uip_ipaddr_t *addr)
184 {
185  unsigned char *buffer;
186  uip_ipaddr_t tmpaddr;
187 
188  /*
189  * DAG Information Solicitation - 2 bytes reserved
190  * 0 1 2
191  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
192  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
193  * | Flags | Reserved | Option(s)...
194  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195  */
196 
197  buffer = UIP_ICMP_PAYLOAD;
198  buffer[0] = buffer[1] = 0;
199 
200  if(addr == NULL) {
201  uip_create_linklocal_rplnodes_mcast(&tmpaddr);
202  addr = &tmpaddr;
203  }
204 
205  PRINTF("RPL: Sending a DIS to ");
206  PRINT6ADDR(addr);
207  PRINTF("\n");
208 
209  uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIS, 2);
210 }
211 /*---------------------------------------------------------------------------*/
212 static void
213 dio_input(void)
214 {
215  unsigned char *buffer;
216  uint8_t buffer_length;
217  rpl_dio_t dio;
218  uint8_t subopt_type;
219  int i;
220  int len;
221  uip_ipaddr_t from;
222  uip_ds6_nbr_t *nbr;
223 
224  memset(&dio, 0, sizeof(dio));
225 
226  /* Set default values in case the DIO configuration option is missing. */
227  dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
228  dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
229  dio.dag_redund = RPL_DIO_REDUNDANCY;
230  dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
231  dio.dag_max_rankinc = RPL_MAX_RANKINC;
232  dio.ocp = RPL_OF.ocp;
233  dio.default_lifetime = RPL_DEFAULT_LIFETIME;
234  dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
235 
236  uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);
237 
238  /* DAG Information Object */
239  PRINTF("RPL: Received a DIO from ");
240  PRINT6ADDR(&from);
241  PRINTF("\n");
242 
243  if((nbr = uip_ds6_nbr_lookup(&from)) == NULL) {
244  if((nbr = uip_ds6_nbr_add(&from, (uip_lladdr_t *)
245  packetbuf_addr(PACKETBUF_ADDR_SENDER),
246  0, NBR_REACHABLE)) != NULL) {
247  /* set reachable timer */
248  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
249  PRINTF("RPL: Neighbor added to neighbor cache ");
250  PRINT6ADDR(&from);
251  PRINTF(", ");
252  PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
253  PRINTF("\n");
254  } else {
255  PRINTF("RPL: Out of memory, dropping DIO from ");
256  PRINT6ADDR(&from);
257  PRINTF(", ");
258  PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
259  PRINTF("\n");
260  return;
261  }
262  } else {
263  PRINTF("RPL: Neighbor already in neighbor cache\n");
264  }
265 
266  buffer_length = uip_len - uip_l3_icmp_hdr_len;
267 
268  /* Process the DIO base option. */
269  i = 0;
270  buffer = UIP_ICMP_PAYLOAD;
271 
272  dio.instance_id = buffer[i++];
273  dio.version = buffer[i++];
274  dio.rank = get16(buffer, i);
275  i += 2;
276 
277  PRINTF("RPL: Incoming DIO (id, ver, rank) = (%u,%u,%u)\n",
278  (unsigned)dio.instance_id,
279  (unsigned)dio.version,
280  (unsigned)dio.rank);
281 
282  dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
283  dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
284  dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;
285 
286  dio.dtsn = buffer[i++];
287  /* two reserved bytes */
288  i += 2;
289 
290  memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
291  i += sizeof(dio.dag_id);
292 
293  PRINTF("RPL: Incoming DIO (dag_id, pref) = (");
294  PRINT6ADDR(&dio.dag_id);
295  PRINTF(", %u)\n", dio.preference);
296 
297  /* Check if there are any DIO suboptions. */
298  for(; i < buffer_length; i += len) {
299  subopt_type = buffer[i];
300  if(subopt_type == RPL_OPTION_PAD1) {
301  len = 1;
302  } else {
303  /* Suboption with a two-byte header + payload */
304  len = 2 + buffer[i + 1];
305  }
306 
307  if(len + i > buffer_length) {
308  PRINTF("RPL: Invalid DIO packet\n");
309  RPL_STAT(rpl_stats.malformed_msgs++);
310  return;
311  }
312 
313  PRINTF("RPL: DIO option %u, length: %u\n", subopt_type, len - 2);
314 
315  switch(subopt_type) {
316  case RPL_OPTION_DAG_METRIC_CONTAINER:
317  if(len < 6) {
318  PRINTF("RPL: Invalid DAG MC, len = %d\n", len);
319  RPL_STAT(rpl_stats.malformed_msgs++);
320  return;
321  }
322  dio.mc.type = buffer[i + 2];
323  dio.mc.flags = buffer[i + 3] << 1;
324  dio.mc.flags |= buffer[i + 4] >> 7;
325  dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
326  dio.mc.prec = buffer[i + 4] & 0xf;
327  dio.mc.length = buffer[i + 5];
328 
329  if(dio.mc.type == RPL_DAG_MC_NONE) {
330  /* No metric container: do nothing */
331  } else if(dio.mc.type == RPL_DAG_MC_ETX) {
332  dio.mc.obj.etx = get16(buffer, i + 6);
333 
334  PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
335  (unsigned)dio.mc.type,
336  (unsigned)dio.mc.flags,
337  (unsigned)dio.mc.aggr,
338  (unsigned)dio.mc.prec,
339  (unsigned)dio.mc.length,
340  (unsigned)dio.mc.obj.etx);
341  } else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
342  dio.mc.obj.energy.flags = buffer[i + 6];
343  dio.mc.obj.energy.energy_est = buffer[i + 7];
344  } else {
345  PRINTF("RPL: Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type);
346  return;
347  }
348  break;
349  case RPL_OPTION_ROUTE_INFO:
350  if(len < 9) {
351  PRINTF("RPL: Invalid destination prefix option, len = %d\n", len);
352  RPL_STAT(rpl_stats.malformed_msgs++);
353  return;
354  }
355 
356  /* The flags field includes the preference value. */
357  dio.destination_prefix.length = buffer[i + 2];
358  dio.destination_prefix.flags = buffer[i + 3];
359  dio.destination_prefix.lifetime = get32(buffer, i + 4);
360 
361  if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
362  dio.destination_prefix.length <= 128) {
363  PRINTF("RPL: Copying destination prefix\n");
364  memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
365  (dio.destination_prefix.length + 7) / 8);
366  } else {
367  PRINTF("RPL: Invalid route info option, len = %d\n", len);
368  RPL_STAT(rpl_stats.malformed_msgs++);
369  return;
370  }
371 
372  break;
373  case RPL_OPTION_DAG_CONF:
374  if(len != 16) {
375  PRINTF("RPL: Invalid DAG configuration option, len = %d\n", len);
376  RPL_STAT(rpl_stats.malformed_msgs++);
377  return;
378  }
379 
380  /* Path control field not yet implemented - at i + 2 */
381  dio.dag_intdoubl = buffer[i + 3];
382  dio.dag_intmin = buffer[i + 4];
383  dio.dag_redund = buffer[i + 5];
384  dio.dag_max_rankinc = get16(buffer, i + 6);
385  dio.dag_min_hoprankinc = get16(buffer, i + 8);
386  dio.ocp = get16(buffer, i + 10);
387  /* buffer + 12 is reserved */
388  dio.default_lifetime = buffer[i + 13];
389  dio.lifetime_unit = get16(buffer, i + 14);
390  PRINTF("RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
391  dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
392  dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
393  dio.default_lifetime, dio.lifetime_unit);
394  break;
395  case RPL_OPTION_PREFIX_INFO:
396  if(len != 32) {
397  PRINTF("RPL: Invalid DAG prefix info, len != 32\n");
398  RPL_STAT(rpl_stats.malformed_msgs++);
399  return;
400  }
401  dio.prefix_info.length = buffer[i + 2];
402  dio.prefix_info.flags = buffer[i + 3];
403  /* valid lifetime is ingnored for now - at i + 4 */
404  /* preferred lifetime stored in lifetime */
405  dio.prefix_info.lifetime = get32(buffer, i + 8);
406  /* 32-bit reserved at i + 12 */
407  PRINTF("RPL: Copying prefix information\n");
408  memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
409  break;
410  default:
411  PRINTF("RPL: Unsupported suboption type in DIO: %u\n",
412  (unsigned)subopt_type);
413  }
414  }
415 
416 #ifdef RPL_DEBUG_DIO_INPUT
417  RPL_DEBUG_DIO_INPUT(&from, &dio);
418 #endif
419 
420  rpl_process_dio(&from, &dio);
421 
422  uip_len = 0;
423 }
424 /*---------------------------------------------------------------------------*/
425 void
426 dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
427 {
428  unsigned char *buffer;
429  int pos;
430  rpl_dag_t *dag = instance->current_dag;
431 #if !RPL_LEAF_ONLY
432  uip_ipaddr_t addr;
433 #endif /* !RPL_LEAF_ONLY */
434 
435 #if RPL_LEAF_ONLY
436  /* In leaf mode, we only send DIO messages as unicasts in response to
437  unicast DIS messages. */
438  if(uc_addr == NULL) {
439  PRINTF("RPL: LEAF ONLY have multicast addr: skip dio_output\n");
440  return;
441  }
442 #endif /* RPL_LEAF_ONLY */
443 
444  /* DAG Information Object */
445  pos = 0;
446 
447  buffer = UIP_ICMP_PAYLOAD;
448  buffer[pos++] = instance->instance_id;
449  buffer[pos++] = dag->version;
450 
451 #if RPL_LEAF_ONLY
452  PRINTF("RPL: LEAF ONLY DIO rank set to INFINITE_RANK\n");
453  set16(buffer, pos, INFINITE_RANK);
454 #else /* RPL_LEAF_ONLY */
455  set16(buffer, pos, dag->rank);
456 #endif /* RPL_LEAF_ONLY */
457  pos += 2;
458 
459  buffer[pos] = 0;
460  if(dag->grounded) {
461  buffer[pos] |= RPL_DIO_GROUNDED;
462  }
463 
464  buffer[pos] |= instance->mop << RPL_DIO_MOP_SHIFT;
465  buffer[pos] |= dag->preference & RPL_DIO_PREFERENCE_MASK;
466  pos++;
467 
468  buffer[pos++] = instance->dtsn_out;
469 
470  /* always request new DAO to refresh route */
471  RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
472 
473  /* reserved 2 bytes */
474  buffer[pos++] = 0; /* flags */
475  buffer[pos++] = 0; /* reserved */
476 
477  memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
478  pos += 16;
479 
480 #if !RPL_LEAF_ONLY
481  if(instance->mc.type != RPL_DAG_MC_NONE) {
482  instance->of->update_metric_container(instance);
483 
484  buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
485  buffer[pos++] = 6;
486  buffer[pos++] = instance->mc.type;
487  buffer[pos++] = instance->mc.flags >> 1;
488  buffer[pos] = (instance->mc.flags & 1) << 7;
489  buffer[pos++] |= (instance->mc.aggr << 4) | instance->mc.prec;
490  if(instance->mc.type == RPL_DAG_MC_ETX) {
491  buffer[pos++] = 2;
492  set16(buffer, pos, instance->mc.obj.etx);
493  pos += 2;
494  } else if(instance->mc.type == RPL_DAG_MC_ENERGY) {
495  buffer[pos++] = 2;
496  buffer[pos++] = instance->mc.obj.energy.flags;
497  buffer[pos++] = instance->mc.obj.energy.energy_est;
498  } else {
499  PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type %u\n",
500  (unsigned)instance->mc.type);
501  return;
502  }
503  }
504 #endif /* !RPL_LEAF_ONLY */
505 
506  /* Always add a DAG configuration option. */
507  buffer[pos++] = RPL_OPTION_DAG_CONF;
508  buffer[pos++] = 14;
509  buffer[pos++] = 0; /* No Auth, PCS = 0 */
510  buffer[pos++] = instance->dio_intdoubl;
511  buffer[pos++] = instance->dio_intmin;
512  buffer[pos++] = instance->dio_redundancy;
513  set16(buffer, pos, instance->max_rankinc);
514  pos += 2;
515  set16(buffer, pos, instance->min_hoprankinc);
516  pos += 2;
517  /* OCP is in the DAG_CONF option */
518  set16(buffer, pos, instance->of->ocp);
519  pos += 2;
520  buffer[pos++] = 0; /* reserved */
521  buffer[pos++] = instance->default_lifetime;
522  set16(buffer, pos, instance->lifetime_unit);
523  pos += 2;
524 
525  /* Check if we have a prefix to send also. */
526  if(dag->prefix_info.length > 0) {
527  buffer[pos++] = RPL_OPTION_PREFIX_INFO;
528  buffer[pos++] = 30; /* always 30 bytes + 2 long */
529  buffer[pos++] = dag->prefix_info.length;
530  buffer[pos++] = dag->prefix_info.flags;
531  set32(buffer, pos, dag->prefix_info.lifetime);
532  pos += 4;
533  set32(buffer, pos, dag->prefix_info.lifetime);
534  pos += 4;
535  memset(&buffer[pos], 0, 4);
536  pos += 4;
537  memcpy(&buffer[pos], &dag->prefix_info.prefix, 16);
538  pos += 16;
539  PRINTF("RPL: Sending prefix info in DIO for ");
540  PRINT6ADDR(&dag->prefix_info.prefix);
541  PRINTF("\n");
542  } else {
543  PRINTF("RPL: No prefix to announce (len %d)\n",
544  dag->prefix_info.length);
545  }
546 
547 #if RPL_LEAF_ONLY
548 #if (DEBUG) & DEBUG_PRINT
549  if(uc_addr == NULL) {
550  PRINTF("RPL: LEAF ONLY sending unicast-DIO from multicast-DIO\n");
551  }
552 #endif /* DEBUG_PRINT */
553  PRINTF("RPL: Sending unicast-DIO with rank %u to ",
554  (unsigned)dag->rank);
555  PRINT6ADDR(uc_addr);
556  PRINTF("\n");
557  uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
558 #else /* RPL_LEAF_ONLY */
559  /* Unicast requests get unicast replies! */
560  if(uc_addr == NULL) {
561  PRINTF("RPL: Sending a multicast-DIO with rank %u\n",
562  (unsigned)instance->current_dag->rank);
563  uip_create_linklocal_rplnodes_mcast(&addr);
564  uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DIO, pos);
565  } else {
566  PRINTF("RPL: Sending unicast-DIO with rank %u to ",
567  (unsigned)instance->current_dag->rank);
568  PRINT6ADDR(uc_addr);
569  PRINTF("\n");
570  uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
571  }
572 #endif /* RPL_LEAF_ONLY */
573 }
574 /*---------------------------------------------------------------------------*/
575 static void
576 dao_input(void)
577 {
578  uip_ipaddr_t dao_sender_addr;
579  rpl_dag_t *dag;
580  rpl_instance_t *instance;
581  unsigned char *buffer;
582  uint16_t sequence;
583  uint8_t instance_id;
584  uint8_t lifetime;
585  uint8_t prefixlen;
586  uint8_t flags;
587  uint8_t subopt_type;
588  /*
589  uint8_t pathcontrol;
590  uint8_t pathsequence;
591  */
592  uip_ipaddr_t prefix;
593  uip_ds6_route_t *rep;
594  uint8_t buffer_length;
595  int pos;
596  int len;
597  int i;
598  int learned_from;
599  rpl_parent_t *parent;
600  uip_ds6_nbr_t *nbr;
601 
602  prefixlen = 0;
603  parent = NULL;
604 
605  uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
606 
607  /* Destination Advertisement Object */
608  PRINTF("RPL: Received a DAO from ");
609  PRINT6ADDR(&dao_sender_addr);
610  PRINTF("\n");
611 
612  buffer = UIP_ICMP_PAYLOAD;
613  buffer_length = uip_len - uip_l3_icmp_hdr_len;
614 
615  pos = 0;
616  instance_id = buffer[pos++];
617 
618  instance = rpl_get_instance(instance_id);
619  if(instance == NULL) {
620  PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
621  instance_id);
622  return;
623  }
624 
625  lifetime = instance->default_lifetime;
626 
627  flags = buffer[pos++];
628  /* reserved */
629  pos++;
630  sequence = buffer[pos++];
631 
632  dag = instance->current_dag;
633  /* Is the DAG ID present? */
634  if(flags & RPL_DAO_D_FLAG) {
635  if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
636  PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
637  return;
638  }
639  pos += 16;
640  }
641 
642  learned_from = uip_is_addr_mcast(&dao_sender_addr) ?
643  RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
644 
645  PRINTF("RPL: DAO from %s\n",
646  learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast");
647  if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
648  /* Check whether this is a DAO forwarding loop. */
649  parent = rpl_find_parent(dag, &dao_sender_addr);
650  /* check if this is a new DAO registration with an "illegal" rank */
651  /* if we already route to this node it is likely */
652  if(parent != NULL &&
653  DAG_RANK(parent->rank, instance) < DAG_RANK(dag->rank, instance)) {
654  PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
655  DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
656  parent->rank = INFINITE_RANK;
657  parent->flags |= RPL_PARENT_FLAG_UPDATED;
658  return;
659  }
660 
661  /* If we get the DAO from our parent, we also have a loop. */
662  if(parent != NULL && parent == dag->preferred_parent) {
663  PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n");
664  parent->rank = INFINITE_RANK;
665  parent->flags |= RPL_PARENT_FLAG_UPDATED;
666  return;
667  }
668  }
669 
670  /* Check if there are any RPL options present. */
671  for(i = pos; i < buffer_length; i += len) {
672  subopt_type = buffer[i];
673  if(subopt_type == RPL_OPTION_PAD1) {
674  len = 1;
675  } else {
676  /* The option consists of a two-byte header and a payload. */
677  len = 2 + buffer[i + 1];
678  }
679 
680  switch(subopt_type) {
681  case RPL_OPTION_TARGET:
682  /* Handle the target option. */
683  prefixlen = buffer[i + 3];
684  memset(&prefix, 0, sizeof(prefix));
685  memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
686  break;
687  case RPL_OPTION_TRANSIT:
688  /* The path sequence and control are ignored. */
689  /* pathcontrol = buffer[i + 3];
690  pathsequence = buffer[i + 4];*/
691  lifetime = buffer[i + 5];
692  /* The parent address is also ignored. */
693  break;
694  }
695  }
696 
697  PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
698  (unsigned)lifetime, (unsigned)prefixlen);
699  PRINT6ADDR(&prefix);
700  PRINTF("\n");
701 
702 #if RPL_CONF_MULTICAST
703  if(uip_is_addr_mcast_global(&prefix)) {
704  mcast_group = uip_mcast6_route_add(&prefix);
705  if(mcast_group) {
706  mcast_group->dag = dag;
707  mcast_group->lifetime = RPL_LIFETIME(instance, lifetime);
708  }
709  goto fwd_dao;
710  }
711 #endif
712 
713  rep = uip_ds6_route_lookup(&prefix);
714 
715  if(lifetime == RPL_ZERO_LIFETIME) {
716  PRINTF("RPL: No-Path DAO received\n");
717  /* No-Path DAO received; invoke the route purging routine. */
718  if(rep != NULL &&
719  rep->state.nopath_received == 0 &&
720  rep->length == prefixlen &&
721  uip_ds6_route_nexthop(rep) != NULL &&
722  uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) {
723  PRINTF("RPL: Setting expiration timer for prefix ");
724  PRINT6ADDR(&prefix);
725  PRINTF("\n");
726  rep->state.nopath_received = 1;
727  rep->state.lifetime = DAO_EXPIRATION_TIMEOUT;
728 
729  /* We forward the incoming no-path DAO to our parent, if we have
730  one. */
731  if(dag->preferred_parent != NULL &&
732  rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) {
733  PRINTF("RPL: Forwarding no-path DAO to parent ");
734  PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
735  PRINTF("\n");
736  uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
737  ICMP6_RPL, RPL_CODE_DAO, buffer_length);
738  }
739  if(flags & RPL_DAO_K_FLAG) {
740  dao_ack_output(instance, &dao_sender_addr, sequence);
741  }
742  }
743  return;
744  }
745 
746  PRINTF("RPL: adding DAO route\n");
747 
748  if((nbr = uip_ds6_nbr_lookup(&dao_sender_addr)) == NULL) {
749  if((nbr = uip_ds6_nbr_add(&dao_sender_addr,
750  (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER),
751  0, NBR_REACHABLE)) != NULL) {
752  /* set reachable timer */
753  stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
754  PRINTF("RPL: Neighbor added to neighbor cache ");
755  PRINT6ADDR(&dao_sender_addr);
756  PRINTF(", ");
757  PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
758  PRINTF("\n");
759  } else {
760  PRINTF("RPL: Out of Memory, dropping DAO from ");
761  PRINT6ADDR(&dao_sender_addr);
762  PRINTF(", ");
763  PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
764  PRINTF("\n");
765  return;
766  }
767  } else {
768  PRINTF("RPL: Neighbor already in neighbor cache\n");
769  }
770 
771  rpl_lock_parent(parent);
772 
773  rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
774  if(rep == NULL) {
775  RPL_STAT(rpl_stats.mem_overflows++);
776  PRINTF("RPL: Could not add a route after receiving a DAO\n");
777  return;
778  }
779 
780  rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
781  rep->state.learned_from = learned_from;
782 
783 #if RPL_CONF_MULTICAST
784 fwd_dao:
785 #endif
786 
787  if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
788  if(dag->preferred_parent != NULL &&
789  rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) {
790  PRINTF("RPL: Forwarding DAO to parent ");
791  PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
792  PRINTF("\n");
793  uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
794  ICMP6_RPL, RPL_CODE_DAO, buffer_length);
795  }
796  if(flags & RPL_DAO_K_FLAG) {
797  dao_ack_output(instance, &dao_sender_addr, sequence);
798  }
799  }
800  uip_len = 0;
801 }
802 /*---------------------------------------------------------------------------*/
803 void
804 dao_output(rpl_parent_t *parent, uint8_t lifetime)
805 {
806  /* Destination Advertisement Object */
807  uip_ipaddr_t prefix;
808 
809  if(get_global_addr(&prefix) == 0) {
810  PRINTF("RPL: No global address set for this node - suppressing DAO\n");
811  return;
812  }
813 
814  /* Sending a DAO with own prefix as target */
815  dao_output_target(parent, &prefix, lifetime);
816 }
817 /*---------------------------------------------------------------------------*/
818 void
819 dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
820 {
821  rpl_dag_t *dag;
822  rpl_instance_t *instance;
823  unsigned char *buffer;
824  uint8_t prefixlen;
825  int pos;
826 
827  /* Destination Advertisement Object */
828 
829  /* If we are in feather mode, we should not send any DAOs */
830  if(rpl_get_mode() == RPL_MODE_FEATHER) {
831  return;
832  }
833 
834  if(parent == NULL) {
835  PRINTF("RPL dao_output_target error parent NULL\n");
836  return;
837  }
838 
839  dag = parent->dag;
840  if(dag == NULL) {
841  PRINTF("RPL dao_output_target error dag NULL\n");
842  return;
843  }
844 
845  instance = dag->instance;
846 
847  if(instance == NULL) {
848  PRINTF("RPL dao_output_target error instance NULL\n");
849  return;
850  }
851  if(prefix == NULL) {
852  PRINTF("RPL dao_output_target error prefix NULL\n");
853  return;
854  }
855 #ifdef RPL_DEBUG_DAO_OUTPUT
856  RPL_DEBUG_DAO_OUTPUT(parent);
857 #endif
858 
859  buffer = UIP_ICMP_PAYLOAD;
860 
861  RPL_LOLLIPOP_INCREMENT(dao_sequence);
862  pos = 0;
863 
864  buffer[pos++] = instance->instance_id;
865  buffer[pos] = 0;
866 #if RPL_DAO_SPECIFY_DAG
867  buffer[pos] |= RPL_DAO_D_FLAG;
868 #endif /* RPL_DAO_SPECIFY_DAG */
869 #if RPL_CONF_DAO_ACK
870  buffer[pos] |= RPL_DAO_K_FLAG;
871 #endif /* RPL_CONF_DAO_ACK */
872  ++pos;
873  buffer[pos++] = 0; /* reserved */
874  buffer[pos++] = dao_sequence;
875 #if RPL_DAO_SPECIFY_DAG
876  memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
877  pos+=sizeof(dag->dag_id);
878 #endif /* RPL_DAO_SPECIFY_DAG */
879 
880  /* create target subopt */
881  prefixlen = sizeof(*prefix) * CHAR_BIT;
882  buffer[pos++] = RPL_OPTION_TARGET;
883  buffer[pos++] = 2 + ((prefixlen + 7) / CHAR_BIT);
884  buffer[pos++] = 0; /* reserved */
885  buffer[pos++] = prefixlen;
886  memcpy(buffer + pos, prefix, (prefixlen + 7) / CHAR_BIT);
887  pos += ((prefixlen + 7) / CHAR_BIT);
888 
889  /* Create a transit information sub-option. */
890  buffer[pos++] = RPL_OPTION_TRANSIT;
891  buffer[pos++] = 4;
892  buffer[pos++] = 0; /* flags - ignored */
893  buffer[pos++] = 0; /* path control - ignored */
894  buffer[pos++] = 0; /* path seq - ignored */
895  buffer[pos++] = lifetime;
896 
897  PRINTF("RPL: Sending DAO with prefix ");
898  PRINT6ADDR(prefix);
899  PRINTF(" to ");
900  PRINT6ADDR(rpl_get_parent_ipaddr(parent));
901  PRINTF("\n");
902 
903  if(rpl_get_parent_ipaddr(parent) != NULL) {
904  uip_icmp6_send(rpl_get_parent_ipaddr(parent), ICMP6_RPL, RPL_CODE_DAO, pos);
905  }
906 }
907 /*---------------------------------------------------------------------------*/
908 static void
909 dao_ack_input(void)
910 {
911 #if DEBUG
912  unsigned char *buffer;
913  uint8_t buffer_length;
914  uint8_t instance_id;
915  uint8_t sequence;
916  uint8_t status;
917 
918  buffer = UIP_ICMP_PAYLOAD;
919  buffer_length = uip_len - uip_l3_icmp_hdr_len;
920 
921  instance_id = buffer[0];
922  sequence = buffer[2];
923  status = buffer[3];
924 
925  PRINTF("RPL: Received a DAO ACK with sequence number %d and status %d from ",
926  sequence, status);
927  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
928  PRINTF("\n");
929 #endif /* DEBUG */
930  uip_len = 0;
931 }
932 /*---------------------------------------------------------------------------*/
933 void
934 dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence)
935 {
936  unsigned char *buffer;
937 
938  PRINTF("RPL: Sending a DAO ACK with sequence number %d to ", sequence);
939  PRINT6ADDR(dest);
940  PRINTF("\n");
941 
942  buffer = UIP_ICMP_PAYLOAD;
943 
944  buffer[0] = instance->instance_id;
945  buffer[1] = 0;
946  buffer[2] = sequence;
947  buffer[3] = 0;
948 
949  uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
950 }
951 /*---------------------------------------------------------------------------*/
952 void
953 rpl_icmp6_register_handlers()
954 {
955  uip_icmp6_register_input_handler(&dis_handler);
956  uip_icmp6_register_input_handler(&dio_handler);
957  uip_icmp6_register_input_handler(&dao_handler);
958  uip_icmp6_register_input_handler(&dao_ack_handler);
959 }
960 /*---------------------------------------------------------------------------*/
961 #endif /* UIP_CONF_IPV6 */
962 
963 /** @}*/
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
An entry in the routing table.
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 3513 a is of type uip_ipaddr_t*
Definition: uip.h:2095
Neighbor discovery (RFC 4861)
#define uip_is_addr_link_local(a)
is addr (a) a link local unicast address, see RFC3513 i.e.
Definition: uip.h:2058
This header file contains configuration directives for uIPv6 multicast support.
Header file for the uIP TCP/IP stack.
Header for the Contiki/uIP interface.
Network interface and stateless autoconfiguration (RFC 4862)
Header file for the Rime buffer (packetbuf) management
#define NULL
The null pointer.
An entry in the multicast routing table.
#define uip_is_addr_mcast_global(a)
is address a global multicast address (FFxE::/16), a is of type uip_ip6addr_t*
Definition: uip.h:2102
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
Register a handler which can handle a specific ICMPv6 message type.
Definition: uip-icmp6.c:117
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:104
#define ICMP6_RPL
RPL.
Definition: uip-icmp6.h:66
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
void uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
Send an icmpv6 message.
Definition: uip-icmp6.c:297
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
#define ADDR_TENTATIVE
Possible states for the an address (RFC 4862)
Definition: uip-ds6.h:123
A set of debugging macros.
uip_ds6_nbr_t * uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr, uint8_t isrouter, uint8_t state)
Neighbor Cache basic routines.
Definition: uip-ds6-nbr.c:81
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:70