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 /*---------------------------------------------------------------------------*/
64 int
65 rpl_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 /*---------------------------------------------------------------------------*/
169 int
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 /*---------------------------------------------------------------------------*/
203 int
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 {
237  uint8_t i = path_len - segments_left; /* The index of the next address to be visited */
238  uint8_t *addr_ptr = ((uint8_t *)rh_header) + RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
239  uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
240 
241  /* As per RFC6554: swap the IPv6 destination address and address[i] */
242 
243  /* First, copy the current IPv6 destination address */
244  uip_ipaddr_copy(&current_dest_addr, &UIP_IP_BUF->destipaddr);
245  /* Second, update the IPv6 destination address with addresses[i] */
246  memcpy(((uint8_t *)&UIP_IP_BUF->destipaddr) + cmpr, addr_ptr, 16 - cmpr);
247  /* Third, write current_dest_addr to addresses[i] */
248  memcpy(addr_ptr, ((uint8_t *)&current_dest_addr) + cmpr, 16 - cmpr);
249 
250  /* Update segments left field */
251  rh_header->seg_left--;
252 
253  LOG_INFO("SRH next hop ");
254  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
255  LOG_INFO_("\n");
256  }
257  return 1;
258  }
259 
260  return 0;
261 #else /* RPL_WITH_NON_STORING */
262  return 0; /* SRH not found */
263 #endif /* RPL_WITH_NON_STORING */
264 }
265 /*---------------------------------------------------------------------------*/
266 static int
267 count_matching_bytes(const void *p1, const void *p2, size_t n)
268 {
269  int i = 0;
270  for(i = 0; i < n; i++) {
271  if(((uint8_t *)p1)[i] != ((uint8_t *)p2)[i]) {
272  return i;
273  }
274  }
275  return n;
276 }
277 /*---------------------------------------------------------------------------*/
278 static int
279 insert_srh_header(void)
280 {
281  /* Implementation of RFC6554 */
282  uint8_t path_len;
283  uint8_t ext_len;
284  uint8_t cmpri, cmpre; /* ComprI and ComprE fields of the RPL Source Routing Header */
285  uint8_t *hop_ptr;
286  uint8_t padding;
287  uip_sr_node_t *dest_node;
288  uip_sr_node_t *root_node;
289  uip_sr_node_t *node;
290  rpl_dag_t *dag;
291  uip_ipaddr_t node_addr;
292 
293  /* Always insest SRH as first extension header */
294  struct uip_routing_hdr *rh_hdr = (struct uip_routing_hdr *)UIP_IP_PAYLOAD(0);
295  struct uip_rpl_srh_hdr *srh_hdr = (struct uip_rpl_srh_hdr *)(UIP_IP_PAYLOAD(0) + RPL_RH_LEN);
296 
297  LOG_INFO("SRH creating source routing header with destination ");
298  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
299  LOG_INFO_("\n");
300 
301  /* Construct source route. We do not do this recursively to keep the runtime stack usage constant. */
302 
303  /* Get link of the destination and root */
304  dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
305 
306  if(dag == NULL) {
307  LOG_ERR("SRH DAG not found\n");
308  return 0;
309  }
310 
311  dest_node = uip_sr_get_node(dag, &UIP_IP_BUF->destipaddr);
312  if(dest_node == NULL) {
313  /* The destination is not found, skip SRH insertion */
314  return 1;
315  }
316 
317  root_node = uip_sr_get_node(dag, &dag->dag_id);
318  if(root_node == NULL) {
319  LOG_ERR("SRH root node not found\n");
320  return 0;
321  }
322 
323  if(!uip_sr_is_addr_reachable(dag, &UIP_IP_BUF->destipaddr)) {
324  LOG_ERR("SRH no path found to destination\n");
325  return 0;
326  }
327 
328  /* Compute path length and compression factors (we use cmpri == cmpre) */
329  path_len = 0;
330  node = dest_node->parent;
331  /* For simplicity, we use cmpri = cmpre */
332  cmpri = 15;
333  cmpre = 15;
334 
335  if(node == root_node) {
336  LOG_DBG("SRH no need to insert SRH\n");
337  return 1;
338  }
339 
340  while(node != NULL && node != root_node) {
341 
342  NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
343 
344  /* How many bytes in common between all nodes in the path? */
345  cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &UIP_IP_BUF->destipaddr, 16));
346  cmpre = cmpri;
347 
348  LOG_DBG("SRH Hop ");
349  LOG_DBG_6ADDR(&node_addr);
350  LOG_DBG_("\n");
351  node = node->parent;
352  path_len++;
353  }
354 
355  /* Extension header length: fixed headers + (n-1) * (16-ComprI) + (16-ComprE)*/
356  ext_len = RPL_RH_LEN + RPL_SRH_LEN
357  + (path_len - 1) * (16 - cmpre)
358  + (16 - cmpri);
359 
360  padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8));
361  ext_len += padding;
362 
363  LOG_DBG("SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n",
364  path_len, cmpri, cmpre, ext_len, padding);
365 
366  /* Check if there is enough space to store the extension header */
367  if(uip_len + ext_len > UIP_LINK_MTU) {
368  LOG_ERR("Packet too long: impossible to add source routing header (%u bytes)\n", ext_len);
369  return 0;
370  }
371 
372  /* Move existing ext headers and payload ext_len further */
373  memmove(uip_buf + UIP_IPH_LEN + uip_ext_len + ext_len,
374  uip_buf + UIP_IPH_LEN + uip_ext_len, uip_len - UIP_IPH_LEN);
375  memset(uip_buf + UIP_IPH_LEN + uip_ext_len, 0, ext_len);
376 
377  /* Insert source routing header (as first ext header) */
378  rh_hdr->next = UIP_IP_BUF->proto;
379  UIP_IP_BUF->proto = UIP_PROTO_ROUTING;
380 
381  /* Initialize IPv6 Routing Header */
382  rh_hdr->len = (ext_len - 8) / 8;
383  rh_hdr->routing_type = RPL_RH_TYPE_SRH;
384  rh_hdr->seg_left = path_len;
385 
386  /* Initialize RPL Source Routing Header */
387  srh_hdr->cmpr = (cmpri << 4) + cmpre;
388  srh_hdr->pad = padding << 4;
389 
390  /* Initialize addresses field (the actual source route).
391  * From last to first. */
392  node = dest_node;
393  hop_ptr = ((uint8_t *)rh_hdr) + ext_len - padding; /* Pointer where to write the next hop compressed address */
394 
395  while(node != NULL && node->parent != root_node) {
396  NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
397 
398  hop_ptr -= (16 - cmpri);
399  memcpy(hop_ptr, ((uint8_t*)&node_addr) + cmpri, 16 - cmpri);
400 
401  node = node->parent;
402  }
403 
404  /* The next hop (i.e. node whose parent is the root) is placed as the current IPv6 destination */
405  NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
406  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &node_addr);
407 
408  /* Update the IPv6 length field */
409  uipbuf_add_ext_hdr(ext_len);
410  uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
411 
412  return 1;
413 }
414 /*---------------------------------------------------------------------------*/
415 static int
416 update_hbh_header(void)
417 {
418  rpl_instance_t *instance;
419  rpl_parent_t *parent;
420  struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
421  struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(0) + 2);
422 
423  if(UIP_IP_BUF->proto == UIP_PROTO_HBHO && rpl_opt->opt_type == UIP_EXT_HDR_OPT_RPL) {
424  if(hbh_hdr->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
425  || rpl_opt->opt_len != RPL_HDR_OPT_LEN) {
426 
427  LOG_ERR("Hop-by-hop extension header has wrong size (%u)\n", rpl_opt->opt_len);
428  return 0; /* Drop */
429  }
430 
431  instance = rpl_get_instance(rpl_opt->instance);
432  if(instance == NULL || !instance->used || !instance->current_dag->joined) {
433  LOG_ERR("Unable to add/update hop-by-hop extension header: incorrect instance\n");
434  return 0; /* Drop */
435  }
436 
437  LOG_INFO("Updating RPL option\n");
438  /* Update sender rank and instance, will update flags next */
439  rpl_opt->senderrank = UIP_HTONS(instance->current_dag->rank);
440  rpl_opt->instance = instance->instance_id;
441 
442  if(RPL_IS_STORING(instance)) { /* In non-storing mode, downwards traffic does not have the HBH option */
443  /* Check the direction of the down flag, as per Section 11.2.2.3,
444  which states that if a packet is going down it should in
445  general not go back up again. If this happens, a
446  RPL_HDR_OPT_FWD_ERR should be flagged. */
447  if((rpl_opt->flags & RPL_HDR_OPT_DOWN)) {
448  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
449  rpl_opt->flags |= RPL_HDR_OPT_FWD_ERR;
450  LOG_WARN("RPL forwarding error\n");
451  /* We should send back the packet to the originating parent,
452  but it is not feasible yet, so we send a No-Path DAO instead */
453  LOG_WARN("RPL generate No-Path DAO\n");
454  parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
455  if(parent != NULL) {
456  dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
457  }
458  /* Drop packet */
459  return 0;
460  }
461  } else {
462  /* Set the down extension flag correctly as described in Section
463  11.2 of RFC6550. If the packet progresses along a DAO route,
464  the down flag should be set. */
465  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
466  /* No route was found, so this packet will go towards the RPL
467  root. If so, we should not set the down flag. */
468  rpl_opt->flags &= ~RPL_HDR_OPT_DOWN;
469  LOG_DBG("RPL option going up\n");
470  } else {
471  /* A DAO route was found so we set the down flag. */
472  rpl_opt->flags |= RPL_HDR_OPT_DOWN;
473  LOG_DBG("RPL option going down\n");
474  }
475  }
476  }
477  }
478 
479  return 1;
480 }
481 /*---------------------------------------------------------------------------*/
482 static int
483 insert_hbh_header(const rpl_instance_t *instance)
484 {
485  struct uip_hbho_hdr *hbh_hdr = (struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
486  struct uip_ext_hdr_opt_rpl *rpl_opt = (struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(2));
487 
488  /* Insert hop-by-hop header */
489  LOG_DBG("Creating hop-by-hop option\n");
490  if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_LINK_MTU) {
491  LOG_ERR("Packet too long: impossible to add hop-by-hop option\n");
492  return 0;
493  }
494 
495  /* Move existing ext headers and payload RPL_HOP_BY_HOP_LEN further */
496  memmove(UIP_IP_PAYLOAD(RPL_HOP_BY_HOP_LEN), UIP_IP_PAYLOAD(0), uip_len - UIP_IPH_LEN);
497  memset(UIP_IP_PAYLOAD(0), 0, RPL_HOP_BY_HOP_LEN);
498 
499  /* Insert HBH header (as first ext header) */
500  hbh_hdr->next = UIP_IP_BUF->proto;
501  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
502 
503  /* Initialize HBH option */
504  hbh_hdr->len = (RPL_HOP_BY_HOP_LEN - 8) / 8;
505  rpl_opt->opt_type = UIP_EXT_HDR_OPT_RPL;
506  rpl_opt->opt_len = RPL_HDR_OPT_LEN;
507  rpl_opt->flags = 0;
508  rpl_opt->senderrank = UIP_HTONS(instance->current_dag->rank);
509  rpl_opt->instance = instance->instance_id;
510 
511  uipbuf_add_ext_hdr(RPL_HOP_BY_HOP_LEN);
512  uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
513 
514  /* Update header before returning */
515  return update_hbh_header();
516 }
517 /*---------------------------------------------------------------------------*/
518 bool
520 {
521  uint8_t *prev_proto_ptr;
522  uint8_t protocol;
523  uint16_t ext_len;
524  uint8_t *next_header;
525  struct uip_ext_hdr *ext_ptr;
526  struct uip_ext_hdr_opt *opt_ptr;
527 
528  next_header = uipbuf_get_next_header(uip_buf, uip_len, &protocol, true);
529  if(next_header == NULL) {
530  return true;
531  }
532  ext_ptr = (struct uip_ext_hdr *)next_header;
533  prev_proto_ptr = &UIP_IP_BUF->proto;
534 
535  while(uip_is_proto_ext_hdr(protocol)) {
536  opt_ptr = (struct uip_ext_hdr_opt *)(next_header + 2);
537  if(protocol == UIP_PROTO_ROUTING ||
538  (protocol == UIP_PROTO_HBHO && opt_ptr->type == UIP_EXT_HDR_OPT_RPL)) {
539  /* Remove ext header */
540  *prev_proto_ptr = ext_ptr->next;
541  ext_len = ext_ptr->len * 8 + 8;
542  if(uipbuf_add_ext_hdr(-ext_len) == false) {
543  return false;
544  }
545 
546  /* Update length field and rest of packet to the "left" */
547  uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
548  if(uip_len <= next_header - uip_buf) {
549  /* No more data to move. */
550  return false;
551  }
552  memmove(next_header, next_header + ext_len,
553  uip_len - (next_header - uip_buf));
554 
555  /* Update loop variables */
556  protocol = *prev_proto_ptr;
557  } else {
558  /* move to the ext hdr */
559  next_header = uipbuf_get_next_header(next_header,
560  uip_len - (next_header - uip_buf),
561  &protocol, false);
562  if(next_header == NULL) {
563  /* Processing finished. */
564  break;
565  }
566  ext_ptr = (struct uip_ext_hdr *)next_header;
567  prev_proto_ptr = &ext_ptr->next;
568  }
569  }
570 
571  return true;
572 }
573 /*---------------------------------------------------------------------------*/
574 int
576 {
577  if(default_instance == NULL || default_instance->current_dag == NULL
578  || uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) || uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
579  return 1;
580  }
581 
582  if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
583  /* At the root, remove headers if any, and insert SRH or HBH
584  * (SRH is inserted only if the destination is in the DODAG) */
586  if(rpl_get_dag(&UIP_IP_BUF->destipaddr) != NULL) {
587  /* dest is in a DODAG; the packet is going down. */
588  if(RPL_IS_NON_STORING(default_instance)) {
589  return insert_srh_header();
590  } else {
591  return insert_hbh_header(default_instance);
592  }
593  } else {
594  /* dest is outside of DODAGs; no ext header is needed. */
595  return 1;
596  }
597  } else {
598  if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)
599  && UIP_IP_BUF->ttl == uip_ds6_if.cur_hop_limit) {
600  /* Insert HBH option at source. Checking the address is not sufficient because
601  * in non-storing mode, a packet may go up and then down the same path again */
602  return insert_hbh_header(default_instance);
603  } else {
604  /* Update HBH option at forwarders */
605  return update_hbh_header();
606  }
607  }
608 }
609 
610 /** @}*/
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:116
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition: uip.h:71
Header for the Contiki/uIP interface.
RPL DAG structure.
Definition: rpl.h:135
RPL instance structure.
Definition: rpl.h:219
#define ROOT_RANK
Rank of a root node.
Definition: rpl-types.h:78
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
#define UIP_PROTO_HBHO
extension headers types
Definition: uip.h:1764
int rpl_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr)
Look for next hop from SRH of current uIP packet.
int rpl_ext_header_update(void)
Adds/updates all RPL extension headers to current uIP packet.
#define UIP_LINK_MTU
The maximum transmission unit at the IP Layer.
Definition: uipopt.h:228
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.
Source routing support.
Header file for IPv6-related data structures.
An entry in the routing table.
uint16_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:122
Routing driver header file
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:510
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1015
uip_sr_node_t * uip_sr_get_node(void *graph, const uip_ipaddr_t *addr)
Looks up for a source routing node from its IPv6 global address.
Definition: uip-sr.c:81
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 4291 a is of type uip_ipaddr_t*
Definition: uip.h:1961
bool rpl_ext_header_remove(void)
Removes all RPL extension headers.
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1223
Header file for the uIP TCP/IP stack.
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
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
Header file for the Packet buffer (packetbuf) management
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC 4291 i.e.
Definition: uip.h:1877
Header file for the logging system
int uip_sr_is_addr_reachable(void *graph, const uip_ipaddr_t *addr)
Telle whether an address is reachable, i.e.
Definition: uip-sr.c:94
A node in a source routing graph, stored at the root and representing all child-parent relationship...
Definition: uip-sr.h:92
int rpl_ext_header_srh_update(void)
Process and update SRH in-place, i.e.