Contiki-NG
Loading...
Searching...
No Matches
rpl-ext-header.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009, Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/**
31 * \file
32 * Management of extension headers for ContikiRPL.
33 *
34 * \author Vincent Brillault <vincent.brillault@imag.fr>,
35 * Joakim Eriksson <joakime@sics.se>,
36 * Niclas Finne <nfi@sics.se>,
37 * Nicolas Tsiftes <nvt@sics.se>.
38 */
39
40/**
41 * \addtogroup uip
42 * @{
43 */
44
45#include "net/routing/routing.h"
46#include "net/ipv6/uip.h"
47#include "net/ipv6/tcpip.h"
48#include "net/ipv6/uip-ds6.h"
49#include "net/ipv6/uip-sr.h"
50#include "net/routing/rpl-classic/rpl-private.h"
51#include "net/packetbuf.h"
52
53#include "sys/log.h"
54
55#define LOG_MODULE "RPL"
56#define LOG_LEVEL LOG_LEVEL_RPL
57
58#include <limits.h>
59#include <string.h>
60
61/*---------------------------------------------------------------------------*/
62int
63rpl_ext_header_hbh_update(uint8_t *ext_buf, int opt_offset)
64{
65 rpl_instance_t *instance;
66 int down;
67 uint16_t sender_rank;
68 uint8_t sender_closer;
69 uip_ds6_route_t *route;
70 rpl_parent_t *sender;
71
72 /* RFC 6553: "This option has an alignment requirement of 2n." */
73 if(opt_offset < 0 || opt_offset & 1) {
74 LOG_ERR("Invalid RPL option offset: %d\n", opt_offset);
75 return 0;
76 }
77
78 struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)ext_buf;
79 struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(ext_buf + opt_offset);
80
81 if(hbh_hdr->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
82 || rpl_opt->opt_type != UIP_EXT_HDR_OPT_RPL
83 || rpl_opt->opt_len != RPL_HDR_OPT_LEN) {
84
85 LOG_ERR("Hop-by-hop extension header has wrong size or type (%u %u %u)\n",
86 hbh_hdr->len, rpl_opt->opt_type, rpl_opt->opt_len);
87 return 0; /* Drop */
88 }
89
90 instance = rpl_get_instance(rpl_opt->instance);
91 if(instance == NULL) {
92 LOG_ERR("Unknown instance: %u\n", rpl_opt->instance);
93 return 0;
94 }
95
96 if(rpl_opt->flags & RPL_HDR_OPT_FWD_ERR) {
97 LOG_ERR("Forward error!\n");
98 /*
99 * We should try to repair it by removing the neighbor that caused
100 * the packet to be forwarded in the first place. We drop any
101 * routes that go through the neighbor that sent the packet to us.
102 */
103 if(RPL_IS_STORING(instance)) {
104 route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
105 if(route != NULL) {
106 uip_ds6_route_rm(route);
107 }
108 }
109 RPL_STAT(rpl_stats.forward_errors++);
110 /* Trigger DAO retransmission. */
111 rpl_reset_dio_timer(instance);
112 /* Drop the packet because it is not routable. */
113 return 0;
114 }
115
116 if(!instance->current_dag->joined) {
117 LOG_ERR("No DAG in the instance\n");
118 return 0;
119 }
120 down = 0;
121 if(rpl_opt->flags & RPL_HDR_OPT_DOWN) {
122 down = 1;
123 }
124
125 sender_rank = UIP_HTONS(rpl_opt->senderrank);
126 sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER));
127
128 if(sender != NULL && (rpl_opt->flags & RPL_HDR_OPT_RANK_ERR)) {
129 /* A rank error was signaled -- attempt to repair it by updating
130 the sender's rank from the ext header. */
131 sender->rank = sender_rank;
132 if(RPL_IS_NON_STORING(instance)) {
133 /*
134 * Select DAG and preferred parent only in non-storing mode. In
135 * storing mode, a parent switch would result in an immediate
136 * no-path DAO transmission, dropping the current incoming
137 * packet.
138 */
139 rpl_select_dag(instance, sender);
140 }
141 }
142
143 sender_closer = sender_rank < instance->current_dag->rank;
144
145
146 LOG_DBG("Packet going %s, sender%s closer (%d < %d)\n",
147 down == 1 ? "down" : "up",
148 sender_closer ? "" : " not",
149 sender_rank,
150 instance->current_dag->rank);
151
152 if((down && !sender_closer) || (!down && sender_closer)) {
153 LOG_WARN("Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
154 sender_rank, instance->current_dag->rank,
155 sender_closer);
156 /* Attempt to repair the loop by sending a unicast DIO back to the
157 sender so that it gets a fresh update of our rank. */
158 if(sender != NULL) {
159 instance->unicast_dio_target = sender;
160 rpl_schedule_unicast_dio_immediately(instance);
161 }
162
163 if(rpl_opt->flags & RPL_HDR_OPT_RANK_ERR) {
164 RPL_STAT(rpl_stats.loop_errors++);
165 LOG_ERR("Rank error signaled in RPL option!\n");
166 /* Packet must be dropped and dio trickle timer reset, see
167 RFC6550 - 11.2.2.2 */
168 rpl_reset_dio_timer(instance);
169 return 0;
170 }
171
172 LOG_WARN("One inconsistency along path is tolerated\n");
173 RPL_STAT(rpl_stats.loop_warnings++);
174 rpl_opt->flags |= RPL_HDR_OPT_RANK_ERR;
175 return 1;
176 }
177
178 LOG_DBG("Rank OK\n");
179 return 1;
180}
181/*---------------------------------------------------------------------------*/
182int
183rpl_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr)
184{
185#if RPL_WITH_NON_STORING
186 struct uip_routing_hdr *rh_header;
187 rpl_dag_t *dag;
188 uip_sr_node_t *dest_node;
189 uip_sr_node_t *root_node;
190
191 /* Look for the routing ext header. */
192 rh_header = (struct uip_routing_hdr *)uipbuf_search_header(uip_buf, uip_len, UIP_PROTO_ROUTING);
193
194 dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
195 root_node = uip_sr_get_node(dag, &dag->dag_id);
196 dest_node = uip_sr_get_node(dag, &UIP_IP_BUF->destipaddr);
197
198 if((rh_header != NULL && rh_header->routing_type == RPL_RH_TYPE_SRH) ||
199 (dest_node != NULL && root_node != NULL &&
200 dest_node->parent == root_node)) {
201 /*
202 * A routing header was found or the packet was destined for a
203 * direct child of the root. The next hop should already be copied
204 * as the IPv6 destination address, via
205 * rpl_ext_header_srh_update. We turn this address into a
206 * link-local address to enable forwarding to next hop.
207 */
208 uip_ipaddr_copy(ipaddr, &UIP_IP_BUF->destipaddr);
209 uip_create_linklocal_prefix(ipaddr);
210 return 1;
211 }
212
213 return 0;
214#else /* RPL_WITH_NON_STORING */
215 return 0; /* SRH not found */
216#endif /* RPL_WITH_NON_STORING */
217}
218/*---------------------------------------------------------------------------*/
219#if RPL_WITH_NON_STORING
220static bool
221srh_is_valid(struct uip_routing_hdr *rh_header,
222 struct uip_rpl_srh_hdr *srh_header)
223{
224 uip_ipaddr_t hop_addr;
225 uip_ipaddr_copy(&hop_addr, &UIP_IP_BUF->destipaddr);
226
227 uint8_t segments_left = rh_header->seg_left;
228 uint8_t ext_len = rh_header->len * 8 + 8;
229 uint8_t cmpri = srh_header->cmpr >> 4;
230 uint8_t cmpre = srh_header->cmpr & 0x0f;
231 uint8_t padding = srh_header->pad >> 4;
232 uint8_t path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
233
234 bool prev_hop_is_my_addr = false;
235 uint8_t my_addr_count = 0;
236 for(uint8_t i = path_len - segments_left; i < path_len; i++) {
237 uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
238 ptrdiff_t rh_offset = (uint8_t *)rh_header - uip_buf;
239 size_t addr_offset = RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
240
241 if(rh_offset + addr_offset + 16 - cmpr > UIP_BUFSIZE) {
242 return false;
243 }
244
245 uint8_t *addr_ptr = (uint8_t *)rh_header + addr_offset;
246 memcpy((uint8_t *)&hop_addr + cmpr, addr_ptr, 16 - cmpr);
247
248 LOG_DBG("Processing SRH hop %u, IP addr ", i);
249 LOG_DBG_6ADDR(&hop_addr);
250 LOG_DBG_("\n");
251
252 /*
253 * RFC 6554 states that "To detect loops in the SRH, a router MUST
254 * determine if the SRH includes multiple addresses assigned to
255 * any interface on that router. If such addresses appear more
256 * than once and are separated by at least one address not
257 * assigned to that router, the router MUST drop the packet."
258 *
259 * We add further checks of unacceptable next hop addresses.
260 */
261 if(uip_ds6_is_my_addr(&hop_addr) ||
262 uip_ds6_is_my_maddr(&hop_addr)) {
263 my_addr_count++;
264 if(!prev_hop_is_my_addr && my_addr_count > 1) {
265 LOG_WARN("SRH contains a loop\n");
266 return false;
267 }
268 prev_hop_is_my_addr = true;
269 } else {
270 prev_hop_is_my_addr = false;
271 }
272
273 if(uip_is_addr_mcast(&hop_addr) ||
274 uip_is_addr_unspecified(&hop_addr) ||
275 uip_is_addr_loopback(&hop_addr)) {
276 LOG_WARN("SRH contains an invalid next hop address\n");
277 return false;
278 }
279 }
280
281 return true;
282}
283#endif /* RPL_WITH_NON_STORING */
284/*---------------------------------------------------------------------------*/
285int
286rpl_ext_header_srh_update(void)
287{
288#if RPL_WITH_NON_STORING
289 struct uip_routing_hdr *rh_header;
290 struct uip_rpl_srh_hdr *srh_header;
291
292 /* Look for routing ext header */
293 rh_header = (struct uip_routing_hdr *)uipbuf_search_header(uip_buf, uip_len,
294 UIP_PROTO_ROUTING);
295
296 if(rh_header != NULL && rh_header->routing_type == RPL_RH_TYPE_SRH) {
297 /* SRH found, now look for next hop */
298 uint8_t cmpri, cmpre;
299 uint8_t ext_len;
300 uint8_t padding;
301 uint8_t path_len;
302 uint8_t segments_left;
303 uip_ipaddr_t current_dest_addr;
304
305 srh_header = (struct uip_rpl_srh_hdr *)(((uint8_t *)rh_header) + RPL_RH_LEN);
306 segments_left = rh_header->seg_left;
307 ext_len = rh_header->len * 8 + 8;
308 cmpri = srh_header->cmpr >> 4;
309 cmpre = srh_header->cmpr & 0x0f;
310 padding = srh_header->pad >> 4;
311 path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
312 (void)path_len;
313
314 LOG_DBG("read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n",
315 path_len, segments_left, cmpri, cmpre, ext_len, padding);
316
317 if(segments_left == 0) {
318 /* We are the final destination, do nothing. */
319 } else if(segments_left > path_len) {
320 /* Discard the packet because of a parameter problem. */
321 LOG_ERR("SRH with too many segments left (%u > %u)\n",
322 segments_left, path_len);
323 return 0;
324 } else {
325 if(!srh_is_valid(rh_header, srh_header)) {
326 LOG_ERR("Invalid SRH hop sequence\n");
327 return 0;
328 }
329
330 /* The index of the next address to be visited. */
331 uint8_t i = path_len - segments_left;
332 uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
333 ptrdiff_t rh_offset = (uint8_t *)rh_header - uip_buf;
334 size_t addr_offset = RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
335
336 if(rh_offset + addr_offset + 16 - cmpr > UIP_BUFSIZE) {
337 LOG_ERR("Invalid SRH address pointer\n");
338 return 0;
339 }
340
341 uint8_t *addr_ptr = ((uint8_t *)rh_header) + addr_offset;
342
343 /* As per RFC6554: swap the IPv6 destination address and address[i]. */
344
345 /* First, copy the current IPv6 destination address. */
346 uip_ipaddr_copy(&current_dest_addr, &UIP_IP_BUF->destipaddr);
347 /* Second, update the IPv6 destination address with addresses[i]. */
348 memcpy(((uint8_t *)&UIP_IP_BUF->destipaddr) + cmpr, addr_ptr, 16 - cmpr);
349 /* Third, write current_dest_addr to addresses[i]. */
350 memcpy(addr_ptr, ((uint8_t *)&current_dest_addr) + cmpr, 16 - cmpr);
351
352 /* Update segments left field */
353 rh_header->seg_left--;
354
355 LOG_INFO("SRH next hop ");
356 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
357 LOG_INFO_("\n");
358 }
359 return 1;
360 }
361
362 return 0;
363#else /* RPL_WITH_NON_STORING */
364 return 0; /* SRH not found */
365#endif /* RPL_WITH_NON_STORING */
366}
367/*---------------------------------------------------------------------------*/
368static int
369count_matching_bytes(const void *p1, const void *p2, size_t n)
370{
371 for(size_t i = 0; i < n; i++) {
372 if(((uint8_t *)p1)[i] != ((uint8_t *)p2)[i]) {
373 return i;
374 }
375 }
376 return n;
377}
378/*---------------------------------------------------------------------------*/
379static int
380insert_srh_header(void)
381{
382 /* Implementation of RFC6554. */
383 uint8_t path_len;
384 uint8_t ext_len;
385 uint8_t cmpri, cmpre; /* ComprI and ComprE fields of the RPL Source Routing Header. */
386 uint8_t *hop_ptr;
387 uint8_t padding;
388 uip_sr_node_t *dest_node;
389 uip_sr_node_t *root_node;
390 uip_sr_node_t *node;
391 rpl_dag_t *dag;
392 uip_ipaddr_t node_addr;
393
394 /* Always insert the SRH as the first extension header. */
395 struct uip_routing_hdr *rh_hdr = (struct uip_routing_hdr *)UIP_IP_PAYLOAD(0);
396 struct uip_rpl_srh_hdr *srh_hdr = (struct uip_rpl_srh_hdr *)(UIP_IP_PAYLOAD(0) + RPL_RH_LEN);
397
398 LOG_INFO("SRH creating source routing header with destination ");
399 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
400 LOG_INFO_("\n");
401
402 /* Construct source route. We do not do this recursively to keep the
403 runtime stack usage constant. */
404
405 /* Get link of the destination and root. */
406 dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
407 if(dag == NULL) {
408 LOG_ERR("SRH DAG not found\n");
409 return 0;
410 }
411
412 dest_node = uip_sr_get_node(dag, &UIP_IP_BUF->destipaddr);
413 if(dest_node == NULL) {
414 /* The destination was not found, skip SRH insertion. */
415 return 1;
416 }
417
418 root_node = uip_sr_get_node(dag, &dag->dag_id);
419 if(root_node == NULL) {
420 LOG_ERR("SRH root node not found\n");
421 return 0;
422 }
423
424 if(!uip_sr_is_addr_reachable(dag, &UIP_IP_BUF->destipaddr)) {
425 LOG_ERR("SRH no path found to destination\n");
426 return 0;
427 }
428
429 /* Compute path length and compression factors. (We use cmpri == cmpre.) */
430 path_len = 0;
431 node = dest_node->parent;
432 /* For simplicity, we use cmpri = cmpre. */
433 cmpri = 15;
434 cmpre = 15;
435
436 if(node == root_node) {
437 LOG_DBG("SRH no need to insert SRH\n");
438 return 1;
439 }
440
441 while(node != NULL && node != root_node) {
442
443 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
444
445 /* How many bytes in common between all nodes in the path? */
446 cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &UIP_IP_BUF->destipaddr, 16));
447 cmpre = cmpri;
448
449 LOG_DBG("SRH Hop ");
450 LOG_DBG_6ADDR(&node_addr);
451 LOG_DBG_("\n");
452 node = node->parent;
453 path_len++;
454 }
455
456 /* Extension header length:
457 fixed headers + (n - 1) * (16 - ComprI) + (16 - ComprE). */
458 ext_len = RPL_RH_LEN + RPL_SRH_LEN
459 + (path_len - 1) * (16 - cmpre)
460 + (16 - cmpri);
461
462 padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8));
463 ext_len += padding;
464
465 LOG_DBG("SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n",
466 path_len, cmpri, cmpre, ext_len, padding);
467
468 /* Check if there is enough space to store the extension header. */
469 if(uip_len + ext_len > UIP_LINK_MTU) {
470 LOG_ERR("Too long packet: impossible to add SRH (%u bytes)\n", ext_len);
471 return 0;
472 }
473
474 /* Move existing ext headers and payload ext_len further. */
475 memmove(uip_buf + UIP_IPH_LEN + uip_ext_len + ext_len,
476 uip_buf + UIP_IPH_LEN + uip_ext_len, uip_len - UIP_IPH_LEN);
477 memset(uip_buf + UIP_IPH_LEN + uip_ext_len, 0, ext_len);
478
479 /* Insert source routing header (as first ext header). */
480 rh_hdr->next = UIP_IP_BUF->proto;
481 UIP_IP_BUF->proto = UIP_PROTO_ROUTING;
482
483 /* Initialize IPv6 Routing Header. */
484 rh_hdr->len = (ext_len - 8) / 8;
485 rh_hdr->routing_type = RPL_RH_TYPE_SRH;
486 rh_hdr->seg_left = path_len;
487
488 /* Initialize RPL Source Routing Header. */
489 srh_hdr->cmpr = (cmpri << 4) + cmpre;
490 srh_hdr->pad = padding << 4;
491
492 /* Initialize the addresses field (the actual source route).
493 From last to first. */
494 node = dest_node;
495
496 /* Pointer where to write the next hop compressed address. */
497 hop_ptr = ((uint8_t *)rh_hdr) + ext_len - padding;
498
499 while(node != NULL && node->parent != root_node) {
500 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
501
502 hop_ptr -= (16 - cmpri);
503 memcpy(hop_ptr, ((uint8_t *)&node_addr) + cmpri, 16 - cmpri);
504
505 node = node->parent;
506 }
507
508 /* The next hop (i.e. node whose parent is the root) is placed as
509 the current IPv6 destination. */
510 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
511 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &node_addr);
512
513 /* Update the IPv6 length field. */
514 uipbuf_add_ext_hdr(ext_len);
515 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
516
517 return 1;
518}
519/*---------------------------------------------------------------------------*/
520static int
521update_hbh_header(void)
522{
523 rpl_instance_t *instance;
524 rpl_parent_t *parent;
525 struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
526 struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(0) + 2);
527
528 if(UIP_IP_BUF->proto == UIP_PROTO_HBHO &&
529 rpl_opt->opt_type == UIP_EXT_HDR_OPT_RPL) {
530 if(hbh_hdr->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8) ||
531 rpl_opt->opt_len != RPL_HDR_OPT_LEN) {
532
533 LOG_ERR("Hop-by-hop extension header has wrong size (%u)\n",
534 rpl_opt->opt_len);
535 return 0; /* Drop */
536 }
537
538 instance = rpl_get_instance(rpl_opt->instance);
539 if(instance == NULL || !instance->used || !instance->current_dag->joined) {
540 LOG_ERR("Unable to add/update hop-by-hop extension header: incorrect instance\n");
541 return 0; /* Drop */
542 }
543
544 LOG_INFO("Updating RPL option\n");
545 /* Update sender rank and instance, will update flags next. */
546 rpl_opt->senderrank = UIP_HTONS(instance->current_dag->rank);
547 rpl_opt->instance = instance->instance_id;
548
549 if(RPL_IS_STORING(instance)) {
550 /* In non-storing mode, downwards traffic does not have the HBH option. */
551
552 /*
553 * Check the direction of the down flag, as per Section
554 * 11.2.2.3, which states that if a packet is going down it
555 * should in general not go back up again. If this happens, a
556 * RPL_HDR_OPT_FWD_ERR should be flagged.
557 */
558 if(rpl_opt->flags & RPL_HDR_OPT_DOWN) {
559 if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
560 rpl_opt->flags |= RPL_HDR_OPT_FWD_ERR;
561 LOG_WARN("RPL forwarding error\n");
562 /* We should send back the packet to the originating parent,
563 but it is not feasible yet, so we send a No-Path DAO instead. */
564 LOG_WARN("RPL generate No-Path DAO\n");
565 parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
566 if(parent != NULL) {
567 rpl_schedule_unicast_dao_immediately(instance, parent,
568 &UIP_IP_BUF->destipaddr,
569 RPL_ZERO_LIFETIME);
570 }
571 /* Drop packet. */
572 return 0;
573 }
574 } else {
575 /*
576 * Set the down extension flag correctly as described in
577 * Section 11.2 of RFC6550. If the packet progresses along a
578 * DAO route, the down flag should be set.
579 */
580 if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
581 /* No route was found, so this packet will go towards the
582 RPL root. If so, we should not set the down flag. */
583 rpl_opt->flags &= ~RPL_HDR_OPT_DOWN;
584 LOG_DBG("RPL option going up\n");
585 } else {
586 /* A DAO route was found so we set the down flag. */
587 rpl_opt->flags |= RPL_HDR_OPT_DOWN;
588 LOG_DBG("RPL option going down\n");
589 }
590 }
591 }
592 }
593
594 return 1;
595}
596/*---------------------------------------------------------------------------*/
597static int
598insert_hbh_header(const rpl_instance_t *instance)
599{
600 struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
601 struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(2));
602
603 /* Insert hop-by-hop header. */
604 LOG_DBG("Creating hop-by-hop option\n");
605 if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_LINK_MTU) {
606 LOG_ERR("Too long packet: impossible to add hop-by-hop option\n");
607 return 0;
608 }
609
610 /* Move existing ext headers and payload RPL_HOP_BY_HOP_LEN further. */
611 memmove(UIP_IP_PAYLOAD(RPL_HOP_BY_HOP_LEN), UIP_IP_PAYLOAD(0),
612 uip_len - UIP_IPH_LEN);
613 memset(UIP_IP_PAYLOAD(0), 0, RPL_HOP_BY_HOP_LEN);
614
615 /* Insert the HBH header as the first ext header. */
616 hbh_hdr->next = UIP_IP_BUF->proto;
617 UIP_IP_BUF->proto = UIP_PROTO_HBHO;
618
619 /* Initialize the HBH option. */
620 hbh_hdr->len = (RPL_HOP_BY_HOP_LEN - 8) / 8;
621 rpl_opt->opt_type = UIP_EXT_HDR_OPT_RPL;
622 rpl_opt->opt_len = RPL_HDR_OPT_LEN;
623 rpl_opt->flags = 0;
624 rpl_opt->senderrank = UIP_HTONS(instance->current_dag->rank);
625 rpl_opt->instance = instance->instance_id;
626
627 uipbuf_add_ext_hdr(RPL_HOP_BY_HOP_LEN);
628 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
629
630 /* Update the header before returning. */
631 return update_hbh_header();
632}
633/*---------------------------------------------------------------------------*/
634bool
635rpl_ext_header_remove(void)
636{
637 uint8_t *prev_proto_ptr;
638 uint8_t protocol;
639 uint16_t ext_len;
640 uint8_t *next_header;
641 struct uip_ext_hdr *ext_ptr;
642 struct uip_ext_hdr_opt *opt_ptr;
643
644 next_header = uipbuf_get_next_header(uip_buf, uip_len, &protocol, true);
645 if(next_header == NULL) {
646 return true;
647 }
648
649 ext_ptr = (struct uip_ext_hdr *)next_header;
650 prev_proto_ptr = &UIP_IP_BUF->proto;
651
652 while(uip_is_proto_ext_hdr(protocol)) {
653 opt_ptr = (struct uip_ext_hdr_opt *)(next_header + 2);
654 if(protocol == UIP_PROTO_ROUTING ||
655 (protocol == UIP_PROTO_HBHO && opt_ptr->type == UIP_EXT_HDR_OPT_RPL)) {
656 /* Remove ext header */
657 *prev_proto_ptr = ext_ptr->next;
658 ext_len = ext_ptr->len * 8 + 8;
659 if(uipbuf_add_ext_hdr(-ext_len) == false) {
660 return false;
661 }
662
663 /* Update length field and rest of packet to the "left". */
664 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
665 if(uip_len <= next_header - uip_buf) {
666 /* No more data to move. */
667 return false;
668 }
669 memmove(next_header, next_header + ext_len,
670 uip_len - (next_header - uip_buf));
671
672 /* Update loop variables. */
673 protocol = *prev_proto_ptr;
674 } else {
675 /* Move to the ext hdr. */
676 next_header = uipbuf_get_next_header(next_header,
677 uip_len - (next_header - uip_buf),
678 &protocol, false);
679 if(next_header == NULL) {
680 /* Processing finished. */
681 break;
682 }
683 ext_ptr = (struct uip_ext_hdr *)next_header;
684 prev_proto_ptr = &ext_ptr->next;
685 }
686 }
687
688 return true;
689}
690/*---------------------------------------------------------------------------*/
691int
692rpl_ext_header_update(void)
693{
694 if(default_instance == NULL || default_instance->current_dag == NULL ||
695 uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) ||
696 uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
697 return 1;
698 }
699
700 if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
701 /* At the root, remove headers if any, and insert SRH or HBH.
702 (SRH is inserted only if the destination is in the DODAG.) */
703 rpl_ext_header_remove();
704 if(rpl_get_dag(&UIP_IP_BUF->destipaddr) != NULL) {
705 /* dest is in a DODAG; the packet is going down. */
706 if(RPL_IS_NON_STORING(default_instance)) {
707 return insert_srh_header();
708 } else {
709 return insert_hbh_header(default_instance);
710 }
711 } else {
712 /* dest is outside of DODAGs; no ext header is needed. */
713 return 1;
714 }
715 } else {
716 if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)
717 && UIP_IP_BUF->ttl == uip_ds6_if.cur_hop_limit) {
718 /*
719 * Insert a HBH option at the source. Checking the address is
720 * insufficient because in non-storing mode, a packet may go up
721 * and then down the same path again.
722 */
723 return insert_hbh_header(default_instance);
724 } else {
725 /* Update HBH option at forwarders. */
726 return update_hbh_header();
727 }
728 }
729}
730/** @}*/
uip_sr_node_t * uip_sr_get_node(const void *graph, const uip_ipaddr_t *addr)
Looks up for a source routing node from its IPv6 global address.
Definition uip-sr.c:82
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Definition uip.h:1725
int uip_sr_is_addr_reachable(const void *graph, const uip_ipaddr_t *addr)
Telle whether an address is reachable, i.e.
Definition uip-sr.c:95
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 4291 a is of type uip_ipaddr_t*
Definition uip.h:1860
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC 4291 i.e.
Definition uip.h:1766
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition uip-ds6.c:75
#define uip_is_addr_loopback(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Definition uip.h:1711
#define UIP_PROTO_HBHO
extension headers types
Definition uip.h:1663
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition uip.h:71
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition uip.h:1157
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition uip.h:969
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition uip.h:465
uint16_t uip_ext_len
The length of the extension headers.
Definition uip6.c:122
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition uip6.c:159
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition uipopt.h:92
#define UIP_LINK_MTU
The maximum transmission unit at the IP layer.
Definition uipopt.h:145
Header file for the logging system.
Header file for the Packet buffer (packetbuf) management.
Routing driver header file.
int(* get_sr_node_ipaddr)(uip_ipaddr_t *ipaddr, const uip_sr_node_t *node)
Returns the global IPv6 address of a source routing node.
Definition routing.h:97
RPL DAG structure.
Definition rpl.h:138
RPL instance structure.
Definition rpl.h:222
An entry in the routing table.
A node in a source routing graph, stored at the root and representing all child-parent relationship.
Definition uip-sr.h:92
Header for the Contiki/uIP interface.
Header file for IPv6-related data structures.
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition uip-nd6.c:116
Source routing support.
Header file for the uIP TCP/IP stack.