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 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 /*---------------------------------------------------------------------------*/
279 static int
280 count_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 /*---------------------------------------------------------------------------*/
291 static int
292 insert_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 /*---------------------------------------------------------------------------*/
428 static int
429 update_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 /*---------------------------------------------------------------------------*/
495 static int
496 insert_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 /*---------------------------------------------------------------------------*/
531 bool
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 /*---------------------------------------------------------------------------*/
587 int
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 /** @}*/
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
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:134
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.