00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
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
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
00141
00142
00143
00144
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
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
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
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
00218 i += 2;
00219
00220 memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
00221 i += sizeof(dio.dag_id);
00222
00223
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
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
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
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
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
00328
00329 dio.prefix_info.lifetime = get32(buffer, i + 8);
00330
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
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
00370 buffer[pos++] = 0;
00371 buffer[pos++] = 0;
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
00401 buffer[pos++] = RPL_DIO_SUBOPT_DAG_CONF;
00402 buffer[pos++] = 14;
00403 buffer[pos++] = 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
00412 buffer[pos++] = dag->of->ocp >> 8;
00413 buffer[pos++] = dag->of->ocp & 0xff;
00414 buffer[pos++] = 0;
00415 buffer[pos++] = dag->default_lifetime;
00416 buffer[pos++] = dag->lifetime_unit >> 8;
00417 buffer[pos++] = dag->lifetime_unit & 0xff;
00418
00419
00420 if(dag->prefix_info.length > 0) {
00421 buffer[pos++] = RPL_DIO_SUBOPT_PREFIX_INFO;
00422 buffer[pos++] = 30;
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
00442
00443
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
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
00506 pos++;
00507 sequence = buffer[pos++];
00508
00509
00510 if(flags & RPL_DAO_D_FLAG) {
00511
00512
00513 pos += 16;
00514 }
00515
00516
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
00524 len = 2 + buffer[i + 1];
00525 }
00526
00527 switch(subopt_type) {
00528 case RPL_DIO_SUBOPT_TARGET:
00529
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
00536 pathcontrol = buffer[i + 3];
00537 pathsequence = buffer[i + 4];
00538 lifetime = buffer[i + 5];
00539
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
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
00567 p = rpl_find_parent(dag, &dao_sender_addr);
00568
00569
00570 if(p != NULL && DAG_RANK(p->rank, dag) < DAG_RANK(dag->rank, dag)
00571 ) {
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
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;
00637 #else
00638 buffer[pos++] = 0;
00639 #endif
00640 buffer[pos++] = 0;
00641 buffer[pos++] = dao_sequence & 0xff;
00642
00643
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;
00648 buffer[pos++] = prefixlen;
00649 memcpy(buffer + pos, &prefix, (prefixlen + 7) / CHAR_BIT);
00650 pos += ((prefixlen + 7) / CHAR_BIT);
00651
00652
00653 buffer[pos++] = RPL_DIO_SUBOPT_TRANSIT;
00654 buffer[pos++] = 4;
00655 buffer[pos++] = 0;
00656 buffer[pos++] = 0;
00657 buffer[pos++] = 0;
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