Contiki 2.6
|
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 }