48 #include "net/ipv6/uip-ds6.h"
49 #include "net/ipv6/uip-nd6.h"
51 #include "net/rpl/rpl-private.h"
58 #define DEBUG DEBUG_NONE
64 #define RPL_DIO_GROUNDED 0x80
65 #define RPL_DIO_MOP_SHIFT 3
66 #define RPL_DIO_MOP_MASK 0x3c
67 #define RPL_DIO_PREFERENCE_MASK 0x07
69 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
70 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
71 #define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len])
73 static void dis_input(
void);
74 static void dio_input(
void);
75 static void dao_input(
void);
76 static void dao_ack_input(
void);
79 #ifdef RPL_DEBUG_DIO_INPUT
80 void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *,
rpl_dio_t *);
83 #ifdef RPL_DEBUG_DAO_OUTPUT
84 void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
87 static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
91 #if RPL_CONF_MULTICAST
96 get_global_addr(uip_ipaddr_t *addr)
101 for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
102 state = uip_ds6_if.addr_list[i].state;
103 if(uip_ds6_if.addr_list[i].isused &&
104 (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
106 memcpy(addr, &uip_ds6_if.addr_list[i].ipaddr,
sizeof(uip_ipaddr_t));
115 get32(uint8_t *buffer,
int pos)
117 return (uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
118 (uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3];
122 set32(uint8_t *buffer,
int pos, uint32_t value)
124 buffer[pos++] = value >> 24;
125 buffer[pos++] = (value >> 16) & 0xff;
126 buffer[pos++] = (value >> 8) & 0xff;
127 buffer[pos++] = value & 0xff;
131 get16(uint8_t *buffer,
int pos)
133 return (uint16_t)buffer[pos] << 8 | buffer[pos + 1];
137 set16(uint8_t *buffer,
int pos, uint16_t value)
139 buffer[pos++] = value >> 8;
140 buffer[pos++] = value & 0xff;
150 PRINTF(
"RPL: Received a DIS from ");
154 for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
155 instance < end; ++instance) {
156 if(instance->used == 1) {
159 PRINTF(
"RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n");
162 PRINTF(
"RPL: Multicast DIS => reset DIO timer\n");
163 rpl_reset_dio_timer(instance);
166 PRINTF(
"RPL: Unicast DIS, reply to sender\n");
174 dis_output(uip_ipaddr_t *addr)
176 unsigned char *buffer;
177 uip_ipaddr_t tmpaddr;
188 buffer = UIP_ICMP_PAYLOAD;
189 buffer[0] = buffer[1] = 0;
192 uip_create_linklocal_rplnodes_mcast(&tmpaddr);
196 PRINTF(
"RPL: Sending a DIS to ");
206 unsigned char *buffer;
207 uint8_t buffer_length;
215 memset(&dio, 0,
sizeof(dio));
218 dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
219 dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
220 dio.dag_redund = RPL_DIO_REDUNDANCY;
221 dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
222 dio.dag_max_rankinc = RPL_MAX_RANKINC;
223 dio.ocp = RPL_OF.ocp;
224 dio.default_lifetime = RPL_DEFAULT_LIFETIME;
225 dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
230 PRINTF(
"RPL: Received a DIO from ");
236 packetbuf_addr(PACKETBUF_ADDR_SENDER),
237 0, NBR_REACHABLE)) !=
NULL) {
239 stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
240 PRINTF(
"RPL: Neighbor added to neighbor cache ");
243 PRINTLLADDR((
uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
246 PRINTF(
"RPL: Out of memory, dropping DIO from ");
249 PRINTLLADDR((
uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
254 PRINTF(
"RPL: Neighbor already in neighbor cache\n");
257 buffer_length =
uip_len - uip_l3_icmp_hdr_len;
261 buffer = UIP_ICMP_PAYLOAD;
263 dio.instance_id = buffer[i++];
264 dio.version = buffer[i++];
265 dio.rank = get16(buffer, i);
268 PRINTF(
"RPL: Incoming DIO (id, ver, rank) = (%u,%u,%u)\n",
269 (
unsigned)dio.instance_id,
270 (
unsigned)dio.version,
273 dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
274 dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
275 dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;
277 dio.dtsn = buffer[i++];
281 memcpy(&dio.dag_id, buffer + i,
sizeof(dio.dag_id));
282 i +=
sizeof(dio.dag_id);
284 PRINTF(
"RPL: Incoming DIO (dag_id, pref) = (");
285 PRINT6ADDR(&dio.dag_id);
286 PRINTF(
", %u)\n", dio.preference);
289 for(; i < buffer_length; i += len) {
290 subopt_type = buffer[i];
291 if(subopt_type == RPL_OPTION_PAD1) {
295 len = 2 + buffer[i + 1];
298 if(len + i > buffer_length) {
299 PRINTF(
"RPL: Invalid DIO packet\n");
300 RPL_STAT(rpl_stats.malformed_msgs++);
304 PRINTF(
"RPL: DIO option %u, length: %u\n", subopt_type, len - 2);
306 switch(subopt_type) {
307 case RPL_OPTION_DAG_METRIC_CONTAINER:
309 PRINTF(
"RPL: Invalid DAG MC, len = %d\n", len);
310 RPL_STAT(rpl_stats.malformed_msgs++);
313 dio.mc.type = buffer[i + 2];
314 dio.mc.flags = buffer[i + 3] << 1;
315 dio.mc.flags |= buffer[i + 4] >> 7;
316 dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
317 dio.mc.prec = buffer[i + 4] & 0xf;
318 dio.mc.length = buffer[i + 5];
320 if(dio.mc.type == RPL_DAG_MC_NONE) {
322 }
else if(dio.mc.type == RPL_DAG_MC_ETX) {
323 dio.mc.obj.etx = get16(buffer, i + 6);
325 PRINTF(
"RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
326 (
unsigned)dio.mc.type,
327 (
unsigned)dio.mc.flags,
328 (
unsigned)dio.mc.aggr,
329 (
unsigned)dio.mc.prec,
330 (
unsigned)dio.mc.length,
331 (
unsigned)dio.mc.obj.etx);
332 }
else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
333 dio.mc.obj.energy.flags = buffer[i + 6];
334 dio.mc.obj.energy.energy_est = buffer[i + 7];
336 PRINTF(
"RPL: Unhandled DAG MC type: %u\n", (
unsigned)dio.mc.type);
340 case RPL_OPTION_ROUTE_INFO:
342 PRINTF(
"RPL: Invalid destination prefix option, len = %d\n", len);
343 RPL_STAT(rpl_stats.malformed_msgs++);
348 dio.destination_prefix.length = buffer[i + 2];
349 dio.destination_prefix.flags = buffer[i + 3];
350 dio.destination_prefix.lifetime = get32(buffer, i + 4);
352 if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
353 dio.destination_prefix.length <= 128) {
354 PRINTF(
"RPL: Copying destination prefix\n");
355 memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
356 (dio.destination_prefix.length + 7) / 8);
358 PRINTF(
"RPL: Invalid route info option, len = %d\n", len);
359 RPL_STAT(rpl_stats.malformed_msgs++);
364 case RPL_OPTION_DAG_CONF:
366 PRINTF(
"RPL: Invalid DAG configuration option, len = %d\n", len);
367 RPL_STAT(rpl_stats.malformed_msgs++);
372 dio.dag_intdoubl = buffer[i + 3];
373 dio.dag_intmin = buffer[i + 4];
374 dio.dag_redund = buffer[i + 5];
375 dio.dag_max_rankinc = get16(buffer, i + 6);
376 dio.dag_min_hoprankinc = get16(buffer, i + 8);
377 dio.ocp = get16(buffer, i + 10);
379 dio.default_lifetime = buffer[i + 13];
380 dio.lifetime_unit = get16(buffer, i + 14);
381 PRINTF(
"RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
382 dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
383 dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
384 dio.default_lifetime, dio.lifetime_unit);
386 case RPL_OPTION_PREFIX_INFO:
388 PRINTF(
"RPL: Invalid DAG prefix info, len != 32\n");
389 RPL_STAT(rpl_stats.malformed_msgs++);
392 dio.prefix_info.length = buffer[i + 2];
393 dio.prefix_info.flags = buffer[i + 3];
396 dio.prefix_info.lifetime = get32(buffer, i + 8);
398 PRINTF(
"RPL: Copying prefix information\n");
399 memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
402 PRINTF(
"RPL: Unsupported suboption type in DIO: %u\n",
403 (
unsigned)subopt_type);
407 #ifdef RPL_DEBUG_DIO_INPUT
408 RPL_DEBUG_DIO_INPUT(&from, &dio);
411 rpl_process_dio(&from, &dio);
417 unsigned char *buffer;
427 if(uc_addr ==
NULL) {
428 PRINTF(
"RPL: LEAF ONLY have multicast addr: skip dio_output\n");
436 buffer = UIP_ICMP_PAYLOAD;
437 buffer[pos++] = instance->instance_id;
438 buffer[pos++] = dag->version;
441 PRINTF(
"RPL: LEAF ONLY DIO rank set to INFINITE_RANK\n");
442 set16(buffer, pos, INFINITE_RANK);
444 set16(buffer, pos, dag->rank);
450 buffer[pos] |= RPL_DIO_GROUNDED;
453 buffer[pos] |= instance->mop << RPL_DIO_MOP_SHIFT;
454 buffer[pos] |= dag->preference & RPL_DIO_PREFERENCE_MASK;
457 buffer[pos++] = instance->dtsn_out;
460 RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
466 memcpy(buffer + pos, &dag->dag_id,
sizeof(dag->dag_id));
470 if(instance->mc.type != RPL_DAG_MC_NONE) {
473 buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
475 buffer[pos++] = instance->mc.type;
476 buffer[pos++] = instance->mc.flags >> 1;
477 buffer[pos] = (instance->mc.flags & 1) << 7;
478 buffer[pos++] |= (instance->mc.aggr << 4) | instance->mc.prec;
479 if(instance->mc.type == RPL_DAG_MC_ETX) {
481 set16(buffer, pos, instance->mc.obj.etx);
483 }
else if(instance->mc.type == RPL_DAG_MC_ENERGY) {
485 buffer[pos++] = instance->mc.obj.energy.flags;
486 buffer[pos++] = instance->mc.obj.energy.energy_est;
488 PRINTF(
"RPL: Unable to send DIO because of unhandled DAG MC type %u\n",
489 (
unsigned)instance->mc.type);
496 buffer[pos++] = RPL_OPTION_DAG_CONF;
499 buffer[pos++] = instance->dio_intdoubl;
500 buffer[pos++] = instance->dio_intmin;
501 buffer[pos++] = instance->dio_redundancy;
502 set16(buffer, pos, instance->max_rankinc);
504 set16(buffer, pos, instance->min_hoprankinc);
507 set16(buffer, pos, instance->of->ocp);
510 buffer[pos++] = instance->default_lifetime;
511 set16(buffer, pos, instance->lifetime_unit);
515 if(dag->prefix_info.length > 0) {
516 buffer[pos++] = RPL_OPTION_PREFIX_INFO;
518 buffer[pos++] = dag->prefix_info.length;
519 buffer[pos++] = dag->prefix_info.flags;
520 set32(buffer, pos, dag->prefix_info.lifetime);
522 set32(buffer, pos, dag->prefix_info.lifetime);
524 memset(&buffer[pos], 0, 4);
526 memcpy(&buffer[pos], &dag->prefix_info.prefix, 16);
528 PRINTF(
"RPL: Sending prefix info in DIO for ");
529 PRINT6ADDR(&dag->prefix_info.prefix);
532 PRINTF(
"RPL: No prefix to announce (len %d)\n",
533 dag->prefix_info.length);
537 #if (DEBUG) & DEBUG_PRINT
538 if(uc_addr ==
NULL) {
539 PRINTF(
"RPL: LEAF ONLY sending unicast-DIO from multicast-DIO\n");
542 PRINTF(
"RPL: Sending unicast-DIO with rank %u to ",
543 (
unsigned)dag->rank);
549 if(uc_addr ==
NULL) {
550 PRINTF(
"RPL: Sending a multicast-DIO with rank %u\n",
551 (
unsigned)instance->current_dag->rank);
552 uip_create_linklocal_rplnodes_mcast(&addr);
555 PRINTF(
"RPL: Sending unicast-DIO with rank %u to ",
556 (
unsigned)instance->current_dag->rank);
567 uip_ipaddr_t dao_sender_addr;
570 unsigned char *buffer;
583 uint8_t buffer_length;
588 rpl_parent_t *parent;
597 PRINTF(
"RPL: Received a DAO from ");
598 PRINT6ADDR(&dao_sender_addr);
601 buffer = UIP_ICMP_PAYLOAD;
602 buffer_length =
uip_len - uip_l3_icmp_hdr_len;
605 instance_id = buffer[pos++];
607 instance = rpl_get_instance(instance_id);
608 if(instance ==
NULL) {
609 PRINTF(
"RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
614 lifetime = instance->default_lifetime;
616 flags = buffer[pos++];
619 sequence = buffer[pos++];
621 dag = instance->current_dag;
623 if(flags & RPL_DAO_D_FLAG) {
624 if(memcmp(&dag->dag_id, &buffer[pos],
sizeof(dag->dag_id))) {
625 PRINTF(
"RPL: Ignoring a DAO for a DAG different from ours\n");
632 RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
634 PRINTF(
"RPL: DAO from %s\n",
635 learned_from == RPL_ROUTE_FROM_UNICAST_DAO?
"unicast":
"multicast");
636 if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
638 parent = rpl_find_parent(dag, &dao_sender_addr);
642 DAG_RANK(parent->rank, instance) < DAG_RANK(dag->rank, instance)) {
643 PRINTF(
"RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
644 DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
645 parent->rank = INFINITE_RANK;
651 if(parent !=
NULL && parent == dag->preferred_parent) {
652 PRINTF(
"RPL: Loop detected when receiving a unicast DAO from our parent\n");
653 parent->rank = INFINITE_RANK;
660 for(i = pos; i < buffer_length; i += len) {
661 subopt_type = buffer[i];
662 if(subopt_type == RPL_OPTION_PAD1) {
666 len = 2 + buffer[i + 1];
669 switch(subopt_type) {
670 case RPL_OPTION_TARGET:
672 prefixlen = buffer[i + 3];
673 memset(&prefix, 0,
sizeof(prefix));
674 memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
676 case RPL_OPTION_TRANSIT:
680 lifetime = buffer[i + 5];
686 PRINTF(
"RPL: DAO lifetime: %u, prefix length: %u prefix: ",
687 (
unsigned)lifetime, (
unsigned)prefixlen);
691 #if RPL_CONF_MULTICAST
693 mcast_group = uip_mcast6_route_add(&prefix);
695 mcast_group->dag = dag;
696 mcast_group->lifetime = RPL_LIFETIME(instance, lifetime);
704 if(lifetime == RPL_ZERO_LIFETIME) {
705 PRINTF(
"RPL: No-Path DAO received\n");
708 rep->state.nopath_received == 0 &&
709 rep->length == prefixlen &&
710 uip_ds6_route_nexthop(rep) !=
NULL &&
711 uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) {
712 PRINTF(
"RPL: Setting expiration timer for prefix ");
715 rep->state.nopath_received = 1;
716 rep->state.lifetime = DAO_EXPIRATION_TIMEOUT;
720 if(dag->preferred_parent !=
NULL &&
721 rpl_get_parent_ipaddr(dag->preferred_parent) !=
NULL) {
722 PRINTF(
"RPL: Forwarding no-path DAO to parent ");
723 PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
728 if(flags & RPL_DAO_K_FLAG) {
729 dao_ack_output(instance, &dao_sender_addr, sequence);
735 PRINTF(
"RPL: adding DAO route\n");
740 0, NBR_REACHABLE)) !=
NULL) {
742 stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
743 PRINTF(
"RPL: Neighbor added to neighbor cache ");
744 PRINT6ADDR(&dao_sender_addr);
746 PRINTLLADDR((
uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
749 PRINTF(
"RPL: Out of Memory, dropping DAO from ");
750 PRINT6ADDR(&dao_sender_addr);
752 PRINTLLADDR((
uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
757 PRINTF(
"RPL: Neighbor already in neighbor cache\n");
760 rpl_lock_parent(parent);
762 rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
764 RPL_STAT(rpl_stats.mem_overflows++);
765 PRINTF(
"RPL: Could not add a route after receiving a DAO\n");
769 rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
770 rep->state.learned_from = learned_from;
772 #if RPL_CONF_MULTICAST
776 if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
777 if(dag->preferred_parent !=
NULL &&
778 rpl_get_parent_ipaddr(dag->preferred_parent) !=
NULL) {
779 PRINTF(
"RPL: Forwarding DAO to parent ");
780 PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
785 if(flags & RPL_DAO_K_FLAG) {
786 dao_ack_output(instance, &dao_sender_addr, sequence);
792 dao_output(rpl_parent_t *parent, uint8_t lifetime)
797 if(get_global_addr(&prefix) == 0) {
798 PRINTF(
"RPL: No global address set for this node - suppressing DAO\n");
803 dao_output_target(parent, &prefix, lifetime);
807 dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
811 unsigned char *buffer;
823 PRINTF(
"RPL dao_output_target error parent NULL\n");
829 PRINTF(
"RPL dao_output_target error dag NULL\n");
833 instance = dag->instance;
835 if(instance ==
NULL) {
836 PRINTF(
"RPL dao_output_target error instance NULL\n");
840 PRINTF(
"RPL dao_output_target error prefix NULL\n");
843 #ifdef RPL_DEBUG_DAO_OUTPUT
844 RPL_DEBUG_DAO_OUTPUT(parent);
847 buffer = UIP_ICMP_PAYLOAD;
849 RPL_LOLLIPOP_INCREMENT(dao_sequence);
852 buffer[pos++] = instance->instance_id;
854 #if RPL_DAO_SPECIFY_DAG
855 buffer[pos] |= RPL_DAO_D_FLAG;
858 buffer[pos] |= RPL_DAO_K_FLAG;
862 buffer[pos++] = dao_sequence;
863 #if RPL_DAO_SPECIFY_DAG
864 memcpy(buffer + pos, &dag->dag_id,
sizeof(dag->dag_id));
865 pos+=
sizeof(dag->dag_id);
869 prefixlen =
sizeof(*prefix) * CHAR_BIT;
870 buffer[pos++] = RPL_OPTION_TARGET;
871 buffer[pos++] = 2 + ((prefixlen + 7) / CHAR_BIT);
873 buffer[pos++] = prefixlen;
874 memcpy(buffer + pos, prefix, (prefixlen + 7) / CHAR_BIT);
875 pos += ((prefixlen + 7) / CHAR_BIT);
878 buffer[pos++] = RPL_OPTION_TRANSIT;
883 buffer[pos++] = lifetime;
885 PRINTF(
"RPL: Sending DAO with prefix ");
888 PRINT6ADDR(rpl_get_parent_ipaddr(parent));
891 if(rpl_get_parent_ipaddr(parent) !=
NULL) {
900 unsigned char *buffer;
901 uint8_t buffer_length;
906 buffer = UIP_ICMP_PAYLOAD;
907 buffer_length =
uip_len - uip_l3_icmp_hdr_len;
909 instance_id = buffer[0];
910 sequence = buffer[2];
913 PRINTF(
"RPL: Received a DAO ACK with sequence number %d and status %d from ",
921 dao_ack_output(
rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence)
923 unsigned char *buffer;
925 PRINTF(
"RPL: Sending a DAO ACK with sequence number %d to ", sequence);
929 buffer = UIP_ICMP_PAYLOAD;
931 buffer[0] = instance->instance_id;
933 buffer[2] = sequence;
942 PRINTF(
"Received an RPL control message\n");
953 case RPL_CODE_DAO_ACK:
957 PRINTF(
"RPL: received an unknown ICMP6 code (%u)\n",
UIP_ICMP_BUF->icode);