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 static uint8_t dao_sequence;
00076 /*---------------------------------------------------------------------------*/
00077 static int
00078 get_global_addr(uip_ipaddr_t *addr)
00079 {
00080   int i;
00081   int state;
00082 
00083   for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
00084     state = uip_ds6_if.addr_list[i].state;
00085     if(uip_ds6_if.addr_list[i].isused &&
00086        (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
00087       if(!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
00088         memcpy(addr, &uip_ds6_if.addr_list[i].ipaddr, sizeof(uip_ipaddr_t));
00089         return 1;
00090       }
00091     }
00092   }
00093   return 0;
00094 }
00095 /*---------------------------------------------------------------------------*/
00096 static uint32_t
00097 get32(uint8_t *buffer, int pos)
00098 {
00099   return (uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
00100          (uint32_t)buffer[pos + 2] << 8  | buffer[pos + 3];
00101 }
00102 /*---------------------------------------------------------------------------*/
00103 static void
00104 set32(uint8_t *buffer, int pos, uint32_t value)
00105 {
00106   buffer[pos++] = value >> 24;
00107   buffer[pos++] = (value >> 16) & 0xff;
00108   buffer[pos++] = (value >> 8) & 0xff;
00109   buffer[pos++] = value & 0xff;
00110 }
00111 /*---------------------------------------------------------------------------*/
00112 static void
00113 dis_input(void)
00114 {
00115   rpl_dag_t *dag;
00116 
00117   /* DAG Information Solicitation */
00118   PRINTF("RPL: Received a DIS from ");
00119   PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
00120   PRINTF("\n");
00121 
00122   dag = rpl_get_dag(RPL_ANY_INSTANCE);
00123   if(dag != NULL) {
00124     if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
00125       PRINTF("RPL: Multicast DIS => reset DIO timer\n");
00126       rpl_reset_dio_timer(dag, 0);
00127     } else {
00128       PRINTF("RPL: Unicast DIS, reply to sender\n");
00129       dio_output(dag, &UIP_IP_BUF->srcipaddr);
00130     }
00131   }
00132 }
00133 /*---------------------------------------------------------------------------*/
00134 void
00135 dis_output(uip_ipaddr_t *addr)
00136 {
00137   unsigned char *buffer;
00138   uip_ipaddr_t tmpaddr;
00139 
00140   /* DAG Information Solicitation  - 2 bytes reserved */
00141   /*      0                   1                   2        */
00142   /*      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3  */
00143   /*     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
00144   /*     |     Flags     |   Reserved    |   Option(s)...  */
00145   /*     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
00146 
00147   buffer = UIP_ICMP_PAYLOAD;
00148   buffer[0] = buffer[1] = 0;
00149 
00150   if(addr == NULL) {
00151     PRINTF("RPL: Sending a DIS\n");
00152     uip_create_linklocal_rplnodes_mcast(&tmpaddr);
00153     addr = &tmpaddr;
00154   } else {
00155     PRINTF("RPL: Sending a unicast DIS\n");
00156   }
00157   uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIS, 2);
00158 }
00159 /*---------------------------------------------------------------------------*/
00160 static void
00161 dio_input(void)
00162 {
00163   unsigned char *buffer;
00164   uint8_t buffer_length;
00165   rpl_dio_t dio;
00166   uint8_t subopt_type;
00167   int i;
00168   int len;
00169   uip_ipaddr_t from;
00170   uip_ds6_nbr_t *nbr;
00171 
00172   dio.dag_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS;
00173   dio.dag_intmin = DEFAULT_DIO_INTERVAL_MIN;
00174   dio.dag_redund = DEFAULT_DIO_REDUNDANCY;
00175 
00176   uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);
00177 
00178   /* DAG Information Object */
00179   PRINTF("RPL: Received a DIO from ");
00180   PRINT6ADDR(&from);
00181   PRINTF("\n");
00182 
00183   if((nbr = uip_ds6_nbr_lookup(&from)) == NULL) {
00184     if((nbr = uip_ds6_nbr_add(&from, (uip_lladdr_t *)
00185                               packetbuf_addr(PACKETBUF_ADDR_SENDER),
00186                               0, NBR_REACHABLE)) != NULL) {
00187       /* set reachable timer */
00188       stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
00189       PRINTF("RPL: Neighbor added to neighbor cache ");
00190       PRINT6ADDR(&from);
00191       PRINTF(", ");
00192       PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
00193       PRINTF("\n");
00194     }
00195   } else {
00196     PRINTF("RPL: Neighbor already in neighbor cache\n");
00197   }
00198 
00199   buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
00200 
00201   /* Process the DIO base option. */
00202   i = 0;
00203   buffer = UIP_ICMP_PAYLOAD;
00204 
00205   dio.instance_id = buffer[i++];
00206   dio.version = buffer[i++];
00207   dio.rank = (buffer[i] << 8) | buffer[i + 1];
00208   i += 2;
00209 
00210   PRINTF("RPL: Incoming DIO rank %u\n", (unsigned)dio.rank);
00211 
00212   dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
00213   dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
00214   dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;
00215 
00216   dio.dtsn = buffer[i++];
00217   /* two reserved bytes */
00218   i += 2;
00219 
00220   memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
00221   i += sizeof(dio.dag_id);
00222 
00223   /* Check if there are any DIO suboptions. */
00224   for(; i < buffer_length; i += len) {
00225     subopt_type = buffer[i];
00226     if(subopt_type == RPL_DIO_SUBOPT_PAD1) {
00227       len = 1;
00228     } else {
00229       /* Suboption with a two-byte header + payload */
00230       len = 2 + buffer[i + 1];
00231     }
00232 
00233     if(len + i > buffer_length) {
00234       PRINTF("RPL: Invalid DIO packet\n");
00235       RPL_STAT(rpl_stats.malformed_msgs++);
00236       return;
00237     }
00238 
00239     PRINTF("RPL: DIO suboption %u, length: %u\n", subopt_type, len - 2);
00240 
00241     switch(subopt_type) {
00242     case RPL_DIO_SUBOPT_DAG_METRIC_CONTAINER:
00243       if(len < 6) {
00244         PRINTF("RPL: Invalid DAG MC, len = %d\n", len);
00245         RPL_STAT(rpl_stats.malformed_msgs++);
00246         return;
00247       }
00248       dio.mc.type = buffer[i + 2];
00249       dio.mc.flags = buffer[i + 3];
00250       dio.mc.aggr = buffer[i + 4] >> 4;
00251       dio.mc.prec = buffer[i + 4] & 0xf;
00252       dio.mc.length = buffer[i + 5];
00253 
00254       if(dio.mc.type == RPL_DAG_MC_ETX) {
00255         dio.mc.obj.etx = buffer[i + 6] << 8;
00256         dio.mc.obj.etx |= buffer[i + 7];
00257 
00258         PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
00259                (unsigned)dio.mc.type,  
00260                (unsigned)dio.mc.flags, 
00261                (unsigned)dio.mc.aggr, 
00262                (unsigned)dio.mc.prec, 
00263                (unsigned)dio.mc.length, 
00264                (unsigned)dio.mc.obj.etx);
00265       } else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
00266         dio.mc.obj.energy.flags = buffer[i + 6];
00267         dio.mc.obj.energy.energy_est = buffer[i + 7];
00268       } else {
00269        PRINTF("RPL: Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type);
00270        return;
00271       }
00272       break;
00273     case RPL_DIO_SUBOPT_ROUTE_INFO:
00274       if(len < 9) {
00275         PRINTF("RPL: Invalid destination prefix option, len = %d\n", len);
00276         RPL_STAT(rpl_stats.malformed_msgs++);
00277         return;
00278       }
00279 
00280       /* flags is both preference and flags for now */
00281       dio.destination_prefix.length = buffer[i + 2];
00282       dio.destination_prefix.flags = buffer[i + 3];
00283       dio.destination_prefix.lifetime = get32(buffer, i + 4);
00284 
00285       if(((dio.destination_prefix.length + 7)/ 8) + 8 <= len &&
00286          dio.destination_prefix.length <= 128) {
00287         PRINTF("RPL: Copying destination prefix\n");
00288         memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
00289                (dio.destination_prefix.length + 7) / 8);
00290       } else {
00291         PRINTF("RPL: Invalid route infoprefix option, len = %d\n", len);
00292         RPL_STAT(rpl_stats.malformed_msgs++);
00293         return;
00294       }
00295 
00296       break;
00297     case RPL_DIO_SUBOPT_DAG_CONF:
00298       if(len != 16) {
00299         PRINTF("RPL: Invalid DAG configuration option, len = %d\n", len);
00300         RPL_STAT(rpl_stats.malformed_msgs++);
00301         return;
00302       }
00303 
00304       /* Path control field not yet implemented - at i + 2 */
00305       dio.dag_intdoubl = buffer[i + 3];
00306       dio.dag_intmin = buffer[i + 4];
00307       dio.dag_redund = buffer[i + 5];
00308       dio.dag_max_rankinc = (buffer[i + 6] << 8) | buffer[i + 7];
00309       dio.dag_min_hoprankinc = (buffer[i + 8] << 8) | buffer[i + 9];
00310       dio.ocp = (buffer[i + 10] << 8) | buffer[i + 11];
00311       /* buffer + 12 is reserved */
00312       dio.default_lifetime = buffer[i + 13];
00313       dio.lifetime_unit = (buffer[i + 14] << 8) | buffer[i + 15];
00314       PRINTF("RPL: DIO Conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
00315              dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
00316              dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
00317              dio.default_lifetime, dio.lifetime_unit);
00318       break;
00319     case RPL_DIO_SUBOPT_PREFIX_INFO:
00320       if(len != 32) {
00321         PRINTF("RPL: DAG Prefix info not ok, len != 32\n");
00322         RPL_STAT(rpl_stats.malformed_msgs++);
00323         return;
00324       }
00325       dio.prefix_info.length = buffer[i + 2];
00326       dio.prefix_info.flags = buffer[i + 3];
00327       /* valid lifetime is ingnored for now - at i + 4 */
00328       /* preferred lifetime stored in lifetime */
00329       dio.prefix_info.lifetime = get32(buffer, i + 8);
00330       /* 32-bit reserved at i + 12 */
00331       PRINTF("RPL: Copying prefix information\n");
00332       memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
00333       break;
00334     default:
00335       PRINTF("RPL: Unsupported suboption type in DIO: %u\n",
00336         (unsigned)subopt_type);
00337     }
00338   }
00339 
00340   rpl_process_dio(&from, &dio);
00341 }
00342 /*---------------------------------------------------------------------------*/
00343 void
00344 dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr)
00345 {
00346   unsigned char *buffer;
00347   int pos;
00348   uip_ipaddr_t addr;
00349 
00350   /* DAG Information Object */
00351   pos = 0;
00352 
00353   buffer = UIP_ICMP_PAYLOAD;
00354   buffer[pos++] = dag->instance_id;
00355   buffer[pos++] = dag->version;
00356   buffer[pos++] = dag->rank >> 8;
00357   buffer[pos++] = dag->rank & 0xff;
00358 
00359   buffer[pos] = 0;
00360   if(dag->grounded) {
00361     buffer[pos] |= RPL_DIO_GROUNDED;
00362   }
00363 
00364   buffer[pos] = dag->mop << RPL_DIO_MOP_SHIFT;
00365   pos++;
00366 
00367   buffer[pos++] = ++dag->dtsn_out;
00368 
00369   /* reserved 2 bytes */
00370   buffer[pos++] = 0; /* flags */
00371   buffer[pos++] = 0; /* reserved */
00372 
00373   memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
00374   pos += 16;
00375 
00376   if(dag->mc.type != RPL_DAG_MC_NONE) {
00377     dag->of->update_metric_container(dag);
00378 
00379     buffer[pos++] = RPL_DIO_SUBOPT_DAG_METRIC_CONTAINER;
00380     buffer[pos++] = 6;
00381     buffer[pos++] = dag->mc.type;
00382     buffer[pos++] = dag->mc.flags;
00383     buffer[pos] = dag->mc.aggr << 4;
00384     buffer[pos++] |= dag->mc.prec;
00385     if(dag->mc.type == RPL_DAG_MC_ETX) {
00386       buffer[pos++] = 2;
00387       buffer[pos++] = dag->mc.obj.etx >> 8;
00388       buffer[pos++] = dag->mc.obj.etx & 0xff;
00389     } else if(dag->mc.type == RPL_DAG_MC_ENERGY) {
00390       buffer[pos++] = 2;
00391       buffer[pos++] = dag->mc.obj.energy.flags;
00392       buffer[pos++] = dag->mc.obj.energy.energy_est;
00393     } else {
00394       PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type %u\n",
00395         (unsigned)dag->mc.type);
00396       return;
00397     }
00398   }
00399 
00400   /* always add a sub-option for DAG configuration */
00401   buffer[pos++] = RPL_DIO_SUBOPT_DAG_CONF;
00402   buffer[pos++] = 14;
00403   buffer[pos++] = 0; /* No Auth, PCS = 0 */
00404   buffer[pos++] = dag->dio_intdoubl;
00405   buffer[pos++] = dag->dio_intmin;
00406   buffer[pos++] = dag->dio_redundancy;
00407   buffer[pos++] = dag->max_rankinc >> 8;
00408   buffer[pos++] = dag->max_rankinc & 0xff;
00409   buffer[pos++] = dag->min_hoprankinc >> 8;
00410   buffer[pos++] = dag->min_hoprankinc & 0xff;
00411   /* OCP is in the DAG_CONF option */
00412   buffer[pos++] = dag->of->ocp >> 8;
00413   buffer[pos++] = dag->of->ocp & 0xff;
00414   buffer[pos++] = 0; /* reserved */
00415   buffer[pos++] = dag->default_lifetime;
00416   buffer[pos++] = dag->lifetime_unit >> 8;
00417   buffer[pos++] = dag->lifetime_unit & 0xff;
00418 
00419   /* if prefix info length > 0 then we have a prefix to send! */
00420   if(dag->prefix_info.length > 0) {
00421     buffer[pos++] = RPL_DIO_SUBOPT_PREFIX_INFO;
00422     buffer[pos++] = 30; /* always 30 bytes + 2 long */
00423     buffer[pos++] = dag->prefix_info.length;
00424     buffer[pos++] = dag->prefix_info.flags;
00425     set32(buffer, pos, dag->prefix_info.lifetime);
00426     pos += 4;
00427     set32(buffer, pos, dag->prefix_info.lifetime);
00428     pos += 4;
00429     memset(&buffer[pos], 0, 4);
00430     pos += 4;
00431     memcpy(&buffer[pos], &dag->prefix_info.prefix, 16);
00432     pos += 16;
00433     PRINTF("RPL: Sending prefix info in DIO for ");
00434     PRINT6ADDR(&dag->prefix_info.prefix);
00435     PRINTF("\n");
00436   } else {
00437     PRINTF("RPL: No prefix to announce (len %d)\n",
00438            dag->prefix_info.length);
00439   }
00440 
00441   /* buffer[len++] = RPL_DIO_SUBOPT_PAD1; */
00442 
00443   /* Unicast requests get unicast replies! */
00444   if(uc_addr == NULL) {
00445     PRINTF("RPL: Sending a multicast-DIO with rank %u\n",
00446         (unsigned)dag->rank);
00447     uip_create_linklocal_rplnodes_mcast(&addr);
00448     uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DIO, pos);
00449   } else {
00450     PRINTF("RPL: Sending unicast-DIO with rank %u to ",
00451         (unsigned)dag->rank);
00452     PRINT6ADDR(uc_addr);
00453     PRINTF("\n");
00454     uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
00455   }
00456 }
00457 /*---------------------------------------------------------------------------*/
00458 static void
00459 dao_input(void)
00460 {
00461   uip_ipaddr_t dao_sender_addr;
00462   rpl_dag_t *dag;
00463   unsigned char *buffer;
00464   uint16_t sequence;
00465   uint8_t instance_id;
00466   uint32_t lifetime;
00467   uint8_t prefixlen;
00468   uint8_t flags;
00469   uint8_t subopt_type;
00470   uint8_t pathcontrol;
00471   uint8_t pathsequence;
00472   uip_ipaddr_t prefix;
00473   uip_ds6_route_t *rep;
00474   uint8_t buffer_length;
00475   int pos;
00476   int len;
00477   int i;
00478   int learned_from;
00479   rpl_parent_t *p;
00480 
00481   lifetime = 0;
00482   prefixlen = 0;
00483 
00484   uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
00485 
00486   /* Destination Advertisement Object */
00487   PRINTF("RPL: Received a DAO from ");
00488   PRINT6ADDR(&dao_sender_addr);
00489   PRINTF("\n");
00490 
00491   buffer = UIP_ICMP_PAYLOAD;
00492   buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
00493 
00494   pos = 0;
00495   instance_id = buffer[pos++];
00496 
00497   dag = rpl_get_dag(instance_id);
00498   if(dag == NULL) {
00499     PRINTF("RPL: Ignoring a DAO for a different RPL instance (%u)\n",
00500            instance_id);
00501     return;
00502   }
00503 
00504   flags = buffer[pos++];
00505   /* reserved */
00506   pos++;
00507   sequence = buffer[pos++];
00508 
00509   /* Is the DAGID present? */
00510   if(flags & RPL_DAO_D_FLAG) {
00511     /* currently the DAG ID is ignored since we only use global
00512        RPL Instance IDs... */
00513     pos += 16;
00514   }
00515 
00516   /* Check if there are any DIO suboptions. */
00517   i = pos;
00518   for(; i < buffer_length; i += len) {
00519     subopt_type = buffer[i];
00520     if(subopt_type == RPL_DIO_SUBOPT_PAD1) {
00521       len = 1;
00522     } else {
00523       /* Suboption with a two-byte header + payload */
00524       len = 2 + buffer[i + 1];
00525     }
00526 
00527     switch(subopt_type) {
00528     case RPL_DIO_SUBOPT_TARGET:
00529       /* handle the target option */
00530       prefixlen = buffer[i + 3];
00531       memset(&prefix, 0, sizeof(prefix));
00532       memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
00533       break;
00534     case RPL_DIO_SUBOPT_TRANSIT:
00535       /* path sequence and control ignored */
00536       pathcontrol = buffer[i + 3];
00537       pathsequence = buffer[i + 4];
00538       lifetime = buffer[i + 5];
00539       /* parent address also ignored */
00540       break;
00541     }
00542   }
00543 
00544   PRINTF("RPL: DAO lifetime: %lu, prefix length: %u prefix: ",
00545          (unsigned long)lifetime, (unsigned)prefixlen);
00546   PRINT6ADDR(&prefix);
00547   PRINTF("\n");
00548 
00549   if(lifetime == ZERO_LIFETIME) {
00550     /* No-Path DAO received; invoke the route purging routine. */
00551     rep = uip_ds6_route_lookup(&prefix);
00552     if(rep != NULL && rep->state.saved_lifetime == 0) {
00553       PRINTF("RPL: Setting expiration timer for prefix ");
00554       PRINT6ADDR(&prefix);
00555       PRINTF("\n");
00556       rep->state.saved_lifetime = rep->state.lifetime;
00557       rep->state.lifetime = DAO_EXPIRATION_TIMEOUT;
00558     }
00559     return;
00560   }
00561 
00562   learned_from = uip_is_addr_mcast(&dao_sender_addr) ?
00563                  RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
00564 
00565   if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
00566     /* Check if this is a DAO forwarding loop. */
00567     p = rpl_find_parent(dag, &dao_sender_addr);
00568     /* check if this is a new DAO registration with an "illegal" rank */
00569     /* if we already route to this node it is likely */
00570     if(p != NULL && DAG_RANK(p->rank, dag) < DAG_RANK(dag->rank, dag) 
00571       /* && uip_ds6_route_lookup(&prefix) == NULL*/) {
00572       PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
00573           DAG_RANK(p->rank, dag), DAG_RANK(dag->rank, dag));
00574       p->rank = INFINITE_RANK;
00575       p->updated = 1;
00576       return;
00577     }
00578   }
00579 
00580   rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
00581   if(rep == NULL) {
00582     RPL_STAT(rpl_stats.mem_overflows++);
00583     PRINTF("RPL: Could not add a route after receiving a DAO\n");
00584     return;
00585   } else {
00586     rep->state.lifetime = lifetime * dag->lifetime_unit;
00587     rep->state.learned_from = learned_from;
00588   }
00589 
00590   if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) {
00591     if(dag->preferred_parent) {
00592       PRINTF("RPL: Forwarding DAO to parent ");
00593       PRINT6ADDR(&dag->preferred_parent->addr);
00594       PRINTF("\n");
00595       uip_icmp6_send(&dag->preferred_parent->addr,
00596                      ICMP6_RPL, RPL_CODE_DAO, buffer_length);
00597     } else if(flags & RPL_DAO_K_FLAG) {
00598       dao_ack_output(dag, &dao_sender_addr, sequence);
00599     }
00600   }
00601 }
00602 /*---------------------------------------------------------------------------*/
00603 void
00604 dao_output(rpl_parent_t *n, uint32_t lifetime)
00605 {
00606   rpl_dag_t *dag;
00607   unsigned char *buffer;
00608   uint8_t prefixlen;
00609   uip_ipaddr_t addr;
00610   uip_ipaddr_t prefix;
00611   int pos;
00612 
00613   /* Destination Advertisement Object */
00614   if(get_global_addr(&prefix) == 0) {
00615     PRINTF("RPL: No global address set for this node - suppressing DAO\n");
00616     return;
00617   }
00618 
00619   if(n == NULL) {
00620     dag = rpl_get_dag(RPL_ANY_INSTANCE);
00621     if(dag == NULL) {
00622       PRINTF("RPL: Did not join a DAG before sending DAO\n");
00623       return;
00624     }
00625   } else {
00626     dag = n->dag;
00627   }
00628 
00629   buffer = UIP_ICMP_PAYLOAD;
00630 
00631   ++dao_sequence;
00632   pos = 0;
00633 
00634   buffer[pos++] = dag->instance_id;
00635 #if RPL_CONF_DAO_ACK
00636   buffer[pos++] = RPL_DAO_K_FLAG; /* DAO ACK request, no DODAGID */
00637 #else
00638   buffer[pos++] = 0; /* No DAO ACK request, no DODAGID */
00639 #endif
00640   buffer[pos++] = 0; /* reserved */
00641   buffer[pos++] = dao_sequence & 0xff;
00642 
00643   /* create target subopt */
00644   prefixlen = sizeof(prefix) * CHAR_BIT;
00645   buffer[pos++] = RPL_DIO_SUBOPT_TARGET;
00646   buffer[pos++] = 2 + ((prefixlen + 7) / CHAR_BIT);
00647   buffer[pos++] = 0; /* reserved */
00648   buffer[pos++] = prefixlen;
00649   memcpy(buffer + pos, &prefix, (prefixlen + 7) / CHAR_BIT);
00650   pos += ((prefixlen + 7) / CHAR_BIT);
00651 
00652   /* create a transit information subopt (RPL-18)*/
00653   buffer[pos++] = RPL_DIO_SUBOPT_TRANSIT;
00654   buffer[pos++] = 4;
00655   buffer[pos++] = 0; /* flags - ignored */
00656   buffer[pos++] = 0; /* path control - ignored */
00657   buffer[pos++] = 0; /* path seq - ignored */
00658   buffer[pos++] = (lifetime / dag->lifetime_unit) & 0xff;
00659 
00660   if(n == NULL) {
00661     uip_create_linklocal_rplnodes_mcast(&addr);
00662   } else {
00663     uip_ipaddr_copy(&addr, &n->addr);
00664   }
00665 
00666   PRINTF("RPL: Sending DAO with prefix ");
00667   PRINT6ADDR(&prefix);
00668   PRINTF(" to ");
00669   if(n != NULL) {
00670     PRINT6ADDR(&n->addr);
00671   } else {
00672     PRINTF("multicast address");
00673   }
00674   PRINTF("\n");
00675 
00676   uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DAO, pos);
00677 }
00678 /*---------------------------------------------------------------------------*/
00679 static void
00680 dao_ack_input(void)
00681 {
00682   unsigned char *buffer;
00683   uint8_t buffer_length;
00684   uint8_t instance_id;
00685   uint8_t sequence;
00686   uint8_t status;
00687 
00688   buffer = UIP_ICMP_PAYLOAD;
00689   buffer_length = uip_len - uip_l2_l3_icmp_hdr_len;
00690 
00691   instance_id = buffer[0];
00692   sequence = buffer[2];
00693   status = buffer[3];
00694 
00695   PRINTF("RPL: Received a DAO ACK with sequence number %d and status %d from ",
00696     sequence, status);
00697   PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
00698   PRINTF("\n");
00699 }
00700 /*---------------------------------------------------------------------------*/
00701 void
00702 dao_ack_output(rpl_dag_t *dag, uip_ipaddr_t *dest, uint8_t sequence)
00703 {
00704   unsigned char *buffer;
00705 
00706   PRINTF("RPL: Sending a DAO ACK with sequence number %d to ", sequence);
00707   PRINT6ADDR(dest);
00708   PRINTF("\n");
00709 
00710   buffer = UIP_ICMP_PAYLOAD;
00711 
00712   buffer[0] = dag->instance_id;
00713   buffer[1] = 0;
00714   buffer[2] = sequence;
00715   buffer[3] = 0;
00716 
00717   uip_icmp6_send(dest, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
00718 }
00719 /*---------------------------------------------------------------------------*/
00720 void
00721 uip_rpl_input(void)
00722 {
00723   PRINTF("Received an RPL control message\n");
00724   switch(UIP_ICMP_BUF->icode) {
00725   case RPL_CODE_DIO:
00726     dio_input();
00727     break;
00728   case RPL_CODE_DIS:
00729     dis_input();
00730     break;
00731   case RPL_CODE_DAO:
00732     dao_input();
00733     break;
00734   case RPL_CODE_DAO_ACK:
00735     dao_ack_input();
00736     break;
00737   default:
00738     PRINTF("RPL: received an unknown ICMP6 code (%u)\n", UIP_ICMP_BUF->icode);
00739     break;
00740   }
00741 
00742   uip_len = 0;
00743 }
00744 
00745 /** \} */

Generated on Mon Apr 11 14:23:31 2011 for Contiki 2.5 by  doxygen 1.6.1