53 #include "net/rpl/rpl-private.h"
62 #define DEBUG DEBUG_NONE
67 #define RPL_DIO_GROUNDED 0x80
68 #define RPL_DIO_MOP_SHIFT 3
69 #define RPL_DIO_MOP_MASK 0x38
70 #define RPL_DIO_PREFERENCE_MASK 0x07
72 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
73 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
74 #define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len])
76 static void dis_input(
void);
77 static void dio_input(
void);
78 static void dao_input(
void);
79 static void dao_ack_input(
void);
81 static void dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
82 uint8_t lifetime, uint8_t seq_no);
85 #ifdef RPL_DEBUG_DIO_INPUT
86 void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *);
89 #ifdef RPL_DEBUG_DAO_OUTPUT
90 void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
93 static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
95 #if RPL_CONF_MULTICAST
100 UIP_ICMP6_HANDLER(dis_handler,
ICMP6_RPL, RPL_CODE_DIS, dis_input);
101 UIP_ICMP6_HANDLER(dio_handler,
ICMP6_RPL, RPL_CODE_DIO, dio_input);
102 UIP_ICMP6_HANDLER(dao_handler,
ICMP6_RPL, RPL_CODE_DAO, dao_input);
103 UIP_ICMP6_HANDLER(dao_ack_handler,
ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_input);
108 find_route_entry_by_dao_ack(uint8_t seq)
111 re = uip_ds6_route_head();
113 if(re->state.dao_seqno_out == seq && RPL_ROUTE_IS_DAO_PENDING(re)) {
117 re = uip_ds6_route_next(re);
129 RPL_LOLLIPOP_INCREMENT(dao_sequence);
132 rep->state.dao_seqno_in = sequence;
133 rep->state.dao_seqno_out = dao_sequence;
134 RPL_ROUTE_SET_DAO_PENDING(rep);
140 get_global_addr(uip_ipaddr_t *
addr)
145 for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
150 memcpy(addr, &
uip_ds6_if.addr_list[i].ipaddr,
sizeof(uip_ipaddr_t));
159 get32(uint8_t *buffer,
int pos)
161 return (uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
162 (uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3];
166 set32(uint8_t *buffer,
int pos, uint32_t value)
168 buffer[pos++] = value >> 24;
169 buffer[pos++] = (value >> 16) & 0xff;
170 buffer[pos++] = (value >> 8) & 0xff;
171 buffer[pos++] = value & 0xff;
175 get16(uint8_t *buffer,
int pos)
177 return (uint16_t)buffer[pos] << 8 | buffer[pos + 1];
181 set16(uint8_t *buffer,
int pos, uint16_t value)
183 buffer[pos++] = value >> 8;
184 buffer[pos++] = value & 0xff;
188 rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason,
void *data)
192 if((nbr = uip_ds6_nbr_lookup(from)) ==
NULL) {
194 packetbuf_addr(PACKETBUF_ADDR_SENDER),
195 0, NBR_REACHABLE, reason, data)) !=
NULL) {
196 PRINTF(
"RPL: Neighbor added to neighbor cache ");
199 PRINTLLADDR((
uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
208 stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
209 nbr->state = NBR_REACHABLE;
218 rpl_instance_t *instance;
222 PRINTF(
"RPL: Received a DIS from ");
226 for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
227 instance < end; ++instance) {
228 if(instance->used == 1) {
231 PRINTF(
"RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n");
234 PRINTF(
"RPL: Multicast DIS => reset DIO timer\n");
235 rpl_reset_dio_timer(instance);
239 if(rpl_icmp6_update_nbr_table(&
UIP_IP_BUF->srcipaddr,
240 NBR_TABLE_REASON_RPL_DIS,
NULL) ==
NULL) {
241 PRINTF(
"RPL: Out of Memory, not sending unicast DIO, DIS from ");
244 PRINTLLADDR((
uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
247 PRINTF(
"RPL: Unicast DIS, reply to sender\n");
258 dis_output(uip_ipaddr_t *addr)
260 unsigned char *buffer;
261 uip_ipaddr_t tmpaddr;
272 buffer = UIP_ICMP_PAYLOAD;
273 buffer[0] = buffer[1] = 0;
276 uip_create_linklocal_rplnodes_mcast(&tmpaddr);
280 PRINTF(
"RPL: Sending a DIS to ");
290 unsigned char *buffer;
291 uint8_t buffer_length;
298 memset(&dio, 0,
sizeof(dio));
301 dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
302 dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
303 dio.dag_redund = RPL_DIO_REDUNDANCY;
304 dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
305 dio.dag_max_rankinc = RPL_MAX_RANKINC;
306 dio.ocp = RPL_OF_OCP;
307 dio.default_lifetime = RPL_DEFAULT_LIFETIME;
308 dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
313 PRINTF(
"RPL: Received a DIO from ");
317 buffer_length =
uip_len - uip_l3_icmp_hdr_len;
321 buffer = UIP_ICMP_PAYLOAD;
323 dio.instance_id = buffer[i++];
324 dio.version = buffer[i++];
325 dio.rank = get16(buffer, i);
328 PRINTF(
"RPL: Incoming DIO (id, ver, rank) = (%u,%u,%u)\n",
329 (
unsigned)dio.instance_id,
330 (
unsigned)dio.version,
333 dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
334 dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
335 dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;
337 dio.dtsn = buffer[i++];
341 memcpy(&dio.dag_id, buffer + i,
sizeof(dio.dag_id));
342 i +=
sizeof(dio.dag_id);
344 PRINTF(
"RPL: Incoming DIO (dag_id, pref) = (");
345 PRINT6ADDR(&dio.dag_id);
346 PRINTF(
", %u)\n", dio.preference);
349 for(; i < buffer_length; i += len) {
350 subopt_type = buffer[i];
351 if(subopt_type == RPL_OPTION_PAD1) {
355 len = 2 + buffer[i + 1];
358 if(len + i > buffer_length) {
359 PRINTF(
"RPL: Invalid DIO packet\n");
360 RPL_STAT(rpl_stats.malformed_msgs++);
364 PRINTF(
"RPL: DIO option %u, length: %u\n", subopt_type, len - 2);
366 switch(subopt_type) {
367 case RPL_OPTION_DAG_METRIC_CONTAINER:
369 PRINTF(
"RPL: Invalid DAG MC, len = %d\n", len);
370 RPL_STAT(rpl_stats.malformed_msgs++);
373 dio.mc.type = buffer[i + 2];
374 dio.mc.flags = buffer[i + 3] << 1;
375 dio.mc.flags |= buffer[i + 4] >> 7;
376 dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
377 dio.mc.prec = buffer[i + 4] & 0xf;
378 dio.mc.length = buffer[i + 5];
380 if(dio.mc.type == RPL_DAG_MC_NONE) {
382 }
else if(dio.mc.type == RPL_DAG_MC_ETX) {
383 dio.mc.obj.etx = get16(buffer, i + 6);
385 PRINTF(
"RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
386 (
unsigned)dio.mc.type,
387 (
unsigned)dio.mc.flags,
388 (
unsigned)dio.mc.aggr,
389 (
unsigned)dio.mc.prec,
390 (
unsigned)dio.mc.length,
391 (
unsigned)dio.mc.obj.etx);
392 }
else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
393 dio.mc.obj.energy.flags = buffer[i + 6];
394 dio.mc.obj.energy.energy_est = buffer[i + 7];
396 PRINTF(
"RPL: Unhandled DAG MC type: %u\n", (
unsigned)dio.mc.type);
400 case RPL_OPTION_ROUTE_INFO:
402 PRINTF(
"RPL: Invalid destination prefix option, len = %d\n", len);
403 RPL_STAT(rpl_stats.malformed_msgs++);
408 dio.destination_prefix.length = buffer[i + 2];
409 dio.destination_prefix.flags = buffer[i + 3];
410 dio.destination_prefix.lifetime = get32(buffer, i + 4);
412 if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
413 dio.destination_prefix.length <= 128) {
414 PRINTF(
"RPL: Copying destination prefix\n");
415 memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
416 (dio.destination_prefix.length + 7) / 8);
418 PRINTF(
"RPL: Invalid route info option, len = %d\n", len);
419 RPL_STAT(rpl_stats.malformed_msgs++);
424 case RPL_OPTION_DAG_CONF:
426 PRINTF(
"RPL: Invalid DAG configuration option, len = %d\n", len);
427 RPL_STAT(rpl_stats.malformed_msgs++);
432 dio.dag_intdoubl = buffer[i + 3];
433 dio.dag_intmin = buffer[i + 4];
434 dio.dag_redund = buffer[i + 5];
435 dio.dag_max_rankinc = get16(buffer, i + 6);
436 dio.dag_min_hoprankinc = get16(buffer, i + 8);
437 dio.ocp = get16(buffer, i + 10);
439 dio.default_lifetime = buffer[i + 13];
440 dio.lifetime_unit = get16(buffer, i + 14);
441 PRINTF(
"RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
442 dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
443 dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
444 dio.default_lifetime, dio.lifetime_unit);
446 case RPL_OPTION_PREFIX_INFO:
448 PRINTF(
"RPL: Invalid DAG prefix info, len != 32\n");
449 RPL_STAT(rpl_stats.malformed_msgs++);
452 dio.prefix_info.length = buffer[i + 2];
453 dio.prefix_info.flags = buffer[i + 3];
456 dio.prefix_info.lifetime = get32(buffer, i + 8);
458 PRINTF(
"RPL: Copying prefix information\n");
459 memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
462 PRINTF(
"RPL: Unsupported suboption type in DIO: %u\n",
463 (
unsigned)subopt_type);
467 #ifdef RPL_DEBUG_DIO_INPUT
468 RPL_DEBUG_DIO_INPUT(&from, &dio);
471 rpl_process_dio(&from, &dio);
478 dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
480 unsigned char *buffer;
483 rpl_dag_t *dag = instance->current_dag;
491 if(uc_addr ==
NULL) {
492 PRINTF(
"RPL: LEAF ONLY have multicast addr: skip dio_output\n");
500 buffer = UIP_ICMP_PAYLOAD;
501 buffer[pos++] = instance->instance_id;
502 buffer[pos++] = dag->version;
503 is_root = (dag->rank == ROOT_RANK(instance));
506 PRINTF(
"RPL: LEAF ONLY DIO rank set to INFINITE_RANK\n");
507 set16(buffer, pos, INFINITE_RANK);
509 set16(buffer, pos, dag->rank);
515 buffer[pos] |= RPL_DIO_GROUNDED;
518 buffer[pos] |= instance->mop << RPL_DIO_MOP_SHIFT;
519 buffer[pos] |= dag->preference & RPL_DIO_PREFERENCE_MASK;
522 buffer[pos++] = instance->dtsn_out;
524 if(RPL_DIO_REFRESH_DAO_ROUTES && is_root && uc_addr ==
NULL) {
528 RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
535 memcpy(buffer + pos, &dag->dag_id,
sizeof(dag->dag_id));
539 if(instance->mc.type != RPL_DAG_MC_NONE) {
540 instance->of->update_metric_container(instance);
542 buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
544 buffer[pos++] = instance->mc.type;
545 buffer[pos++] = instance->mc.flags >> 1;
546 buffer[pos] = (instance->mc.flags & 1) << 7;
547 buffer[pos++] |= (instance->mc.aggr << 4) | instance->mc.prec;
548 if(instance->mc.type == RPL_DAG_MC_ETX) {
550 set16(buffer, pos, instance->mc.obj.etx);
552 }
else if(instance->mc.type == RPL_DAG_MC_ENERGY) {
554 buffer[pos++] = instance->mc.obj.energy.flags;
555 buffer[pos++] = instance->mc.obj.energy.energy_est;
557 PRINTF(
"RPL: Unable to send DIO because of unhandled DAG MC type %u\n",
558 (
unsigned)instance->mc.type);
565 buffer[pos++] = RPL_OPTION_DAG_CONF;
568 buffer[pos++] = instance->dio_intdoubl;
569 buffer[pos++] = instance->dio_intmin;
570 buffer[pos++] = instance->dio_redundancy;
571 set16(buffer, pos, instance->max_rankinc);
573 set16(buffer, pos, instance->min_hoprankinc);
576 set16(buffer, pos, instance->of->ocp);
579 buffer[pos++] = instance->default_lifetime;
580 set16(buffer, pos, instance->lifetime_unit);
584 if(dag->prefix_info.length > 0) {
585 buffer[pos++] = RPL_OPTION_PREFIX_INFO;
587 buffer[pos++] = dag->prefix_info.length;
588 buffer[pos++] = dag->prefix_info.flags;
589 set32(buffer, pos, dag->prefix_info.lifetime);
591 set32(buffer, pos, dag->prefix_info.lifetime);
593 memset(&buffer[pos], 0, 4);
595 memcpy(&buffer[pos], &dag->prefix_info.prefix, 16);
597 PRINTF(
"RPL: Sending prefix info in DIO for ");
598 PRINT6ADDR(&dag->prefix_info.prefix);
601 PRINTF(
"RPL: No prefix to announce (len %d)\n",
602 dag->prefix_info.length);
606 #if (DEBUG) & DEBUG_PRINT
607 if(uc_addr ==
NULL) {
608 PRINTF(
"RPL: LEAF ONLY sending unicast-DIO from multicast-DIO\n");
611 PRINTF(
"RPL: Sending unicast-DIO with rank %u to ",
612 (
unsigned)dag->rank);
618 if(uc_addr ==
NULL) {
619 PRINTF(
"RPL: Sending a multicast-DIO with rank %u\n",
620 (
unsigned)instance->current_dag->rank);
621 uip_create_linklocal_rplnodes_mcast(&addr);
624 PRINTF(
"RPL: Sending unicast-DIO with rank %u to ",
625 (
unsigned)instance->current_dag->rank);
634 dao_input_storing(
void)
637 uip_ipaddr_t dao_sender_addr;
639 rpl_instance_t *instance;
640 unsigned char *buffer;
653 uint8_t buffer_length;
658 rpl_parent_t *parent;
667 buffer = UIP_ICMP_PAYLOAD;
668 buffer_length =
uip_len - uip_l3_icmp_hdr_len;
671 instance_id = buffer[pos++];
673 instance = rpl_get_instance(instance_id);
675 lifetime = instance->default_lifetime;
677 flags = buffer[pos++];
680 sequence = buffer[pos++];
682 dag = instance->current_dag;
683 is_root = (dag->rank == ROOT_RANK(instance));
686 if(flags & RPL_DAO_D_FLAG) {
687 if(memcmp(&dag->dag_id, &buffer[pos],
sizeof(dag->dag_id))) {
688 PRINTF(
"RPL: Ignoring a DAO for a DAG different from ours\n");
695 RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
698 PRINTF(
"RPL: Received a (%s) DAO with sequence number %u from ",
699 learned_from == RPL_ROUTE_FROM_UNICAST_DAO?
"unicast":
"multicast", sequence);
700 PRINT6ADDR(&dao_sender_addr);
703 if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
705 parent = rpl_find_parent(dag, &dao_sender_addr);
709 DAG_RANK(parent->rank, instance) < DAG_RANK(dag->rank, instance)) {
710 PRINTF(
"RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
711 DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
712 parent->rank = INFINITE_RANK;
713 parent->flags |= RPL_PARENT_FLAG_UPDATED;
718 if(parent !=
NULL && parent == dag->preferred_parent) {
719 PRINTF(
"RPL: Loop detected when receiving a unicast DAO from our parent\n");
720 parent->rank = INFINITE_RANK;
721 parent->flags |= RPL_PARENT_FLAG_UPDATED;
727 for(i = pos; i < buffer_length; i += len) {
728 subopt_type = buffer[i];
729 if(subopt_type == RPL_OPTION_PAD1) {
733 len = 2 + buffer[i + 1];
736 switch(subopt_type) {
737 case RPL_OPTION_TARGET:
739 prefixlen = buffer[i + 3];
740 memset(&prefix, 0,
sizeof(prefix));
741 memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
743 case RPL_OPTION_TRANSIT:
747 lifetime = buffer[i + 5];
753 PRINTF(
"RPL: DAO lifetime: %u, prefix length: %u prefix: ",
754 (
unsigned)lifetime, (
unsigned)prefixlen);
758 #if RPL_CONF_MULTICAST
762 mcast_group->
dag = dag;
763 mcast_group->
lifetime = RPL_LIFETIME(instance, lifetime);
769 rep = uip_ds6_route_lookup(&prefix);
771 if(lifetime == RPL_ZERO_LIFETIME) {
772 PRINTF(
"RPL: No-Path DAO received\n");
775 !RPL_ROUTE_IS_NOPATH_RECEIVED(rep) &&
776 rep->length == prefixlen &&
777 uip_ds6_route_nexthop(rep) !=
NULL &&
778 uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) {
779 PRINTF(
"RPL: Setting expiration timer for prefix ");
782 RPL_ROUTE_SET_NOPATH_RECEIVED(rep);
783 rep->state.lifetime = RPL_NOPATH_REMOVAL_DELAY;
787 if(dag->preferred_parent !=
NULL &&
788 rpl_get_parent_ipaddr(dag->preferred_parent) !=
NULL) {
790 out_seq = prepare_for_dao_fwd(sequence, rep);
792 PRINTF(
"RPL: Forwarding No-path DAO to parent - out_seq:%d",
794 PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
797 buffer = UIP_ICMP_PAYLOAD;
804 if(flags & RPL_DAO_K_FLAG) {
807 dao_ack_output(instance, &dao_sender_addr, sequence,
808 RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
813 PRINTF(
"RPL: Adding DAO route\n");
816 if((nbr = rpl_icmp6_update_nbr_table(&dao_sender_addr, NBR_TABLE_REASON_RPL_DAO, instance)) ==
NULL) {
817 PRINTF(
"RPL: Out of Memory, dropping DAO from ");
818 PRINT6ADDR(&dao_sender_addr);
820 PRINTLLADDR((
uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
822 if(flags & RPL_DAO_K_FLAG) {
824 dao_ack_output(instance, &dao_sender_addr, sequence,
825 is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
826 RPL_DAO_ACK_UNABLE_TO_ACCEPT);
831 rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
833 RPL_STAT(rpl_stats.mem_overflows++);
834 PRINTF(
"RPL: Could not add a route after receiving a DAO\n");
835 if(flags & RPL_DAO_K_FLAG) {
837 dao_ack_output(instance, &dao_sender_addr, sequence,
838 is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
839 RPL_DAO_ACK_UNABLE_TO_ACCEPT);
845 rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
846 RPL_ROUTE_CLEAR_NOPATH_RECEIVED(rep);
848 #if RPL_CONF_MULTICAST
852 if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
855 if(flags & RPL_DAO_K_FLAG) {
862 if((!RPL_ROUTE_IS_DAO_PENDING(rep) &&
863 rep->state.dao_seqno_in == sequence) ||
864 dag->rank == ROOT_RANK(instance)) {
869 if(dag->preferred_parent !=
NULL &&
870 rpl_get_parent_ipaddr(dag->preferred_parent) !=
NULL) {
873 if(RPL_ROUTE_IS_DAO_PENDING(rep) &&
874 rep->state.dao_seqno_in == sequence) {
876 out_seq = rep->state.dao_seqno_out;
878 out_seq = prepare_for_dao_fwd(sequence, rep);
881 PRINTF(
"RPL: Forwarding DAO to parent ");
882 PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
883 PRINTF(
" in seq: %d out seq: %d\n", sequence, out_seq);
885 buffer = UIP_ICMP_PAYLOAD;
891 PRINTF(
"RPL: Sending DAO ACK\n");
893 dao_ack_output(instance, &dao_sender_addr, sequence,
894 RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
901 dao_input_nonstoring(
void)
903 #if RPL_WITH_NON_STORING
904 uip_ipaddr_t dao_sender_addr;
905 uip_ipaddr_t dao_parent_addr;
907 rpl_instance_t *instance;
908 unsigned char *buffer;
916 uint8_t buffer_length;
924 memset(&dao_parent_addr, 0, 16);
926 buffer = UIP_ICMP_PAYLOAD;
927 buffer_length =
uip_len - uip_l3_icmp_hdr_len;
930 instance_id = buffer[pos++];
931 instance = rpl_get_instance(instance_id);
932 lifetime = instance->default_lifetime;
934 flags = buffer[pos++];
937 sequence = buffer[pos++];
939 dag = instance->current_dag;
941 if(flags & RPL_DAO_D_FLAG) {
942 if(memcmp(&dag->dag_id, &buffer[pos],
sizeof(dag->dag_id))) {
943 PRINTF(
"RPL: Ignoring a DAO for a DAG different from ours\n");
950 for(i = pos; i < buffer_length; i += len) {
951 subopt_type = buffer[i];
952 if(subopt_type == RPL_OPTION_PAD1) {
956 len = 2 + buffer[i + 1];
959 switch(subopt_type) {
960 case RPL_OPTION_TARGET:
962 prefixlen = buffer[i + 3];
963 memset(&prefix, 0,
sizeof(prefix));
964 memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
966 case RPL_OPTION_TRANSIT:
970 lifetime = buffer[i + 5];
972 memcpy(&dao_parent_addr, buffer + i + 6, 16);
978 PRINTF(
"RPL: DAO lifetime: %u, prefix length: %u prefix: ",
979 (
unsigned)lifetime, (
unsigned)prefixlen);
981 PRINTF(
", parent: ");
982 PRINT6ADDR(&dao_parent_addr);
985 if(lifetime == RPL_ZERO_LIFETIME) {
986 PRINTF(
"RPL: No-Path DAO received\n");
987 rpl_ns_expire_parent(dag, &prefix, &dao_parent_addr);
989 if(rpl_ns_update_node(dag, &prefix, &dao_parent_addr, RPL_LIFETIME(instance, lifetime)) ==
NULL) {
990 PRINTF(
"RPL: failed to add link\n");
995 if(flags & RPL_DAO_K_FLAG) {
996 PRINTF(
"RPL: Sending DAO ACK\n");
998 dao_ack_output(instance, &dao_sender_addr, sequence,
999 RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
1007 rpl_instance_t *instance;
1008 uint8_t instance_id;
1011 PRINTF(
"RPL: Received a DAO from ");
1015 instance_id = UIP_ICMP_PAYLOAD[0];
1016 instance = rpl_get_instance(instance_id);
1017 if(instance ==
NULL) {
1018 PRINTF(
"RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
1023 if(RPL_IS_STORING(instance)) {
1024 dao_input_storing();
1025 }
else if(RPL_IS_NON_STORING(instance)) {
1026 dao_input_nonstoring();
1033 #if RPL_WITH_DAO_ACK
1035 handle_dao_retransmission(
void *ptr)
1037 rpl_parent_t *parent;
1038 uip_ipaddr_t prefix;
1039 rpl_instance_t *instance;
1042 if(parent ==
NULL || parent->dag ==
NULL || parent->dag->instance ==
NULL) {
1045 instance = parent->dag->instance;
1047 if(instance->my_dao_transmissions >= RPL_DAO_MAX_RETRANSMISSIONS) {
1049 if(instance->lifetime_unit == 0xffff && instance->default_lifetime == 0xff) {
1060 if(RPL_IS_STORING(instance) && instance->of->dao_ack_callback) {
1062 instance->of->dao_ack_callback(parent, RPL_DAO_ACK_TIMEOUT);
1066 rpl_local_repair(instance);
1070 PRINTF(
"RPL: will retransmit DAO - seq:%d trans:%d\n", instance->my_dao_seqno,
1071 instance->my_dao_transmissions);
1073 if(get_global_addr(&prefix) == 0) {
1078 RPL_DAO_RETRANSMISSION_TIMEOUT / 2 +
1079 (
random_rand() % (RPL_DAO_RETRANSMISSION_TIMEOUT / 2)),
1080 handle_dao_retransmission, parent);
1082 instance->my_dao_transmissions++;
1083 dao_output_target_seq(parent, &prefix,
1084 instance->default_lifetime, instance->my_dao_seqno);
1089 dao_output(rpl_parent_t *parent, uint8_t lifetime)
1092 uip_ipaddr_t prefix;
1094 if(get_global_addr(&prefix) == 0) {
1095 PRINTF(
"RPL: No global address set for this node - suppressing DAO\n");
1099 if(parent ==
NULL || parent->dag ==
NULL || parent->dag->instance ==
NULL) {
1103 RPL_LOLLIPOP_INCREMENT(dao_sequence);
1104 #if RPL_WITH_DAO_ACK
1108 if(lifetime != RPL_ZERO_LIFETIME) {
1109 rpl_instance_t *instance;
1110 instance = parent->dag->instance;
1112 instance->my_dao_seqno = dao_sequence;
1113 instance->my_dao_transmissions = 1;
1114 ctimer_set(&instance->dao_retransmit_timer, RPL_DAO_RETRANSMISSION_TIMEOUT,
1115 handle_dao_retransmission, parent);
1120 parent->dag->instance->has_downward_route = lifetime != RPL_ZERO_LIFETIME;
1124 dao_output_target(parent, &prefix, lifetime);
1128 dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
1130 dao_output_target_seq(parent, prefix, lifetime, dao_sequence);
1134 dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
1135 uint8_t lifetime, uint8_t seq_no)
1138 rpl_instance_t *instance;
1139 unsigned char *buffer;
1142 uip_ipaddr_t *parent_ipaddr =
NULL;
1143 uip_ipaddr_t *dest_ipaddr =
NULL;
1152 if(parent ==
NULL) {
1153 PRINTF(
"RPL dao_output_target error parent NULL\n");
1157 parent_ipaddr = rpl_get_parent_ipaddr(parent);
1158 if(parent_ipaddr ==
NULL) {
1159 PRINTF(
"RPL dao_output_target error parent IP address NULL\n");
1165 PRINTF(
"RPL dao_output_target error dag NULL\n");
1169 instance = dag->instance;
1171 if(instance ==
NULL) {
1172 PRINTF(
"RPL dao_output_target error instance NULL\n");
1175 if(prefix ==
NULL) {
1176 PRINTF(
"RPL dao_output_target error prefix NULL\n");
1179 #ifdef RPL_DEBUG_DAO_OUTPUT
1180 RPL_DEBUG_DAO_OUTPUT(parent);
1183 buffer = UIP_ICMP_PAYLOAD;
1186 buffer[pos++] = instance->instance_id;
1188 #if RPL_DAO_SPECIFY_DAG
1189 buffer[pos] |= RPL_DAO_D_FLAG;
1191 #if RPL_WITH_DAO_ACK
1192 if(lifetime != RPL_ZERO_LIFETIME) {
1193 buffer[pos] |= RPL_DAO_K_FLAG;
1198 buffer[pos++] = seq_no;
1199 #if RPL_DAO_SPECIFY_DAG
1200 memcpy(buffer + pos, &dag->dag_id,
sizeof(dag->dag_id));
1201 pos+=
sizeof(dag->dag_id);
1205 prefixlen =
sizeof(*prefix) * CHAR_BIT;
1206 buffer[pos++] = RPL_OPTION_TARGET;
1207 buffer[pos++] = 2 + ((prefixlen + 7) / CHAR_BIT);
1209 buffer[pos++] = prefixlen;
1210 memcpy(buffer + pos, prefix, (prefixlen + 7) / CHAR_BIT);
1211 pos += ((prefixlen + 7) / CHAR_BIT);
1214 buffer[pos++] = RPL_OPTION_TRANSIT;
1215 buffer[pos++] = (instance->mop != RPL_MOP_NON_STORING) ? 4 : 20;
1219 buffer[pos++] = lifetime;
1221 if(instance->mop != RPL_MOP_NON_STORING) {
1223 dest_ipaddr = parent_ipaddr;
1226 memcpy(buffer + pos, &parent->dag->dag_id, 8);
1228 memcpy(buffer + pos, ((
const unsigned char *)parent_ipaddr) + 8, 8);
1231 dest_ipaddr = &parent->dag->dag_id;
1234 PRINTF(
"RPL: Sending a %sDAO with sequence number %u, lifetime %u, prefix ",
1235 lifetime == RPL_ZERO_LIFETIME ?
"No-Path " :
"", seq_no, lifetime);
1239 PRINT6ADDR(dest_ipaddr);
1240 PRINTF(
" , parent ");
1241 PRINT6ADDR(parent_ipaddr);
1244 if(dest_ipaddr !=
NULL) {
1252 #if RPL_WITH_DAO_ACK
1255 uint8_t instance_id;
1258 rpl_instance_t *instance;
1259 rpl_parent_t *parent;
1261 buffer = UIP_ICMP_PAYLOAD;
1263 instance_id = buffer[0];
1264 sequence = buffer[2];
1267 instance = rpl_get_instance(instance_id);
1268 if(instance ==
NULL) {
1273 if(RPL_IS_STORING(instance)) {
1274 parent = rpl_find_parent(instance->current_dag, &
UIP_IP_BUF->srcipaddr);
1275 if(parent ==
NULL) {
1284 PRINTF(
"RPL: Received a DAO %s with sequence number %d (%d) and status %d from ",
1285 status < 128 ?
"ACK" :
"NACK",
1286 sequence, instance->my_dao_seqno, status);
1290 if(sequence == instance->my_dao_seqno) {
1291 instance->has_downward_route = status < 128;
1297 if(RPL_IS_STORING(instance) && instance->of->dao_ack_callback) {
1298 instance->of->dao_ack_callback(parent, status);
1301 #if RPL_REPAIR_ON_DAO_NACK
1302 if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) {
1307 rpl_local_repair(instance);
1311 }
else if(RPL_IS_STORING(instance)) {
1314 uip_ipaddr_t *nexthop;
1315 if((re = find_route_entry_by_dao_ack(sequence)) !=
NULL) {
1318 RPL_ROUTE_CLEAR_DAO_PENDING(re);
1320 nexthop = uip_ds6_route_nexthop(re);
1321 if(nexthop ==
NULL) {
1322 PRINTF(
"RPL: No next hop to fwd DAO ACK to\n");
1324 PRINTF(
"RPL: Fwd DAO ACK to:");
1325 PRINT6ADDR(nexthop);
1327 buffer[2] = re->state.dao_seqno_in;
1331 if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) {
1333 uip_ds6_route_rm(re);
1336 PRINTF(
"RPL: No route entry found to forward DAO ACK (seqno %u)\n", sequence);
1344 dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence,
1347 #if RPL_WITH_DAO_ACK
1348 unsigned char *buffer;
1350 PRINTF(
"RPL: Sending a DAO %s with sequence number %d to ", status < 128 ?
"ACK" :
"NACK", sequence);
1352 PRINTF(
" with status %d\n", status);
1354 buffer = UIP_ICMP_PAYLOAD;
1356 buffer[0] = instance->instance_id;
1358 buffer[2] = sequence;
1366 rpl_icmp6_register_handlers()
Header file for IPv6 Neighbor discovery (RFC 4861)
uip_len
The length of the packet in the uip_buf buffer.
void * dag
Pointer to an rpl_dag_t struct.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Header file for IPv6-related data structures.
#define uip_is_addr_mcast_global(a)
is address a global multicast address (FFxE::/16), a is of type uip_ip6addr_t*
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
Register a handler which can handle a specific ICMPv6 message type.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
An entry in the nbr cache.
#define UIP_IP_BUF
Pointer to IP header.
Header file for the Rime buffer (packetbuf) management
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 3513 a is of type uip_ipaddr_t*
uip_mcast6_route_t * uip_mcast6_route_add(uip_ipaddr_t *group)
Add a multicast route.
Header for the Contiki/uIP interface.
This header file contains configuration directives for uIPv6 multicast support.
#define NULL
The null pointer.
Header file for ICMPv6 message and error handing (RFC 4443)
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
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.
#define ADDR_TENTATIVE
Possible states for the an address (RFC 4862)
An entry in the multicast routing table.
Header file for the uIP TCP/IP stack.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
A set of debugging macros for the IP stack
enum rpl_mode rpl_get_mode(void)
Get the RPL mode.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC3513 i.e.
uip_ds6_netif_t uip_ds6_if
The single interface.
RPL non-storing mode specific functions.
void uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
Send an icmpv6 message.
An entry in the routing table.
uint32_t lifetime
Entry lifetime seconds.