Contiki 2.6

rpl-icmp6.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup uip6
00003  * @{
00004  */
00005 /*
00006  * Copyright (c) 2010, Swedish Institute of Computer Science.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions
00011  * are met:
00012  * 1. Redistributions of source code must retain the above copyright
00013  *    notice, this list of conditions and the following disclaimer.
00014  * 2. Redistributions in binary form must reproduce the above copyright
00015  *    notice, this list of conditions and the following disclaimer in the
00016  *    documentation and/or other materials provided with the distribution.
00017  * 3. Neither the name of the Institute nor the names of its contributors
00018  *    may be used to endorse or promote products derived from this software
00019  *    without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * This file is part of the Contiki operating system.
00034  *
00035  */
00036 /**
00037  * \file
00038  *         ICMP6 I/O for RPL control messages.
00039  *
00040  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
00041  * Contributors: Niclas Finne <nfi@sics.se>, Joel Hoglund <joel@sics.se>,
00042  *               Mathieu Pouillot <m.pouillot@watteco.com>
00043  */
00044 
00045 #include "net/tcpip.h"
00046 #include "net/uip.h"
00047 #include "net/uip-ds6.h"
00048 #include "net/uip-nd6.h"
00049 #include "net/uip-icmp6.h"
00050 #include "net/rpl/rpl-private.h"
00051 #include "net/packetbuf.h"
00052 
00053 #include <limits.h>
00054 #include <string.h>
00055 
00056 #define DEBUG DEBUG_NONE
00057 
00058 #include "net/uip-debug.h"
00059 
00060 /*---------------------------------------------------------------------------*/
00061 #define RPL_DIO_GROUNDED                 0x80
00062 #define RPL_DIO_MOP_SHIFT                3
00063 #define RPL_DIO_MOP_MASK                 0x3c
00064 #define RPL_DIO_PREFERENCE_MASK          0x07
00065 
00066 #define UIP_IP_BUF       ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
00067 #define UIP_ICMP_BUF     ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
00068 #define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len])
00069 /*---------------------------------------------------------------------------*/
00070 static void dis_input(void);
00071 static void dio_input(void);
00072 static void dao_input(void);
00073 static void dao_ack_input(void);
00074 
00075 /* some debug callbacks useful when debugging RPL networks */
00076 #ifdef RPL_DEBUG_DIO_INPUT
00077 void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *);
00078 #endif
00079 
00080 #ifdef RPL_DEBUG_DAO_OUTPUT
00081 void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
00082 #endif
00083 
00084 static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
00085 
00086 /* some debug callbacks useful when debugging RPL networks */
00087 #ifdef RPL_DEBUG_DIO_INPUT
00088 void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *);
00089 #endif
00090 
00091 #ifdef RPL_DEBUG_DAO_OUTPUT
00092 void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
00093 #endif
00094 
00095 extern rpl_of_t RPL_OF;
00096 
00097 /*---------------------------------------------------------------------------*/
00098 static int
00099 get_global_addr(uip_ipaddr_t *addr)
00100 {
00101   int i;
00102   int state;
00103 
00104   for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
00105     state = uip_ds6_if.addr_list[i].state;
00106     if(uip_ds6_if.addr_list[i].isused &&
00107        (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
00108       if(!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
00109         memcpy(addr, &uip_ds6_if.addr_list[i].ipaddr, sizeof(uip_ipaddr_t));
00110         return 1;
00111       }
00112     }
00113   }
00114   return 0;
00115 }
00116 /*---------------------------------------------------------------------------*/
00117 static uint32_t
00118 get32(uint8_t *buffer, int pos)
00119 {
00120   return (uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
00121          (uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3];
00122 }
00123 /*---------------------------------------------------------------------------*/
00124 static void
00125 set32(uint8_t *buffer, int pos, uint32_t value)
00126 {
00127   buffer[pos++] = value >> 24;
00128   buffer[pos++] = (value >> 16) & 0xff;
00129   buffer[pos++] = (value >> 8) & 0xff;
00130   buffer[pos++] = value & 0xff;
00131 }
00132 /*---------------------------------------------------------------------------*/
00133 static uint16_t
00134 get16(uint8_t *buffer, int pos)
00135 {
00136   return (uint16_t)buffer[pos] << 8 | buffer[pos + 1];
00137 }
00138 /*---------------------------------------------------------------------------*/
00139 static void
00140 set16(uint8_t *buffer, int pos, uint16_t value)
00141 {
00142   buffer[pos++] = value >> 8;
00143   buffer[pos++] = value & 0xff;
00144 }
00145 /*---------------------------------------------------------------------------*/
00146 static void
00147 dis_input(void)
00148 {
00149   rpl_instance_t *instance;
00150   rpl_instance_t *end;
00151 
00152   /* DAG Information Solicitation */
00153   PRINTF("RPL: Received a DIS from ");
00154   PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
00155   PRINTF("\n");
00156 
00157   for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
00158     if(instance->used == 1) {
00159 #if RPL_LEAF_ONLY
00160       if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
00161 #else /* !RPL_LEAF_ONLY */
00162       if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
00163         PRINTF("RPL: Multicast DIS => reset DIO timer\n");
00164         rpl_reset_dio_timer(instance);
00165       } else {
00166 #endif /* !RPL_LEAF_ONLY */
00167         PRINTF("RPL: Unicast DIS, reply to sender\n");
00168         dio_output(instance, &UIP_IP_BUF->srcipaddr);
00169       }
00170     }
00171   }
00172 }
00173 /*---------------------------------------------------------------------------*/
00174 void
00175 dis_output(uip_ipaddr_t *addr)
00176 {
00177   unsigned char *buffer;
00178   uip_ipaddr_t tmpaddr;
00179 
00180   /* DAG Information Solicitation  - 2 bytes reserved      */
00181   /*      0                   1                   2        */
00182   /*      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3  */
00183   /*     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
00184   /*     |     Flags     |   Reserved    |   Option(s)...  */
00185   /*     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
00186 
00187   buffer = UIP_ICMP_PAYLOAD;
00188   buffer[0] = buffer[1] = 0;
00189 
00190   if(addr == NULL) {
00191     uip_create_linklocal_rplnodes_mcast(&tmpaddr);
00192     addr = &tmpaddr;
00193   }
00194 
00195   PRINTF("RPL: Sending a DIS to ");
00196   PRINT6ADDR(addr);
00197   PRINTF("\n");
00198 
00199   uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIS, 2);
00200 }
00201 /*---------------------------------------------------------------------------*/
00202 static void
00203 dio_input(void)
00204 {
00205   unsigned char *buffer;
00206   uint8_t buffer_length;
00207   rpl_dio_t dio;
00208   uint8_t subopt_type;
00209   int i;
00210   int len;
00211   uip_ipaddr_t from;
00212   uip_ds6_nbr_t *nbr;
00213 
00214   memset(&dio, 0, sizeof(dio));
00215 
00216   /* Set default values in case the DIO configuration option is missing. */
00217   dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
00218   dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
00219   dio.dag_redund = RPL_DIO_REDUNDANCY;
00220   dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
00221   dio.dag_max_rankinc = RPL_MAX_RANKINC;
00222   dio.ocp = RPL_OF.ocp;
00223   dio.default_lifetime = RPL_DEFAULT_LIFETIME;
00224   dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
00225 
00226   uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);
00227 
00228   /* DAG Information Object */
00229   PRINTF("RPL: Received a DIO from ");
00230   PRINT6ADDR(&from);
00231   PRINTF("\n");
00232 
00233   if((nbr = uip_ds6_nbr_lookup(&from)) == NULL) {
00234     if((nbr = uip_ds6_nbr_add(&from, (uip_lladdr_t *)
00235                               packetbuf_addr(PACKETBUF_ADDR_SENDER),
00236                               0, NBR_REACHABLE)) != NULL) {
00237       /* set reachable timer */
00238       stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
00239       PRINTF("RPL: Neighbor added to neighbor cache ");
00240       PRINT6ADDR(&from);
00241       PRINTF(", ");
00242       PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
00243       PRINTF("\n");
00244     }
00245   } else {
00246     PRINTF("RPL: Neighbor already in neighbor cache\n");
00247   }
00248 
00249   buffer_length = uip_len - uip_l3_icmp_hdr_len;
00250 
00251   /* Process the DIO base option. */
00252   i = 0;
00253   buffer = UIP_ICMP_PAYLOAD;
00254 
00255   dio.instance_id = buffer[i++];
00256   dio.version = buffer[i++];
00257   dio.rank = get16(buffer, i);
00258   i += 2;
00259 
00260   PRINTF("RPL: Incoming DIO (id, ver, rank) = (%u,%u,%u)\n",
00261          (unsigned)dio.instance_id,
00262          (unsigned)dio.version, 
00263          (unsigned)dio.rank);
00264 
00265   dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
00266   dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
00267   dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;
00268 
00269   dio.dtsn = buffer[i++];
00270   /* two reserved bytes */
00271   i += 2;
00272 
00273   memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
00274   i += sizeof(dio.dag_id);
00275 
00276   PRINTF("RPL: Incoming DIO (dag_id, pref) = (");
00277   PRINT6ADDR(&dio.dag_id);
00278   PRINTF(", %u)\n", dio.preference);
00279 
00280   /* Check if there are any DIO suboptions. */
00281   for(; i < buffer_length; i += len) {
00282     subopt_type = buffer[i];
00283     if(subopt_type == RPL_OPTION_PAD1) {
00284       len = 1;
00285     } else {
00286       /* Suboption with a two-byte header + payload */
00287       len = 2 + buffer[i + 1];
00288     }
00289 
00290     if(len + i > buffer_length) {
00291       PRINTF("RPL: Invalid DIO packet\n");
00292       RPL_STAT(rpl_stats.malformed_msgs++);
00293       return;
00294     }
00295 
00296     PRINTF("RPL: DIO option %u, length: %u\n", subopt_type, len - 2);
00297 
00298     switch(subopt_type) {
00299     case RPL_OPTION_DAG_METRIC_CONTAINER:
00300       if(len < 6) {
00301         PRINTF("RPL: Invalid DAG MC, len = %d\n", len);
00302         RPL_STAT(rpl_stats.malformed_msgs++);
00303         return;
00304       }
00305       dio.mc.type = buffer[i + 2];
00306       dio.mc.flags = buffer[i + 3] << 1;
00307       dio.mc.flags |= buffer[i + 4] >> 7;
00308       dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
00309       dio.mc.prec = buffer[i + 4] & 0xf;
00310       dio.mc.length = buffer[i + 5];
00311 
00312       if(dio.mc.type == RPL_DAG_MC_ETX) {
00313         dio.mc.obj.etx = get16(buffer, i + 6);
00314 
00315         PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
00316                (unsigned)dio.mc.type,  
00317                (unsigned)dio.mc.flags, 
00318                (unsigned)dio.mc.aggr, 
00319                (unsigned)dio.mc.prec, 
00320                (unsigned)dio.mc.length, 
00321                (unsigned)dio.mc.obj.etx);
00322       } else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
00323         dio.mc.obj.energy.flags = buffer[i + 6];
00324         dio.mc.obj.energy.energy_est = buffer[i + 7];
00325       } else {
00326        PRINTF("RPL: Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type);
00327        return;
00328       }
00329       break;
00330     case RPL_OPTION_ROUTE_INFO:
00331       if(len < 9) {
00332         PRINTF("RPL: Invalid destination prefix option, len = %d\n", len);
00333         RPL_STAT(rpl_stats.malformed_msgs++);
00334         return;
00335       }
00336 
00337       /* The flags field includes the preference value. */
00338       dio.destination_prefix.length = buffer[i + 2];
00339       dio.destination_prefix.flags = buffer[i + 3];
00340       dio.destination_prefix.lifetime = get32(buffer, i + 4);
00341 
00342       if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
00343          dio.destination_prefix.length <= 128) {
00344         PRINTF("RPL: Copying destination prefix\n");
00345         memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
00346                (dio.destination_prefix.length + 7) / 8);
00347       } else {
00348         PRINTF("RPL: Invalid route info option, len = %d\n", len);
00349         RPL_STAT(rpl_stats.malformed_msgs++);
00350         return;
00351       }
00352 
00353       break;
00354     case RPL_OPTION_DAG_CONF:
00355       if(len != 16) {
00356         PRINTF("RPL: Invalid DAG configuration option, len = %d\n", len);
00357         RPL_STAT(rpl_stats.malformed_msgs++);
00358         return;
00359       }
00360 
00361       /* Path control field not yet implemented - at i + 2 */
00362       dio.dag_intdoubl = buffer[i + 3];
00363       dio.dag_intmin = buffer[i + 4];
00364       dio.dag_redund = buffer[i + 5];
00365       dio.dag_max_rankinc = get16(buffer, i + 6);
00366       dio.dag_min_hoprankinc = get16(buffer, i + 8);
00367       dio.ocp = get16(buffer, i + 10);
00368       /* buffer + 12 is reserved */
00369       dio.default_lifetime = buffer[i + 13];
00370       dio.lifetime_unit = get16(buffer, i + 14);
00371       PRINTF("RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
00372              dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
00373              dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
00374              dio.default_lifetime, dio.lifetime_unit);
00375       break;
00376     case RPL_OPTION_PREFIX_INFO:
00377       if(len != 32) {
00378         PRINTF("RPL: DAG prefix info not ok, len != 32\n");
00379         RPL_STAT(rpl_stats.malformed_msgs++);
00380         return;
00381       }
00382       dio.prefix_info.length = buffer[i + 2];
00383       dio.prefix_info.flags = buffer[i + 3];
00384       /* valid lifetime is ingnored for now - at i + 4 */
00385       /* preferred lifetime stored in lifetime */
00386       dio.prefix_info.lifetime = get32(buffer, i + 8);
00387       /* 32-bit reserved at i + 12 */
00388       PRINTF("RPL: Copying prefix information\n");
00389       memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
00390       break;
00391     default:
00392       PRINTF("RPL: Unsupported suboption type in DIO: %u\n",
00393         (unsigned)subopt_type);
00394     }
00395   }
00396 
00397 #ifdef RPL_DEBUG_DIO_INPUT
00398   RPL_DEBUG_DIO_INPUT(&from, &dio);
00399 #endif
00400 
00401   rpl_process_dio(&from, &dio);
00402 }
00403 /*---------------------------------------------------------------------------*/
00404 void
00405 dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
00406 {
00407   unsigned char *buffer;
00408   int pos;
00409   rpl_dag_t *dag = instance->current_dag;
00410 #if !RPL_LEAF_ONLY
00411   uip_ipaddr_t addr;
00412 #endif /* !RPL_LEAF_ONLY */
00413 
00414 #if RPL_LEAF_ONLY
00415   /* In leaf mode, we send DIO message only as unicasts in response to 
00416      unicast DIS messages. */
00417   if(uc_addr == NULL) {
00418     return;
00419   }
00420 #endif /* RPL_LEAF_ONLY */
00421 
00422   /* DAG Information Object */
00423   pos = 0;
00424 
00425   buffer = UIP_ICMP_PAYLOAD;
00426   buffer[pos++] = instance->instance_id;
00427   buffer[pos++] = dag->version;
00428 
00429 #if RPL_LEAF_ONLY
00430   set16(buffer, pos, INFINITE_RANK);
00431 #else /* RPL_LEAF_ONLY */
00432   set16(buffer, pos, dag->rank);
00433 #endif /* RPL_LEAF_ONLY */
00434   pos += 2;
00435 
00436   buffer[pos] = 0;
00437   if(dag->grounded) {
00438     buffer[pos] |= RPL_DIO_GROUNDED;
00439   }
00440 
00441   buffer[pos] |= instance->mop << RPL_DIO_MOP_SHIFT;
00442   buffer[pos] |= dag->preference & RPL_DIO_PREFERENCE_MASK;
00443   pos++;
00444 
00445   buffer[pos++] = instance->dtsn_out;
00446 
00447   /* always request new DAO to refresh route */
00448   RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
00449 
00450   /* reserved 2 bytes */
00451   buffer[pos++] = 0; /* flags */
00452   buffer[pos++] = 0; /* reserved */
00453 
00454   memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
00455   pos += 16;
00456 
00457 #if !RPL_LEAF_ONLY
00458   if(instance->mc.type != RPL_DAG_MC_NONE) {
00459     instance->of->update_metric_container(instance);
00460 
00461     buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER;
00462     buffer[pos++] = 6;
00463     buffer[pos++] = instance->mc.type;
00464     buffer[pos++] = instance->mc.flags >> 1;
00465     buffer[pos] = (instance->mc.flags & 1) << 7;
00466     buffer[pos++] |= (instance->mc.aggr << 4) | instance->mc.prec;
00467     if(instance->mc.type == RPL_DAG_MC_ETX) {
00468       buffer[pos++] = 2;
00469       set16(buffer, pos, instance->mc.obj.etx);
00470       pos += 2;
00471     } else if(instance->mc.type == RPL_DAG_MC_ENERGY) {
00472       buffer[pos++] = 2;
00473       buffer[pos++] = instance->mc.obj.energy.flags;
00474       buffer[pos++] = instance->mc.obj.energy.energy_est;
00475     } else {
00476       PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type %u\n",
00477         (unsigned)instance->mc.type);
00478       return;
00479     }
00480   }
00481 #endif /* !RPL_LEAF_ONLY */
00482 
00483   /* Always add a DAG configuration option. */
00484   buffer[pos++] = RPL_OPTION_DAG_CONF;
00485   buffer[pos++] = 14;
00486   buffer[pos++] = 0; /* No Auth, PCS = 0 */
00487   buffer[pos++] = instance->dio_intdoubl;
00488   buffer[pos++] = instance->dio_intmin;
00489   buffer[pos++] = instance->dio_redundancy;
00490   set16(buffer, pos, instance->max_rankinc);
00491   pos += 2;
00492   set16(buffer, pos, instance->min_hoprankinc);
00493   pos += 2;
00494   /* OCP is in the DAG_CONF option */
00495   set16(buffer, pos, instance->of->ocp);
00496   pos += 2;
00497   buffer[pos++] = 0; /* reserved */
00498   buffer[pos++] = instance->default_lifetime;
00499   set16(buffer, pos, instance->lifetime_unit);
00500   pos += 2;
00501 
00502   /* Check if we have a prefix to send also. */
00503   if(dag->prefix_info.length > 0) {
00504     buffer[pos++] = RPL_OPTION_PREFIX_INFO;
00505     buffer[pos++] = 30; /* always 30 bytes + 2 long */
00506     buffer[pos++] = dag->prefix_info.length;
00507     buffer[pos++] = dag->prefix_info.flags;
00508     set32(buffer, pos, dag->prefix_info.lifetime);
00509     pos += 4;
00510     set32(buffer, pos, dag->prefix_info.lifetime);
00511     pos += 4;
00512     memset(&buffer[pos], 0, 4);
00513     pos += 4;
00514     memcpy(&buffer[pos], &dag->prefix_info.prefix, 16);
00515     pos += 16;
00516     PRINTF("RPL: Sending prefix info in DIO for ");
00517     PRINT6ADDR(&dag->prefix_info.prefix);
00518     PRINTF("\n");
00519   } else {
00520     PRINTF("RPL: No prefix to announce (len %d)\n",
00521            dag->prefix_info.length);
00522   }
00523 
00524 #if RPL_LEAF_ONLY
00525   PRINTF("RPL: Sending unicast-DIO with rank %u to ",
00526       (unsigned)dag->rank);
00527   PRINT6ADDR(uc_addr);
00528   PRINTF("\n");
00529   uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
00530 #else /* RPL_LEAF_ONLY */
00531   /* Unicast requests get unicast replies! */
00532   if(uc_addr == NULL) {
00533     PRINTF("RPL: Sending a multicast-DIO with rank %u\n",
00534         (unsigned)instance->current_dag->rank);
00535     uip_create_linklocal_rplnodes_mcast(&addr);
00536     uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DIO, pos);
00537   } else {
00538     PRINTF("RPL: Sending unicast-DIO with rank %u to ",
00539         (unsigned)instance->current_dag->rank);
00540     PRINT6ADDR(uc_addr);
00541     PRINTF("\n");
00542     uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
00543   }
00544 #endif /* RPL_LEAF_ONLY */
00545 }
00546 /*---------------------------------------------------------------------------*/
00547 static void
00548 dao_input(void)
00549 {
00550   uip_ipaddr_t dao_sender_addr;
00551   rpl_dag_t *dag;
00552   rpl_instance_t *instance;
00553   unsigned char *buffer;
00554   uint16_t sequence;
00555   uint8_t instance_id;
00556   uint8_t lifetime;
00557   uint8_t prefixlen;
00558   uint8_t flags;
00559   uint8_t subopt_type;
00560   uint8_t pathcontrol;
00561   uint8_t pathsequence;
00562   uip_ipaddr_t prefix;
00563   uip_ds6_route_t *rep;
00564   uint8_t buffer_length;
00565   int pos;
00566   int len;
00567   int i;
00568   int learned_from;
00569   rpl_parent_t *p;
00570 
00571   prefixlen = 0;
00572 
00573   uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
00574 
00575   /* Destination Advertisement Object */
00576   PRINTF("RPL: Received a DAO from ");
00577   PRINT6ADDR(&dao_sender_addr);
00578   PRINTF("\n");
00579 
00580   buffer = UIP_ICMP_PAYLOAD;
00581   buffer_length = uip_len - uip_l3_icmp_hdr_len;
00582 
00583   pos = 0;
00584   instance_id = buffer[pos++];
00585 
00586   instance = rpl_get_instance(instance_id);
00587   if(instance == NULL) {
00588     PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
00589            instance_id);
00590     return;
00591   }
00592 
00593   lifetime = instance->default_lifetime;
00594 
00595   flags = buffer[pos++];
00596   /* reserved */
00597   pos++;
00598   sequence = buffer[pos++];
00599 
00600   dag = instance->current_dag;
00601   /* Is the DAGID present? */
00602   if(flags & RPL_DAO_D_FLAG) {
00603     if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
00604       PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
00605       return;
00606     }
00607     pos += 16;
00608   } else {
00609     /* Perhaps, there are verification to do but ... */
00610   }
00611 
00612   /* Check if there are any RPL options present. */
00613   i = pos;
00614   for(; i < buffer_length; i += len) {
00615     subopt_type = buffer[i];
00616     if(subopt_type == RPL_OPTION_PAD1) {
00617       len = 1;
00618     } else {
00619       /* The option consists of a two-byte header and a payload. */
00620       len = 2 + buffer[i + 1];
00621     }
00622 
00623     switch(subopt_type) {
00624     case RPL_OPTION_TARGET:
00625       /* Handle the target option. */
00626       prefixlen = buffer[i + 3];
00627       memset(&prefix, 0, sizeof(prefix));
00628       memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
00629       break;
00630     case RPL_OPTION_TRANSIT:
00631       /* The path sequence and control are ignored. */
00632       pathcontrol = buffer[i + 3];
00633       pathsequence = buffer[i + 4];
00634       lifetime = buffer[i + 5];
00635       /* The parent address is also ignored. */
00636       break;
00637     }
00638   }
00639 
00640   PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
00641           (unsigned)lifetime, (unsigned)prefixlen);
00642   PRINT6ADDR(&prefix);
00643   PRINTF("\n");
00644 
00645   rep = uip_ds6_route_lookup(&prefix);
00646 
00647   if(lifetime == RPL_ZERO_LIFETIME) {
00648     /* No-Path DAO received; invoke the route purging routine. */
00649     if(rep != NULL && rep->state.saved_lifetime == 0 && rep->length == prefixlen) {
00650       PRINTF("RPL: Setting expiration timer for prefix ");
00651       PRINT6ADDR(&prefix);
00652       PRINTF("\n");
00653       rep->state.saved_lifetime = rep->state.lifetime;
00654       rep->state.lifetime = DAO_EXPIRATION_TIMEOUT;
00655     }
00656     return;
00657   }
00658 
00659   learned_from = uip_is_addr_mcast(&dao_sender_addr) ?
00660                  RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
00661 
00662   if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
00663     /* Check whether this is a DAO forwarding loop. */
00664     p = rpl_find_parent(dag, &dao_sender_addr);
00665     /* check if this is a new DAO registration with an "illegal" rank */
00666     /* if we already route to this node it is likely */
00667     if(p != NULL && DAG_RANK(p->rank, instance) < DAG_RANK(dag->rank, instance)) {
00668       PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
00669           DAG_RANK(p->rank, instance), DAG_RANK(dag->rank, instance));
00670       p->rank = INFINITE_RANK;
00671       p->updated = 1;
00672       return;
00673     }
00674   }
00675 
00676   rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
00677   if(rep == NULL) {
00678     RPL_STAT(rpl_stats.mem_overflows++);
00679     PRINTF("RPL: Could not add a route after receiving a DAO\n");
00680     return;
00681   }
00682 
00683   rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
00684   rep->state.learned_from = learned_from;
00685 
00686   if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
00687     if(dag->preferred_parent) {
00688       PRINTF("RPL: Forwarding DAO to parent ");
00689       PRINT6ADDR(&dag->preferred_parent->addr);
00690       PRINTF("\n");
00691       uip_icmp6_send(&dag->preferred_parent->addr,
00692                      ICMP6_RPL, RPL_CODE_DAO, buffer_length);
00693     }
00694     if(flags & RPL_DAO_K_FLAG) {
00695       dao_ack_output(instance, &dao_sender_addr, sequence);
00696     }
00697   }
00698 }
00699 /*---------------------------------------------------------------------------*/
00700 void
00701 dao_output(rpl_parent_t *n, uint8_t lifetime)
00702 {
00703   rpl_dag_t *dag;
00704   rpl_instance_t *instance;
00705   unsigned char *buffer;
00706   uint8_t prefixlen;
00707   uip_ipaddr_t prefix;
00708   int pos;
00709 
00710   /* Destination Advertisement Object */
00711 
00712   if(get_global_addr(&prefix) == 0) {
00713     PRINTF("RPL: No global address set for this node - suppressing DAO\n");
00714     return;
00715   }
00716 
00717   dag = n->dag;
00718   instance = dag->instance;
00719 
00720 #ifdef RPL_DEBUG_DAO_OUTPUT
00721   RPL_DEBUG_DAO_OUTPUT(n);
00722 #endif
00723 
00724   buffer = UIP_ICMP_PAYLOAD;
00725 
00726   RPL_LOLLIPOP_INCREMENT(dao_sequence);
00727   pos = 0;
00728 
00729   buffer[pos++] = instance->instance_id;
00730   buffer[pos] = 0;
00731 #if RPL_DAO_SPECIFY_DAG
00732   buffer[pos] |= RPL_DAO_D_FLAG;
00733 #endif /* RPL_DAO_SPECIFY_DAG */
00734 #if RPL_CONF_DAO_ACK
00735   buffer[pos] |= RPL_DAO_K_FLAG;
00736 #endif /* RPL_CONF_DAO_ACK */
00737   ++pos;
00738   buffer[pos++] = 0; /* reserved */
00739   buffer[pos++] = dao_sequence;
00740 #if RPL_DAO_SPECIFY_DAG
00741   memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
00742   pos+=sizeof(dag->dag_id);
00743 #endif /* RPL_DAO_SPECIFY_DAG */
00744 
00745   /* create target subopt */
00746   prefixlen = sizeof(prefix) * CHAR_BIT;
00747   buffer[pos++] = RPL_OPTION_TARGET;
00748   buffer[pos++] = 2 + ((prefixlen + 7) / CHAR_BIT);
00749   buffer[pos++] = 0; /* reserved */
00750   buffer[pos++] = prefixlen;
00751   memcpy(buffer + pos, &prefix, (prefixlen + 7) / CHAR_BIT);
00752   pos += ((prefixlen + 7) / CHAR_BIT);
00753 
00754   /* Create a transit information sub-option. */
00755   buffer[pos++] = RPL_OPTION_TRANSIT;
00756   buffer[pos++] = 4;
00757   buffer[pos++] = 0; /* flags - ignored */
00758   buffer[pos++] = 0; /* path control - ignored */
00759   buffer[pos++] = 0; /* path seq - ignored */
00760   buffer[pos++] = lifetime;
00761 
00762   PRINTF("RPL: Sending DAO with prefix ");
00763   PRINT6ADDR(&prefix);
00764   PRINTF(" to ");
00765   PRINT6ADDR(&n->addr);
00766   PRINTF("\n");
00767 
00768   uip_icmp6_send(&n->addr, ICMP6_RPL, RPL_CODE_DAO, pos);
00769 }
00770 /*---------------------------------------------------------------------------*/
00771 static void
00772 dao_ack_input(void)
00773 {
00774   unsigned char *buffer;
00775   uint8_t buffer_length;
00776   uint8_t instance_id;
00777   uint8_t sequence;
00778   uint8_t status;
00779 
00780   buffer = UIP_ICMP_PAYLOAD;
00781   buffer_length = uip_len - uip_l3_icmp_hdr_len;
00782 
00783   instance_id = buffer[0];
00784   sequence = buffer[2];
00785   status = buffer[3];
00786 
00787   PRINTF("RPL: Received a DAO ACK with sequence number %d and status %d from ",
00788     sequence, status);
00789   PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
00790   PRINTF("\n");
00791 }
00792 /*---------------------------------------------------------------------------*/
00793 void
00794 dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence)
00795 {
00796   unsigned char *buffer;
00797 
00798   PRINTF("RPL: Sending a DAO ACK with sequence number %d to ", sequence);
00799   PRINT6ADDR(dest);
00800   PRINTF("\n");
00801 
00802   buffer = UIP_ICMP_PAYLOAD;
00803 
00804   buffer[0] = instance->instance_id;
00805   buffer[1] = 0;
00806   buffer[2] = sequence;
00807   buffer[3] = 0;
00808 
00809   uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
00810 }
00811 /*---------------------------------------------------------------------------*/
00812 void
00813 uip_rpl_input(void)
00814 {
00815   PRINTF("Received an RPL control message\n");
00816   switch(UIP_ICMP_BUF->icode) {
00817   case RPL_CODE_DIO:
00818     dio_input();
00819     break;
00820   case RPL_CODE_DIS:
00821     dis_input();
00822     break;
00823   case RPL_CODE_DAO:
00824     dao_input();
00825     break;
00826   case RPL_CODE_DAO_ACK:
00827     dao_ack_input();
00828     break;
00829   default:
00830     PRINTF("RPL: received an unknown ICMP6 code (%u)\n", UIP_ICMP_BUF->icode);
00831     break;
00832   }
00833 
00834   uip_len = 0;
00835 }