Contiki-NG
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  * \addtogroup rpl-lite
35  * @{
36  *
37  * \file
38  * ICMP6 I/O for RPL control messages.
39  *
40  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>,
41  * Simon Duquennoy <simon.duquennoy@inria.fr>
42  * Contributors: Niclas Finne <nfi@sics.se>, Joel Hoglund <joel@sics.se>,
43  * Mathieu Pouillot <m.pouillot@watteco.com>,
44  * George Oikonomou <oikonomou@users.sourceforge.net> (multicast)
45  */
46 
47 #include "net/routing/rpl-lite/rpl.h"
48 #include "net/ipv6/uip-icmp6.h"
49 #include "net/packetbuf.h"
50 #include "lib/random.h"
51 
52 #include <limits.h>
53 
54 /* Log configuration */
55 #include "sys/log.h"
56 #define LOG_MODULE "RPL"
57 #define LOG_LEVEL LOG_LEVEL_RPL
58 
59 /*---------------------------------------------------------------------------*/
60 #define RPL_DIO_GROUNDED 0x80
61 #define RPL_DIO_MOP_SHIFT 3
62 #define RPL_DIO_MOP_MASK 0x38
63 #define RPL_DIO_PREFERENCE_MASK 0x07
64 
65 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
66 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
67 #define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len])
68 
69 /*---------------------------------------------------------------------------*/
70 static void dis_input(void);
71 static void dio_input(void);
72 static void dao_input(void);
73 
74 /*---------------------------------------------------------------------------*/
75 /* Initialize RPL ICMPv6 message handlers */
76 UIP_ICMP6_HANDLER(dis_handler, ICMP6_RPL, RPL_CODE_DIS, dis_input);
77 UIP_ICMP6_HANDLER(dio_handler, ICMP6_RPL, RPL_CODE_DIO, dio_input);
78 UIP_ICMP6_HANDLER(dao_handler, ICMP6_RPL, RPL_CODE_DAO, dao_input);
79 
80 #if RPL_WITH_DAO_ACK
81 static void dao_ack_input(void);
82 UIP_ICMP6_HANDLER(dao_ack_handler, ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_input);
83 #endif /* RPL_WITH_DAO_ACK */
84 
85 /*---------------------------------------------------------------------------*/
86 static uint32_t
87 get32(uint8_t *buffer, int pos)
88 {
89  return ((uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
90  (uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3]);
91 }
92 /*---------------------------------------------------------------------------*/
93 static void
94 set32(uint8_t *buffer, int pos, uint32_t value)
95 {
96  buffer[pos++] = value >> 24;
97  buffer[pos++] = (value >> 16) & 0xff;
98  buffer[pos++] = (value >> 8) & 0xff;
99  buffer[pos++] = value & 0xff;
100 }
101 /*---------------------------------------------------------------------------*/
102 static uint16_t
103 get16(uint8_t *buffer, int pos)
104 {
105  return (uint16_t)buffer[pos] << 8 | buffer[pos + 1];
106 }
107 /*---------------------------------------------------------------------------*/
108 static void
109 set16(uint8_t *buffer, int pos, uint16_t value)
110 {
111  buffer[pos++] = value >> 8;
112  buffer[pos++] = value & 0xff;
113 }
114 /*---------------------------------------------------------------------------*/
116 rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void *data)
117 {
119 
120  if((nbr = uip_ds6_nbr_lookup(from)) == NULL) {
121  if((nbr = uip_ds6_nbr_add(from, (uip_lladdr_t *)
122  packetbuf_addr(PACKETBUF_ADDR_SENDER),
123  0, NBR_REACHABLE, reason, data)) == NULL) {
124  LOG_ERR("could not add neighbor to cache ");
125  LOG_ERR_6ADDR(from);
126  LOG_ERR_(", ");
127  LOG_ERR_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
128  LOG_ERR_("\n");
129  }
130  }
131 
132  return nbr;
133 }
134 /*---------------------------------------------------------------------------*/
135 static void
136 dis_input(void)
137 {
138  if(!curr_instance.used) {
139  LOG_WARN("dis_input: not in an instance yet, discard\n");
140  goto discard;
141  }
142 
143  LOG_INFO("received a DIS from ");
144  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
145  LOG_INFO_("\n");
146 
147  rpl_process_dis(&UIP_IP_BUF->srcipaddr, uip_is_addr_mcast(&UIP_IP_BUF->destipaddr));
148 
149  discard:
150  uip_clear_buf();
151 }
152 /*---------------------------------------------------------------------------*/
153 void
155 {
156  unsigned char *buffer;
157 
158  /* Make sure we're up-to-date before sending data out */
160 
161  buffer = UIP_ICMP_PAYLOAD;
162  buffer[0] = buffer[1] = 0;
163 
164  if(addr == NULL) {
165  addr = &rpl_multicast_addr;
166  }
167 
168  LOG_INFO("sending a DIS to ");
169  LOG_INFO_6ADDR(addr);
170  LOG_INFO_("\n");
171 
172  uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIS, 2);
173 }
174 /*---------------------------------------------------------------------------*/
175 static void
176 dio_input(void)
177 {
178  unsigned char *buffer;
179  uint8_t buffer_length;
180  rpl_dio_t dio;
181  uint8_t subopt_type;
182  int i;
183  int len;
184  uip_ipaddr_t from;
185 
186  memset(&dio, 0, sizeof(dio));
187 
188  /* Set default values in case the DIO configuration option is missing. */
189  dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
190  dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
191  dio.dag_redund = RPL_DIO_REDUNDANCY;
192  dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
193  dio.dag_max_rankinc = RPL_MAX_RANKINC;
194  dio.ocp = RPL_OF_OCP;
195  dio.default_lifetime = RPL_DEFAULT_LIFETIME;
196  dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
197 
198  uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);
199 
200  buffer_length = uip_len - uip_l3_icmp_hdr_len;
201 
202  /* Process the DIO base option. */
203  i = 0;
204  buffer = UIP_ICMP_PAYLOAD;
205 
206  dio.instance_id = buffer[i++];
207  dio.version = buffer[i++];
208  dio.rank = get16(buffer, i);
209  i += 2;
210 
211  dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
212  dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
213  dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;
214 
215  dio.dtsn = buffer[i++];
216  /* two reserved bytes */
217  i += 2;
218 
219  memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
220  i += sizeof(dio.dag_id);
221 
222  /* Check if there are any DIO suboptions. */
223  for(; i < buffer_length; i += len) {
224  subopt_type = buffer[i];
225  if(subopt_type == RPL_OPTION_PAD1) {
226  len = 1;
227  } else {
228  /* Suboption with a two-byte header + payload */
229  len = 2 + buffer[i + 1];
230  }
231 
232  if(len + i > buffer_length) {
233  LOG_ERR("dio_input: malformed packet, discard\n");
234  goto discard;
235  }
236 
237  switch(subopt_type) {
238  case RPL_OPTION_DAG_METRIC_CONTAINER:
239  if(len < 6) {
240  LOG_WARN("dio_input: invalid DAG MC, len %u, discard\n", len);
241  goto discard;
242  }
243  dio.mc.type = buffer[i + 2];
244  dio.mc.flags = buffer[i + 3] << 1;
245  dio.mc.flags |= buffer[i + 4] >> 7;
246  dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
247  dio.mc.prec = buffer[i + 4] & 0xf;
248  dio.mc.length = buffer[i + 5];
249 
250  if(dio.mc.type == RPL_DAG_MC_NONE) {
251  /* No metric container: do nothing */
252  } else if(dio.mc.type == RPL_DAG_MC_ETX) {
253  dio.mc.obj.etx = get16(buffer, i + 6);
254  } else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
255  dio.mc.obj.energy.flags = buffer[i + 6];
256  dio.mc.obj.energy.energy_est = buffer[i + 7];
257  } else {
258  LOG_WARN("dio_input: unsupported DAG MC type %u, discard\n", (unsigned)dio.mc.type);
259  goto discard;
260  }
261  break;
262  case RPL_OPTION_ROUTE_INFO:
263  if(len < 9) {
264  LOG_WARN("dio_input: invalid destination prefix option, len %u, discard\n", len);
265  goto discard;
266  }
267 
268  /* The flags field includes the preference value. */
269  dio.destination_prefix.length = buffer[i + 2];
270  dio.destination_prefix.flags = buffer[i + 3];
271  dio.destination_prefix.lifetime = get32(buffer, i + 4);
272 
273  if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
274  dio.destination_prefix.length <= 128) {
275  memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
276  (dio.destination_prefix.length + 7) / 8);
277  } else {
278  LOG_WARN("dio_input: invalid route info option, len %u, discard\n", len);
279  goto discard;
280  }
281 
282  break;
283  case RPL_OPTION_DAG_CONF:
284  if(len != 16) {
285  LOG_WARN("dio_input: invalid DAG configuration option, len %u, discard\n", len);
286  goto discard;
287  }
288 
289  /* Path control field not yet implemented - at i + 2 */
290  dio.dag_intdoubl = buffer[i + 3];
291  dio.dag_intmin = buffer[i + 4];
292  dio.dag_redund = buffer[i + 5];
293  dio.dag_max_rankinc = get16(buffer, i + 6);
294  dio.dag_min_hoprankinc = get16(buffer, i + 8);
295  dio.ocp = get16(buffer, i + 10);
296  /* buffer + 12 is reserved */
297  dio.default_lifetime = buffer[i + 13];
298  dio.lifetime_unit = get16(buffer, i + 14);
299  break;
300  case RPL_OPTION_PREFIX_INFO:
301  if(len != 32) {
302  LOG_WARN("dio_input: invalid DAG prefix info, len %u, discard\n", len);
303  goto discard;
304  }
305  dio.prefix_info.length = buffer[i + 2];
306  dio.prefix_info.flags = buffer[i + 3];
307  /* valid lifetime is ingnored for now - at i + 4 */
308  /* preferred lifetime stored in lifetime */
309  dio.prefix_info.lifetime = get32(buffer, i + 8);
310  /* 32-bit reserved at i + 12 */
311  memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
312  break;
313  default:
314  LOG_WARN("dio_input: unsupported suboption type in DIO: %u, discard\n", (unsigned)subopt_type);
315  goto discard;
316  }
317  }
318 
319  LOG_INFO("received a %s-DIO from ",
320  uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) ? "multicast" : "unicast");
321  LOG_INFO_6ADDR(&from);
322  LOG_INFO_(", instance_id %u, DAG ID ", (unsigned)dio.instance_id);
323  LOG_INFO_6ADDR(&dio.dag_id);
324  LOG_INFO_(", version %u, dtsn %u, rank %u\n",
325  (unsigned)dio.version,
326  (unsigned)dio.dtsn,
327  (unsigned)dio.rank);
328 
329  rpl_process_dio(&from, &dio);
330 
331 discard:
332  uip_clear_buf();
333 }
334 /*---------------------------------------------------------------------------*/
335 void
336 rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr)
337 {
338  unsigned char *buffer;
339  int pos;
340  uip_ipaddr_t *addr = uc_addr;
341 
342  /* Make sure we're up-to-date before sending data out */
344 
345  if(rpl_get_leaf_only()) {
346  /* In leaf mode, we only send DIO messages as unicasts in response to
347  unicast DIS messages. */
348  if(uc_addr == NULL) {
349  /* Do not send multicast DIO in leaf mode */
350  return;
351  }
352  }
353 
354  /* DAG Information Object */
355  pos = 0;
356 
357  buffer = UIP_ICMP_PAYLOAD;
358  buffer[pos++] = curr_instance.instance_id;
359  buffer[pos++] = curr_instance.dag.version;
360 
361  if(rpl_get_leaf_only()) {
362  set16(buffer, pos, RPL_INFINITE_RANK);
363  } else {
364  set16(buffer, pos, curr_instance.dag.rank);
365  }
366  pos += 2;
367 
368  buffer[pos] = 0;
369  if(curr_instance.dag.grounded) {
370  buffer[pos] |= RPL_DIO_GROUNDED;
371  }
372 
373  buffer[pos] |= curr_instance.mop << RPL_DIO_MOP_SHIFT;
374  buffer[pos] |= curr_instance.dag.preference & RPL_DIO_PREFERENCE_MASK;
375  pos++;
376 
377  buffer[pos++] = curr_instance.dtsn_out;
378 
379  /* reserved 2 bytes */
380  buffer[pos++] = 0; /* flags */
381  buffer[pos++] = 0; /* reserved */
382 
383  memcpy(buffer + pos, &curr_instance.dag.dag_id, sizeof(curr_instance.dag.dag_id));
384  pos += 16;
385 
386  if(!rpl_get_leaf_only()) {
387  if(curr_instance.mc.type != RPL_DAG_MC_NONE) {
388  buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
389  buffer[pos++] = 6;
390  buffer[pos++] = curr_instance.mc.type;
391  buffer[pos++] = curr_instance.mc.flags >> 1;
392  buffer[pos] = (curr_instance.mc.flags & 1) << 7;
393  buffer[pos++] |= (curr_instance.mc.aggr << 4) | curr_instance.mc.prec;
394  if(curr_instance.mc.type == RPL_DAG_MC_ETX) {
395  buffer[pos++] = 2;
396  set16(buffer, pos, curr_instance.mc.obj.etx);
397  pos += 2;
398  } else if(curr_instance.mc.type == RPL_DAG_MC_ENERGY) {
399  buffer[pos++] = 2;
400  buffer[pos++] = curr_instance.mc.obj.energy.flags;
401  buffer[pos++] = curr_instance.mc.obj.energy.energy_est;
402  } else {
403  LOG_ERR("unable to send DIO because of unsupported DAG MC type %u\n",
404  (unsigned)curr_instance.mc.type);
405  return;
406  }
407  }
408  }
409 
410  /* Always add a DAG configuration option. */
411  buffer[pos++] = RPL_OPTION_DAG_CONF;
412  buffer[pos++] = 14;
413  buffer[pos++] = 0; /* No Auth, PCS = 0 */
414  buffer[pos++] = curr_instance.dio_intdoubl;
415  buffer[pos++] = curr_instance.dio_intmin;
416  buffer[pos++] = curr_instance.dio_redundancy;
417  set16(buffer, pos, curr_instance.max_rankinc);
418  pos += 2;
419  set16(buffer, pos, curr_instance.min_hoprankinc);
420  pos += 2;
421  /* OCP is in the DAG_CONF option */
422  set16(buffer, pos, curr_instance.of->ocp);
423  pos += 2;
424  buffer[pos++] = 0; /* reserved */
425  buffer[pos++] = curr_instance.default_lifetime;
426  set16(buffer, pos, curr_instance.lifetime_unit);
427  pos += 2;
428 
429  /* Check if we have a prefix to send also. */
430  if(curr_instance.dag.prefix_info.length > 0) {
431  buffer[pos++] = RPL_OPTION_PREFIX_INFO;
432  buffer[pos++] = 30; /* always 30 bytes + 2 long */
433  buffer[pos++] = curr_instance.dag.prefix_info.length;
434  buffer[pos++] = curr_instance.dag.prefix_info.flags;
435  set32(buffer, pos, curr_instance.dag.prefix_info.lifetime);
436  pos += 4;
437  set32(buffer, pos, curr_instance.dag.prefix_info.lifetime);
438  pos += 4;
439  memset(&buffer[pos], 0, 4);
440  pos += 4;
441  memcpy(&buffer[pos], &curr_instance.dag.prefix_info.prefix, 16);
442  pos += 16;
443  }
444 
445  if(!rpl_get_leaf_only()) {
446  addr = addr != NULL ? addr : &rpl_multicast_addr;
447  }
448 
449  LOG_INFO("sending a %s-DIO with rank %u to ",
450  uc_addr != NULL ? "unicast" : "multicast",
451  (unsigned)curr_instance.dag.rank);
452  LOG_INFO_6ADDR(addr);
453  LOG_INFO_("\n");
454 
455  uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIO, pos);
456 }
457 /*---------------------------------------------------------------------------*/
458 static void
459 dao_input(void)
460 {
461  struct rpl_dao dao;
462  uint8_t subopt_type;
463  unsigned char *buffer;
464  uint8_t buffer_length;
465  int pos;
466  int len;
467  int i;
468  uip_ipaddr_t from;
469 
470  memset(&dao, 0, sizeof(dao));
471 
472  dao.instance_id = UIP_ICMP_PAYLOAD[0];
473  if(!curr_instance.used || curr_instance.instance_id != dao.instance_id) {
474  LOG_ERR("dao_input: unknown RPL instance %u, discard\n", dao.instance_id);
475  goto discard;
476  }
477 
478  uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);
479  memset(&dao.parent_addr, 0, 16);
480 
481  buffer = UIP_ICMP_PAYLOAD;
482  buffer_length = uip_len - uip_l3_icmp_hdr_len;
483 
484  pos = 0;
485  pos++; /* instance ID */
486  dao.lifetime = curr_instance.default_lifetime;
487  dao.flags = buffer[pos++];
488  pos++; /* reserved */
489  dao.sequence = buffer[pos++];
490 
491  /* Is the DAG ID present? */
492  if(dao.flags & RPL_DAO_D_FLAG) {
493  if(memcmp(&curr_instance.dag.dag_id, &buffer[pos], sizeof(curr_instance.dag.dag_id))) {
494  LOG_ERR("dao_input: different DAG ID ");
495  LOG_ERR_6ADDR((uip_ipaddr_t *)&buffer[pos]);
496  LOG_ERR_(", discard\n");
497  goto discard;
498  }
499  pos += 16;
500  }
501 
502  /* Check if there are any RPL options present. */
503  for(i = pos; i < buffer_length; i += len) {
504  subopt_type = buffer[i];
505  if(subopt_type == RPL_OPTION_PAD1) {
506  len = 1;
507  } else {
508  /* The option consists of a two-byte header and a payload. */
509  len = 2 + buffer[i + 1];
510  }
511 
512  switch(subopt_type) {
513  case RPL_OPTION_TARGET:
514  /* Handle the target option. */
515  dao.prefixlen = buffer[i + 3];
516  memset(&dao.prefix, 0, sizeof(dao.prefix));
517  memcpy(&dao.prefix, buffer + i + 4, (dao.prefixlen + 7) / CHAR_BIT);
518  break;
519  case RPL_OPTION_TRANSIT:
520  /* The path sequence and control are ignored. */
521  /* pathcontrol = buffer[i + 3];
522  pathsequence = buffer[i + 4];*/
523  dao.lifetime = buffer[i + 5];
524  if(len >= 20) {
525  memcpy(&dao.parent_addr, buffer + i + 6, 16);
526  }
527  break;
528  }
529  }
530 
531  /* Destination Advertisement Object */
532  LOG_INFO("received a %sDAO from ", dao.lifetime == 0 ? "No-path " : "");
533  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
534  LOG_INFO_(", seqno %u, lifetime %u, prefix ", dao.sequence, dao.lifetime);
535  LOG_INFO_6ADDR(&dao.prefix);
536  LOG_INFO_(", prefix length %u, parent ", dao.prefixlen);
537  LOG_INFO_6ADDR(&dao.parent_addr);
538  LOG_INFO_(" \n");
539 
540  rpl_process_dao(&from, &dao);
541 
542  discard:
543  uip_clear_buf();
544 }
545 /*---------------------------------------------------------------------------*/
546 void
547 rpl_icmp6_dao_output(uint8_t lifetime)
548 {
549  unsigned char *buffer;
550  uint8_t prefixlen;
551  int pos;
552  const uip_ipaddr_t *prefix = rpl_get_global_address();
553  uip_ipaddr_t *parent_ipaddr = rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent);
554 
555  /* Make sure we're up-to-date before sending data out */
557 
558  if(!curr_instance.used) {
559  LOG_WARN("rpl_icmp6_dao_output: not in an instance, skip sending DAO\n");
560  return;
561  }
562 
563  if(curr_instance.dag.preferred_parent == NULL) {
564  LOG_WARN("rpl_icmp6_dao_output: no preferred parent, skip sending DAO\n");
565  return;
566  }
567 
568  if(prefix == NULL || parent_ipaddr == NULL || curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
569  LOG_WARN("rpl_icmp6_dao_output: node not ready to send a DAO (prefix %p, parent addr %p, mop %u)\n",
570  prefix, parent_ipaddr, curr_instance.mop);
571  return;
572  }
573 
574  buffer = UIP_ICMP_PAYLOAD;
575  pos = 0;
576 
577  buffer[pos++] = curr_instance.instance_id;
578  buffer[pos] = 0;
579 #if RPL_WITH_DAO_ACK
580  if(lifetime != 0) {
581  buffer[pos] |= RPL_DAO_K_FLAG;
582  }
583 #endif /* RPL_WITH_DAO_ACK */
584  ++pos;
585  buffer[pos++] = 0; /* reserved */
586  buffer[pos++] = curr_instance.dag.dao_curr_seqno;
587 
588  /* create target subopt */
589  prefixlen = sizeof(*prefix) * CHAR_BIT;
590  buffer[pos++] = RPL_OPTION_TARGET;
591  buffer[pos++] = 2 + ((prefixlen + 7) / CHAR_BIT);
592  buffer[pos++] = 0; /* reserved */
593  buffer[pos++] = prefixlen;
594  memcpy(buffer + pos, prefix, (prefixlen + 7) / CHAR_BIT);
595  pos += ((prefixlen + 7) / CHAR_BIT);
596 
597  /* Create a transit information sub-option. */
598  buffer[pos++] = RPL_OPTION_TRANSIT;
599  buffer[pos++] = 20;
600  buffer[pos++] = 0; /* flags - ignored */
601  buffer[pos++] = 0; /* path control - ignored */
602  buffer[pos++] = 0; /* path seq - ignored */
603  buffer[pos++] = lifetime;
604 
605  /* Include parent global IP address */
606  memcpy(buffer + pos, &curr_instance.dag.dag_id, 8); /* Prefix */
607  pos += 8;
608  memcpy(buffer + pos, ((const unsigned char *)parent_ipaddr) + 8, 8); /* Interface identifier */
609  pos += 8;
610 
611  LOG_INFO("sending a %sDAO seqno %u, tx count %u, lifetime %u, prefix ",
612  lifetime == 0 ? "No-path " : "",
613  curr_instance.dag.dao_curr_seqno, curr_instance.dag.dao_transmissions, lifetime);
614  LOG_INFO_6ADDR(prefix);
615  LOG_INFO_(" to ");
616  LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
617  LOG_INFO_(", parent ");
618  LOG_INFO_6ADDR(parent_ipaddr);
619  LOG_INFO_("\n");
620 
621  /* Send DAO to root (IPv6 address is DAG ID) */
622  uip_icmp6_send(&curr_instance.dag.dag_id, ICMP6_RPL, RPL_CODE_DAO, pos);
623 }
624 #if RPL_WITH_DAO_ACK
625 /*---------------------------------------------------------------------------*/
626 static void
627 dao_ack_input(void)
628 {
629  uint8_t *buffer;
630  uint8_t instance_id;
631  uint8_t sequence;
632  uint8_t status;
633 
634  buffer = UIP_ICMP_PAYLOAD;
635 
636  instance_id = buffer[0];
637  sequence = buffer[2];
638  status = buffer[3];
639 
640  if(!curr_instance.used || curr_instance.instance_id != instance_id) {
641  LOG_ERR("dao_ack_input: unknown instance, discard\n");
642  goto discard;
643  }
644 
645  LOG_INFO("received a DAO-%s with seqno %d (%d %d) and status %d from ",
646  status < RPL_DAO_ACK_UNABLE_TO_ACCEPT ? "ACK" : "NACK", sequence,
647  curr_instance.dag.dao_curr_seqno, curr_instance.dag.dao_curr_seqno, status);
648  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
649  LOG_INFO_("\n");
650 
651  rpl_process_dao_ack(sequence, status);
652 
653  discard:
654  uip_clear_buf();
655 }
656 /*---------------------------------------------------------------------------*/
657 void
658 rpl_icmp6_dao_ack_output(uip_ipaddr_t *dest, uint8_t sequence, uint8_t status)
659 {
660  unsigned char *buffer;
661 
662  /* Make sure we're up-to-date before sending data out */
664 
665  buffer = UIP_ICMP_PAYLOAD;
666  buffer[0] = curr_instance.instance_id;
667  buffer[1] = 0;
668  buffer[2] = sequence;
669  buffer[3] = status;
670 
671  LOG_INFO("sending a DAO-%s seqno %d to ",
672  status < RPL_DAO_ACK_UNABLE_TO_ACCEPT ? "ACK" : "NACK", sequence);
673  LOG_INFO_6ADDR(dest);
674  LOG_INFO_(" with status %d\n", status);
675 
676  uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
677 }
678 #endif /* RPL_WITH_DAO_ACK */
679 /*---------------------------------------------------------------------------*/
680 void
682 {
683  uip_icmp6_register_input_handler(&dis_handler);
684  uip_icmp6_register_input_handler(&dio_handler);
685  uip_icmp6_register_input_handler(&dao_handler);
686 #if RPL_WITH_DAO_ACK
687  uip_icmp6_register_input_handler(&dao_ack_handler);
688 #endif /* RPL_WITH_DAO_ACK */
689 }
690 /*---------------------------------------------------------------------------*/
691 
692 /** @}*/
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:97
Header file for ICMPv6 message and error handing (RFC 4443)
uip_ipaddr_t * rpl_neighbor_get_ipaddr(rpl_nbr_t *nbr)
Returns a neighbor&#39;s (link-local) IPv6 address.
Definition: rpl-neighbor.c:249
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:115
void rpl_process_dao(uip_ipaddr_t *from, rpl_dao_t *dao)
Processes incoming DAO.
Definition: rpl-dag.c:627
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:179
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:116
uint8_t rpl_get_leaf_only(void)
Get the value of the rpl_leaf_only flag.
Definition: rpl.c:239
void rpl_icmp6_dao_output(uint8_t lifetime)
Creates an ICMPv6 DAO packet and sends it to the root, advertising the current preferred parent...
Definition: rpl-icmp6.c:547
void rpl_process_dao_ack(uint8_t sequence, uint8_t status)
Processes incoming DAO-ACK.
void rpl_process_dis(uip_ipaddr_t *from, int is_multicast)
Processes incoming DIS.
Definition: rpl-dag.c:613
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1018
uip_ds6_nbr_t * rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void *data)
Updates IPv6 neighbor cache on incoming link-local RPL ICMPv6 messages.
Definition: rpl-icmp6.c:197
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 4291 a is of type uip_ipaddr_t*
Definition: uip.h:2107
const uip_ipaddr_t * rpl_get_global_address(void)
Get one of the node&#39;s global addresses.
Definition: rpl.c:71
void rpl_icmp6_dao_ack_output(uip_ipaddr_t *dest, uint8_t sequence, uint8_t status)
Creates an ICMPv6 DAO-ACK packet and sends it to the originator of the ACK.
uip_ds6_nbr_t * uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr, uint8_t isrouter, uint8_t state, nbr_table_reason_t reason, void *data)
Neighbor Cache basic routines.
Definition: uip-ds6-nbr.c:74
void rpl_dag_update_state(void)
Updates RPL internal state: selects preferred parent, updates rank & metreic container, triggers control traffic accordingly and updates uIP6 internal state.
Definition: rpl-dag.c:264
void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
Processes incoming DIO.
Definition: rpl-dag.c:1454
#define ICMP6_RPL
RPL.
Definition: uip-icmp6.h:66
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:106
Header file for the Packet buffer (packetbuf) management
void uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
Send an icmpv6 message.
Definition: uip-icmp6.c:254
void rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr)
Creates an ICMPv6 DIO packet and sends it.
Definition: rpl-icmp6.c:336
Header file for the logging system
void rpl_icmp6_init()
Initializes rpl-icmp6 module, registers ICMPv6 handlers for all RPL ICMPv6 messages: DIO...
Definition: rpl-icmp6.c:681
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:69
void rpl_icmp6_dis_output(uip_ipaddr_t *addr)
Creates an ICMPv6 DIS packet and sends it.
Definition: rpl-icmp6.c:154