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