Contiki-NG
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 * This file is part of the Contiki operating system.
30 */
31
32/**
33 * \file
34 * Management of extension headers for ContikiRPL.
35 *
36 * \author Vincent Brillault <vincent.brillault@imag.fr>,
37 * Joakim Eriksson <joakime@sics.se>,
38 * Niclas Finne <nfi@sics.se>,
39 * Nicolas Tsiftes <nvt@sics.se>.
40 */
41
42/**
43 * \addtogroup uip
44 * @{
45 */
46
47#include "net/routing/routing.h"
48#include "net/ipv6/uip.h"
49#include "net/ipv6/tcpip.h"
50#include "net/ipv6/uip-ds6.h"
51#include "net/ipv6/uip-sr.h"
52#include "net/routing/rpl-classic/rpl-private.h"
53#include "net/packetbuf.h"
54
55#include "sys/log.h"
56
57#define LOG_MODULE "RPL"
58#define LOG_LEVEL LOG_LEVEL_RPL
59
60#include <limits.h>
61#include <string.h>
62
63/*---------------------------------------------------------------------------*/
64int
65rpl_ext_header_hbh_update(uint8_t *ext_buf, int opt_offset)
66{
67 rpl_instance_t *instance;
68 int down;
69 uint16_t sender_rank;
70 uint8_t sender_closer;
71 uip_ds6_route_t *route;
72 rpl_parent_t *sender;
73 struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)ext_buf;
74 struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(ext_buf + opt_offset);
75
76 if(hbh_hdr->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
77 || rpl_opt->opt_type != UIP_EXT_HDR_OPT_RPL
78 || rpl_opt->opt_len != RPL_HDR_OPT_LEN) {
79
80 LOG_ERR("Hop-by-hop extension header has wrong size or type (%u %u %u)\n",
81 hbh_hdr->len, rpl_opt->opt_type, rpl_opt->opt_len);
82 return 0; /* Drop */
83 }
84
85 instance = rpl_get_instance(rpl_opt->instance);
86 if(instance == NULL) {
87 LOG_ERR("Unknown instance: %u\n", rpl_opt->instance);
88 return 0;
89 }
90
91 if(rpl_opt->flags & RPL_HDR_OPT_FWD_ERR) {
92 LOG_ERR("Forward error!\n");
93 /* We should try to repair it by removing the neighbor that caused
94 the packet to be forwareded in the first place. We drop any
95 routes that go through the neighbor that sent the packet to
96 us. */
97 if(RPL_IS_STORING(instance)) {
98 route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
99 if(route != NULL) {
100 uip_ds6_route_rm(route);
101 }
102 }
103 RPL_STAT(rpl_stats.forward_errors++);
104 /* Trigger DAO retransmission */
105 rpl_reset_dio_timer(instance);
106 /* drop the packet as it is not routable */
107 return 0;
108 }
109
110 if(!instance->current_dag->joined) {
111 LOG_ERR("No DAG in the instance\n");
112 return 0;
113 }
114 down = 0;
115 if(rpl_opt->flags & RPL_HDR_OPT_DOWN) {
116 down = 1;
117 }
118
119 sender_rank = UIP_HTONS(rpl_opt->senderrank);
120 sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER));
121
122 if(sender != NULL && (rpl_opt->flags & RPL_HDR_OPT_RANK_ERR)) {
123 /* A rank error was signalled, attempt to repair it by updating
124 * the sender's rank from ext header */
125 sender->rank = sender_rank;
126 if(RPL_IS_NON_STORING(instance)) {
127 /* Select DAG and preferred parent only in non-storing mode. In storing mode,
128 * a parent switch would result in an immediate No-path DAO transmission, dropping
129 * current incoming packet. */
130 rpl_select_dag(instance, sender);
131 }
132 }
133
134 sender_closer = sender_rank < instance->current_dag->rank;
135
136 LOG_DBG("Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up",
137 sender_closer,
138 sender_rank,
139 instance->current_dag->rank
140 );
141
142 if((down && !sender_closer) || (!down && sender_closer)) {
143 LOG_WARN("Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
144 sender_rank, instance->current_dag->rank,
145 sender_closer);
146 /* Attempt to repair the loop by sending a unicast DIO back to the sender
147 * so that it gets a fresh update of our rank. */
148 if(sender != NULL) {
149 instance->unicast_dio_target = sender;
150 rpl_schedule_unicast_dio_immediately(instance);
151 }
152 if(rpl_opt->flags & RPL_HDR_OPT_RANK_ERR) {
153 RPL_STAT(rpl_stats.loop_errors++);
154 LOG_ERR(" Rank error signalled in RPL option!\n");
155 /* Packet must be dropped and dio trickle timer reset, see RFC6550 - 11.2.2.2 */
156 rpl_reset_dio_timer(instance);
157 return 0;
158 }
159 LOG_WARN("Single error tolerated\n");
160 RPL_STAT(rpl_stats.loop_warnings++);
161 rpl_opt->flags |= RPL_HDR_OPT_RANK_ERR;
162 return 1;
163 }
164
165 LOG_DBG("Rank OK\n");
166 return 1;
167}
168/*---------------------------------------------------------------------------*/
169int
171{
172#if RPL_WITH_NON_STORING
173 struct uip_routing_hdr *rh_header;
174 rpl_dag_t *dag;
175 uip_sr_node_t *dest_node;
176 uip_sr_node_t *root_node;
177
178 /* Look for routing ext header */
179 rh_header = (struct uip_routing_hdr *)uipbuf_search_header(uip_buf, uip_len, UIP_PROTO_ROUTING);
180
181 dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
182 root_node = uip_sr_get_node(dag, &dag->dag_id);
183 dest_node = uip_sr_get_node(dag, &UIP_IP_BUF->destipaddr);
184
185 if((rh_header != NULL && rh_header->routing_type == RPL_RH_TYPE_SRH) ||
186 (dest_node != NULL && root_node != NULL &&
187 dest_node->parent == root_node)) {
188 /* Routing header found or the packet destined for a direct child of the root.
189 * The next hop should be already copied as the IPv6 destination
190 * address, via rpl_ext_header_srh_update. We turn this address into a link-local to enable
191 * forwarding to next hop */
192 uip_ipaddr_copy(ipaddr, &UIP_IP_BUF->destipaddr);
193 uip_create_linklocal_prefix(ipaddr);
194 return 1;
195 }
196
197 return 0;
198#else /* RPL_WITH_NON_STORING */
199 return 0; /* SRH not found */
200#endif /* RPL_WITH_NON_STORING */
201}
202/*---------------------------------------------------------------------------*/
203int
205{
206#if RPL_WITH_NON_STORING
207 struct uip_routing_hdr *rh_header;
208 struct uip_rpl_srh_hdr *srh_header;
209
210 /* Look for routing ext header */
211 rh_header = (struct uip_routing_hdr *)uipbuf_search_header(uip_buf, uip_len, UIP_PROTO_ROUTING);
212
213 if(rh_header != NULL && rh_header->routing_type == RPL_RH_TYPE_SRH) {
214 /* SRH found, now look for next hop */
215 uint8_t cmpri, cmpre;
216 uint8_t ext_len;
217 uint8_t padding;
218 uint8_t path_len;
219 uint8_t segments_left;
220 uip_ipaddr_t current_dest_addr;
221
222 srh_header = (struct uip_rpl_srh_hdr *)(((uint8_t *)rh_header) + RPL_RH_LEN);
223 segments_left = rh_header->seg_left;
224 ext_len = rh_header->len * 8 + 8;
225 cmpri = srh_header->cmpr >> 4;
226 cmpre = srh_header->cmpr & 0x0f;
227 padding = srh_header->pad >> 4;
228 path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
229 (void)path_len;
230
231 LOG_DBG("read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n",
232 path_len, segments_left, cmpri, cmpre, ext_len, padding);
233
234 if(segments_left == 0) {
235 /* We are the final destination, do nothing */
236 } else if(segments_left > path_len) {
237 /* Discard the packet because of a parameter problem. */
238 LOG_ERR("SRH with too many segments left (%u > %u)\n",
239 segments_left, path_len);
240 return 0;
241 } else {
242 uint8_t i = path_len - segments_left; /* The index of the next address to be visited */
243 uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
244 ptrdiff_t rh_offset = (uint8_t *)rh_header - uip_buf;
245 size_t addr_offset = RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
246
247 if(rh_offset + addr_offset + 16 - cmpr > UIP_BUFSIZE) {
248 LOG_ERR("Invalid SRH address pointer\n");
249 return 0;
250 }
251
252 uint8_t *addr_ptr = ((uint8_t *)rh_header) + addr_offset;
253
254 /* As per RFC6554: swap the IPv6 destination address and address[i] */
255
256 /* First, copy the current IPv6 destination address */
257 uip_ipaddr_copy(&current_dest_addr, &UIP_IP_BUF->destipaddr);
258 /* Second, update the IPv6 destination address with addresses[i] */
259 memcpy(((uint8_t *)&UIP_IP_BUF->destipaddr) + cmpr, addr_ptr, 16 - cmpr);
260 /* Third, write current_dest_addr to addresses[i] */
261 memcpy(addr_ptr, ((uint8_t *)&current_dest_addr) + cmpr, 16 - cmpr);
262
263 /* Update segments left field */
264 rh_header->seg_left--;
265
266 LOG_INFO("SRH next hop ");
267 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
268 LOG_INFO_("\n");
269 }
270 return 1;
271 }
272
273 return 0;
274#else /* RPL_WITH_NON_STORING */
275 return 0; /* SRH not found */
276#endif /* RPL_WITH_NON_STORING */
277}
278/*---------------------------------------------------------------------------*/
279static int
280count_matching_bytes(const void *p1, const void *p2, size_t n)
281{
282 int i = 0;
283 for(i = 0; i < n; i++) {
284 if(((uint8_t *)p1)[i] != ((uint8_t *)p2)[i]) {
285 return i;
286 }
287 }
288 return n;
289}
290/*---------------------------------------------------------------------------*/
291static int
292insert_srh_header(void)
293{
294 /* Implementation of RFC6554 */
295 uint8_t path_len;
296 uint8_t ext_len;
297 uint8_t cmpri, cmpre; /* ComprI and ComprE fields of the RPL Source Routing Header */
298 uint8_t *hop_ptr;
299 uint8_t padding;
300 uip_sr_node_t *dest_node;
301 uip_sr_node_t *root_node;
302 uip_sr_node_t *node;
303 rpl_dag_t *dag;
304 uip_ipaddr_t node_addr;
305
306 /* Always insest SRH as first extension header */
307 struct uip_routing_hdr *rh_hdr = (struct uip_routing_hdr *)UIP_IP_PAYLOAD(0);
308 struct uip_rpl_srh_hdr *srh_hdr = (struct uip_rpl_srh_hdr *)(UIP_IP_PAYLOAD(0) + RPL_RH_LEN);
309
310 LOG_INFO("SRH creating source routing header with destination ");
311 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
312 LOG_INFO_("\n");
313
314 /* Construct source route. We do not do this recursively to keep the runtime stack usage constant. */
315
316 /* Get link of the destination and root */
317 dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
318
319 if(dag == NULL) {
320 LOG_ERR("SRH DAG not found\n");
321 return 0;
322 }
323
324 dest_node = uip_sr_get_node(dag, &UIP_IP_BUF->destipaddr);
325 if(dest_node == NULL) {
326 /* The destination is not found, skip SRH insertion */
327 return 1;
328 }
329
330 root_node = uip_sr_get_node(dag, &dag->dag_id);
331 if(root_node == NULL) {
332 LOG_ERR("SRH root node not found\n");
333 return 0;
334 }
335
336 if(!uip_sr_is_addr_reachable(dag, &UIP_IP_BUF->destipaddr)) {
337 LOG_ERR("SRH no path found to destination\n");
338 return 0;
339 }
340
341 /* Compute path length and compression factors (we use cmpri == cmpre) */
342 path_len = 0;
343 node = dest_node->parent;
344 /* For simplicity, we use cmpri = cmpre */
345 cmpri = 15;
346 cmpre = 15;
347
348 if(node == root_node) {
349 LOG_DBG("SRH no need to insert SRH\n");
350 return 1;
351 }
352
353 while(node != NULL && node != root_node) {
354
355 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
356
357 /* How many bytes in common between all nodes in the path? */
358 cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &UIP_IP_BUF->destipaddr, 16));
359 cmpre = cmpri;
360
361 LOG_DBG("SRH Hop ");
362 LOG_DBG_6ADDR(&node_addr);
363 LOG_DBG_("\n");
364 node = node->parent;
365 path_len++;
366 }
367
368 /* Extension header length: fixed headers + (n-1) * (16-ComprI) + (16-ComprE)*/
369 ext_len = RPL_RH_LEN + RPL_SRH_LEN
370 + (path_len - 1) * (16 - cmpre)
371 + (16 - cmpri);
372
373 padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8));
374 ext_len += padding;
375
376 LOG_DBG("SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n",
377 path_len, cmpri, cmpre, ext_len, padding);
378
379 /* Check if there is enough space to store the extension header */
380 if(uip_len + ext_len > UIP_LINK_MTU) {
381 LOG_ERR("Packet too long: impossible to add source routing header (%u bytes)\n", ext_len);
382 return 0;
383 }
384
385 /* Move existing ext headers and payload ext_len further */
386 memmove(uip_buf + UIP_IPH_LEN + uip_ext_len + ext_len,
387 uip_buf + UIP_IPH_LEN + uip_ext_len, uip_len - UIP_IPH_LEN);
388 memset(uip_buf + UIP_IPH_LEN + uip_ext_len, 0, ext_len);
389
390 /* Insert source routing header (as first ext header) */
391 rh_hdr->next = UIP_IP_BUF->proto;
392 UIP_IP_BUF->proto = UIP_PROTO_ROUTING;
393
394 /* Initialize IPv6 Routing Header */
395 rh_hdr->len = (ext_len - 8) / 8;
396 rh_hdr->routing_type = RPL_RH_TYPE_SRH;
397 rh_hdr->seg_left = path_len;
398
399 /* Initialize RPL Source Routing Header */
400 srh_hdr->cmpr = (cmpri << 4) + cmpre;
401 srh_hdr->pad = padding << 4;
402
403 /* Initialize addresses field (the actual source route).
404 * From last to first. */
405 node = dest_node;
406 hop_ptr = ((uint8_t *)rh_hdr) + ext_len - padding; /* Pointer where to write the next hop compressed address */
407
408 while(node != NULL && node->parent != root_node) {
409 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
410
411 hop_ptr -= (16 - cmpri);
412 memcpy(hop_ptr, ((uint8_t*)&node_addr) + cmpri, 16 - cmpri);
413
414 node = node->parent;
415 }
416
417 /* The next hop (i.e. node whose parent is the root) is placed as the current IPv6 destination */
418 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
419 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &node_addr);
420
421 /* Update the IPv6 length field */
422 uipbuf_add_ext_hdr(ext_len);
423 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
424
425 return 1;
426}
427/*---------------------------------------------------------------------------*/
428static int
429update_hbh_header(void)
430{
431 rpl_instance_t *instance;
432 rpl_parent_t *parent;
433 struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
434 struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(0) + 2);
435
436 if(UIP_IP_BUF->proto == UIP_PROTO_HBHO && rpl_opt->opt_type == UIP_EXT_HDR_OPT_RPL) {
437 if(hbh_hdr->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
438 || rpl_opt->opt_len != RPL_HDR_OPT_LEN) {
439
440 LOG_ERR("Hop-by-hop extension header has wrong size (%u)\n", rpl_opt->opt_len);
441 return 0; /* Drop */
442 }
443
444 instance = rpl_get_instance(rpl_opt->instance);
445 if(instance == NULL || !instance->used || !instance->current_dag->joined) {
446 LOG_ERR("Unable to add/update hop-by-hop extension header: incorrect instance\n");
447 return 0; /* Drop */
448 }
449
450 LOG_INFO("Updating RPL option\n");
451 /* Update sender rank and instance, will update flags next */
452 rpl_opt->senderrank = UIP_HTONS(instance->current_dag->rank);
453 rpl_opt->instance = instance->instance_id;
454
455 if(RPL_IS_STORING(instance)) { /* In non-storing mode, downwards traffic does not have the HBH option */
456 /* Check the direction of the down flag, as per Section 11.2.2.3,
457 which states that if a packet is going down it should in
458 general not go back up again. If this happens, a
459 RPL_HDR_OPT_FWD_ERR should be flagged. */
460 if((rpl_opt->flags & RPL_HDR_OPT_DOWN)) {
461 if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
462 rpl_opt->flags |= RPL_HDR_OPT_FWD_ERR;
463 LOG_WARN("RPL forwarding error\n");
464 /* We should send back the packet to the originating parent,
465 but it is not feasible yet, so we send a No-Path DAO instead */
466 LOG_WARN("RPL generate No-Path DAO\n");
467 parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
468 if(parent != NULL) {
469 dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
470 }
471 /* Drop packet */
472 return 0;
473 }
474 } else {
475 /* Set the down extension flag correctly as described in Section
476 11.2 of RFC6550. If the packet progresses along a DAO route,
477 the down flag should be set. */
478 if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
479 /* No route was found, so this packet will go towards the RPL
480 root. If so, we should not set the down flag. */
481 rpl_opt->flags &= ~RPL_HDR_OPT_DOWN;
482 LOG_DBG("RPL option going up\n");
483 } else {
484 /* A DAO route was found so we set the down flag. */
485 rpl_opt->flags |= RPL_HDR_OPT_DOWN;
486 LOG_DBG("RPL option going down\n");
487 }
488 }
489 }
490 }
491
492 return 1;
493}
494/*---------------------------------------------------------------------------*/
495static int
496insert_hbh_header(const rpl_instance_t *instance)
497{
498 struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
499 struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(2));
500
501 /* Insert hop-by-hop header */
502 LOG_DBG("Creating hop-by-hop option\n");
503 if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_LINK_MTU) {
504 LOG_ERR("Packet too long: impossible to add hop-by-hop option\n");
505 return 0;
506 }
507
508 /* Move existing ext headers and payload RPL_HOP_BY_HOP_LEN further */
509 memmove(UIP_IP_PAYLOAD(RPL_HOP_BY_HOP_LEN), UIP_IP_PAYLOAD(0), uip_len - UIP_IPH_LEN);
510 memset(UIP_IP_PAYLOAD(0), 0, RPL_HOP_BY_HOP_LEN);
511
512 /* Insert HBH header (as first ext header) */
513 hbh_hdr->next = UIP_IP_BUF->proto;
514 UIP_IP_BUF->proto = UIP_PROTO_HBHO;
515
516 /* Initialize HBH option */
517 hbh_hdr->len = (RPL_HOP_BY_HOP_LEN - 8) / 8;
518 rpl_opt->opt_type = UIP_EXT_HDR_OPT_RPL;
519 rpl_opt->opt_len = RPL_HDR_OPT_LEN;
520 rpl_opt->flags = 0;
521 rpl_opt->senderrank = UIP_HTONS(instance->current_dag->rank);
522 rpl_opt->instance = instance->instance_id;
523
524 uipbuf_add_ext_hdr(RPL_HOP_BY_HOP_LEN);
525 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
526
527 /* Update header before returning */
528 return update_hbh_header();
529}
530/*---------------------------------------------------------------------------*/
531bool
533{
534 uint8_t *prev_proto_ptr;
535 uint8_t protocol;
536 uint16_t ext_len;
537 uint8_t *next_header;
538 struct uip_ext_hdr *ext_ptr;
539 struct uip_ext_hdr_opt *opt_ptr;
540
541 next_header = uipbuf_get_next_header(uip_buf, uip_len, &protocol, true);
542 if(next_header == NULL) {
543 return true;
544 }
545 ext_ptr = (struct uip_ext_hdr *)next_header;
546 prev_proto_ptr = &UIP_IP_BUF->proto;
547
548 while(uip_is_proto_ext_hdr(protocol)) {
549 opt_ptr = (struct uip_ext_hdr_opt *)(next_header + 2);
550 if(protocol == UIP_PROTO_ROUTING ||
551 (protocol == UIP_PROTO_HBHO && opt_ptr->type == UIP_EXT_HDR_OPT_RPL)) {
552 /* Remove ext header */
553 *prev_proto_ptr = ext_ptr->next;
554 ext_len = ext_ptr->len * 8 + 8;
555 if(uipbuf_add_ext_hdr(-ext_len) == false) {
556 return false;
557 }
558
559 /* Update length field and rest of packet to the "left" */
560 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
561 if(uip_len <= next_header - uip_buf) {
562 /* No more data to move. */
563 return false;
564 }
565 memmove(next_header, next_header + ext_len,
566 uip_len - (next_header - uip_buf));
567
568 /* Update loop variables */
569 protocol = *prev_proto_ptr;
570 } else {
571 /* move to the ext hdr */
572 next_header = uipbuf_get_next_header(next_header,
573 uip_len - (next_header - uip_buf),
574 &protocol, false);
575 if(next_header == NULL) {
576 /* Processing finished. */
577 break;
578 }
579 ext_ptr = (struct uip_ext_hdr *)next_header;
580 prev_proto_ptr = &ext_ptr->next;
581 }
582 }
583
584 return true;
585}
586/*---------------------------------------------------------------------------*/
587int
589{
590 if(default_instance == NULL || default_instance->current_dag == NULL
591 || uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) || uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
592 return 1;
593 }
594
595 if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
596 /* At the root, remove headers if any, and insert SRH or HBH
597 * (SRH is inserted only if the destination is in the DODAG) */
599 if(rpl_get_dag(&UIP_IP_BUF->destipaddr) != NULL) {
600 /* dest is in a DODAG; the packet is going down. */
601 if(RPL_IS_NON_STORING(default_instance)) {
602 return insert_srh_header();
603 } else {
604 return insert_hbh_header(default_instance);
605 }
606 } else {
607 /* dest is outside of DODAGs; no ext header is needed. */
608 return 1;
609 }
610 } else {
611 if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)
612 && UIP_IP_BUF->ttl == uip_ds6_if.cur_hop_limit) {
613 /* Insert HBH option at source. Checking the address is not sufficient because
614 * in non-storing mode, a packet may go up and then down the same path again */
615 return insert_hbh_header(default_instance);
616 } else {
617 /* Update HBH option at forwarders */
618 return update_hbh_header();
619 }
620 }
621}
622
623/** @}*/
#define ROOT_RANK
Rank of a root node.
Definition: rpl-types.h:78
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
int rpl_ext_header_update(void)
Adds/updates all RPL extension headers to current uIP packet.
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:1859
int rpl_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr)
Look for next hop from SRH of current uIP packet.
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC 4291 i.e.
Definition: uip.h:1775
int rpl_ext_header_srh_update(void)
Process and update SRH in-place, i.e.
bool rpl_ext_header_remove(void)
Removes all RPL extension headers.
int rpl_ext_header_hbh_update(uint8_t *ext_buf, int opt_offset)
Process and update the RPL hop-by-hop extension headers of the current uIP packet.
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
#define UIP_PROTO_HBHO
extension headers types
Definition: uip.h:1672
#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:93
#define UIP_LINK_MTU
The maximum transmission unit at the IP Layer.
Definition: uipopt.h:172
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 *addr, 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:135
RPL instance structure.
Definition: rpl.h:219
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.