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 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
65 #define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len])
66 #define UIP_HBHO_BUF ((struct uip_hbho_hdr *)&uip_buf[uip_l2_l3_hdr_len])
67 #define UIP_HBHO_NEXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_HOP_BY_HOP_LEN])
68 #define UIP_RH_BUF ((struct uip_routing_hdr *)&uip_buf[uip_l2_l3_hdr_len])
69 #define UIP_RPL_SRH_BUF ((struct uip_rpl_srh_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_RH_LEN])
70 #define UIP_EXT_HDR_OPT_BUF ((struct uip_ext_hdr_opt *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
71 #define UIP_EXT_HDR_OPT_PADN_BUF ((struct uip_ext_hdr_opt_padn *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
72 #define UIP_EXT_HDR_OPT_RPL_BUF ((struct uip_ext_hdr_opt_rpl *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
73 /*---------------------------------------------------------------------------*/
74 int
76 {
77  rpl_instance_t *instance;
78  int down;
79  uint16_t sender_rank;
80  uint8_t sender_closer;
81  uip_ds6_route_t *route;
82  rpl_parent_t *sender = NULL;
83 
84  if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
85  || UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL
86  || UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
87 
88  LOG_ERR("Hop-by-hop extension header has wrong size or type (%u %u %u)\n",
89  UIP_HBHO_BUF->len,
90  UIP_EXT_HDR_OPT_RPL_BUF->opt_type,
91  UIP_EXT_HDR_OPT_RPL_BUF->opt_len);
92  return 0; /* Drop */
93  }
94 
95  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
96  if(instance == NULL) {
97  LOG_ERR("Unknown instance: %u\n",
98  UIP_EXT_HDR_OPT_RPL_BUF->instance);
99  return 0;
100  }
101 
102  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
103  LOG_ERR("Forward error!\n");
104  /* We should try to repair it by removing the neighbor that caused
105  the packet to be forwareded in the first place. We drop any
106  routes that go through the neighbor that sent the packet to
107  us. */
108  if(RPL_IS_STORING(instance)) {
109  route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
110  if(route != NULL) {
111  uip_ds6_route_rm(route);
112  }
113  }
114  RPL_STAT(rpl_stats.forward_errors++);
115  /* Trigger DAO retransmission */
116  rpl_reset_dio_timer(instance);
117  /* drop the packet as it is not routable */
118  return 0;
119  }
120 
121  if(!instance->current_dag->joined) {
122  LOG_ERR("No DAG in the instance\n");
123  return 0;
124  }
125  down = 0;
126  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) {
127  down = 1;
128  }
129 
130  sender_rank = UIP_HTONS(UIP_EXT_HDR_OPT_RPL_BUF->senderrank);
131  sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER));
132 
133  if(sender != NULL && (UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR)) {
134  /* A rank error was signalled, attempt to repair it by updating
135  * the sender's rank from ext header */
136  sender->rank = sender_rank;
137  if(RPL_IS_NON_STORING(instance)) {
138  /* Select DAG and preferred parent only in non-storing mode. In storing mode,
139  * a parent switch would result in an immediate No-path DAO transmission, dropping
140  * current incoming packet. */
141  rpl_select_dag(instance, sender);
142  }
143  }
144 
145  sender_closer = sender_rank < instance->current_dag->rank;
146 
147  LOG_DBG("Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up",
148  sender_closer,
149  sender_rank,
150  instance->current_dag->rank
151  );
152 
153  if((down && !sender_closer) || (!down && sender_closer)) {
154  LOG_WARN("Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
155  sender_rank, instance->current_dag->rank,
156  sender_closer);
157  /* Attempt to repair the loop by sending a unicast DIO back to the sender
158  * so that it gets a fresh update of our rank. */
159  if(sender != NULL) {
160  instance->unicast_dio_target = sender;
161  rpl_schedule_unicast_dio_immediately(instance);
162  }
163  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) {
164  RPL_STAT(rpl_stats.loop_errors++);
165  LOG_ERR(" Rank error signalled in RPL option!\n");
166  /* Packet must be dropped and dio trickle timer reset, see RFC6550 - 11.2.2.2 */
167  rpl_reset_dio_timer(instance);
168  return 0;
169  }
170  LOG_WARN("Single error tolerated\n");
171  RPL_STAT(rpl_stats.loop_warnings++);
172  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR;
173  return 1;
174  }
175 
176  LOG_DBG("Rank OK\n");
177  return 1;
178 }
179 /*---------------------------------------------------------------------------*/
180 int
182 {
183 #if RPL_WITH_NON_STORING
184  uint8_t *uip_next_hdr;
185  int last_uip_ext_len = uip_ext_len;
186  rpl_dag_t *dag;
187  uip_sr_node_t *dest_node;
188  uip_sr_node_t *root_node;
189 
190  uip_ext_len = 0;
191  uip_next_hdr = &UIP_IP_BUF->proto;
192 
193  /* Look for routing header */
194  while(uip_next_hdr != NULL && *uip_next_hdr != UIP_PROTO_ROUTING) {
195  switch(*uip_next_hdr) {
196  case UIP_PROTO_HBHO:
197  case UIP_PROTO_DESTO:
198  /*
199  * As per RFC 2460, only the Hop-by-Hop Options header and
200  * Destination Options header can appear before the Routing
201  * header.
202  */
203  /* Move to next header */
204  uip_next_hdr = &UIP_EXT_BUF->next;
205  uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
206  break;
207  default:
208  uip_next_hdr = NULL;
209  break;
210  }
211  }
212 
213  dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
214  root_node = uip_sr_get_node(dag, &dag->dag_id);
215  dest_node = uip_sr_get_node(dag, &UIP_IP_BUF->destipaddr);
216 
217  if((uip_next_hdr != NULL && *uip_next_hdr == UIP_PROTO_ROUTING
218  && UIP_RH_BUF->routing_type == RPL_RH_TYPE_SRH) ||
219  (dest_node != NULL && root_node != NULL &&
220  dest_node->parent == root_node)) {
221  /* Routing header found or the packet destined for a direct child of the root.
222  * The next hop should be already copied as the IPv6 destination
223  * address, via rpl_ext_header_srh_update. We turn this address into a link-local to enable
224  * forwarding to next hop */
225  uip_ipaddr_copy(ipaddr, &UIP_IP_BUF->destipaddr);
226  uip_create_linklocal_prefix(ipaddr);
227  uip_ext_len = last_uip_ext_len;
228  return 1;
229  }
230 
231  uip_ext_len = last_uip_ext_len;
232  return 0;
233 #else /* RPL_WITH_NON_STORING */
234  return 0; /* SRH not found */
235 #endif /* RPL_WITH_NON_STORING */
236 }
237 /*---------------------------------------------------------------------------*/
238 int
240 {
241 #if RPL_WITH_NON_STORING
242  uint8_t *uip_next_hdr;
243  int last_uip_ext_len = uip_ext_len;
244 
245  uip_ext_len = 0;
246  uip_next_hdr = &UIP_IP_BUF->proto;
247 
248  /* Look for routing header */
249  while(uip_next_hdr != NULL && *uip_next_hdr != UIP_PROTO_ROUTING) {
250  switch(*uip_next_hdr) {
251  case UIP_PROTO_HBHO:
252  case UIP_PROTO_DESTO:
253  /*
254  * As per RFC 2460, only the Hop-by-Hop Options header and
255  * Destination Options header can appear before the Routing
256  * header.
257  */
258  /* Move to next header */
259  uip_next_hdr = &UIP_EXT_BUF->next;
260  uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
261  break;
262  default:
263  uip_next_hdr = NULL;
264  break;
265  }
266  }
267 
268  if(uip_next_hdr != NULL && *uip_next_hdr == UIP_PROTO_ROUTING
269  && UIP_RH_BUF->routing_type == RPL_RH_TYPE_SRH) {
270  /* SRH found, now look for next hop */
271  uint8_t cmpri, cmpre;
272  uint8_t ext_len;
273  uint8_t padding;
274  uint8_t path_len;
275  uint8_t segments_left;
276  uip_ipaddr_t current_dest_addr;
277 
278  segments_left = UIP_RH_BUF->seg_left;
279  ext_len = (UIP_RH_BUF->len * 8) + 8;
280  cmpri = UIP_RPL_SRH_BUF->cmpr >> 4;
281  cmpre = UIP_RPL_SRH_BUF->cmpr & 0x0f;
282  padding = UIP_RPL_SRH_BUF->pad >> 4;
283  path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
284  (void)path_len;
285 
286  LOG_DBG("read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n",
287  path_len, segments_left, cmpri, cmpre, ext_len, padding);
288 
289  if(segments_left == 0) {
290  /* We are the final destination, do nothing */
291  } else {
292  uint8_t i = path_len - segments_left; /* The index of the next address to be visited */
293  uint8_t *addr_ptr = ((uint8_t *)UIP_RH_BUF) + RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
294  uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
295 
296  /* As per RFC6554: swap the IPv6 destination address and address[i] */
297 
298  /* First, copy the current IPv6 destination address */
299  uip_ipaddr_copy(&current_dest_addr, &UIP_IP_BUF->destipaddr);
300  /* Second, update the IPv6 destination address with addresses[i] */
301  memcpy(((uint8_t *)&UIP_IP_BUF->destipaddr) + cmpr, addr_ptr, 16 - cmpr);
302  /* Third, write current_dest_addr to addresses[i] */
303  memcpy(addr_ptr, ((uint8_t *)&current_dest_addr) + cmpr, 16 - cmpr);
304 
305  /* Update segments left field */
306  UIP_RH_BUF->seg_left--;
307 
308  LOG_INFO("SRH next hop ");
309  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
310  LOG_INFO_("\n");
311  }
312  uip_ext_len = last_uip_ext_len;
313  return 1;
314  }
315 
316  uip_ext_len = last_uip_ext_len;
317  return 0;
318 #else /* RPL_WITH_NON_STORING */
319  return 0; /* SRH not found */
320 #endif /* RPL_WITH_NON_STORING */
321 }
322 /*---------------------------------------------------------------------------*/
323 static int
324 count_matching_bytes(const void *p1, const void *p2, size_t n)
325 {
326  int i = 0;
327  for(i = 0; i < n; i++) {
328  if(((uint8_t *)p1)[i] != ((uint8_t *)p2)[i]) {
329  return i;
330  }
331  }
332  return n;
333 }
334 /*---------------------------------------------------------------------------*/
335 static int
336 insert_srh_header(void)
337 {
338  /* Implementation of RFC6554 */
339  uint8_t temp_len;
340  uint8_t path_len;
341  uint8_t ext_len;
342  uint8_t cmpri, cmpre; /* ComprI and ComprE fields of the RPL Source Routing Header */
343  uint8_t *hop_ptr;
344  uint8_t padding;
345  uip_sr_node_t *dest_node;
346  uip_sr_node_t *root_node;
347  uip_sr_node_t *node;
348  rpl_dag_t *dag;
349  uip_ipaddr_t node_addr;
350 
351  LOG_INFO("SRH creating source routing header with destination ");
352  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
353  LOG_INFO_("\n");
354 
355  /* Construct source route. We do not do this recursively to keep the runtime stack usage constant. */
356 
357  /* Get link of the destination and root */
358  dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
359 
360  if(dag == NULL) {
361  LOG_ERR("SRH DAG not found\n");
362  return 0;
363  }
364 
365  dest_node = uip_sr_get_node(dag, &UIP_IP_BUF->destipaddr);
366  if(dest_node == NULL) {
367  /* The destination is not found, skip SRH insertion */
368  return 1;
369  }
370 
371  root_node = uip_sr_get_node(dag, &dag->dag_id);
372  if(root_node == NULL) {
373  LOG_ERR("SRH root node not found\n");
374  return 0;
375  }
376 
377  if(!uip_sr_is_addr_reachable(dag, &UIP_IP_BUF->destipaddr)) {
378  LOG_ERR("SRH no path found to destination\n");
379  return 0;
380  }
381 
382  /* Compute path length and compression factors (we use cmpri == cmpre) */
383  path_len = 0;
384  node = dest_node->parent;
385  /* For simplicity, we use cmpri = cmpre */
386  cmpri = 15;
387  cmpre = 15;
388 
389  if(node == root_node) {
390  LOG_DBG("SRH no need to insert SRH\n");
391  return 1;
392  }
393 
394  while(node != NULL && node != root_node) {
395 
396  NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
397 
398  /* How many bytes in common between all nodes in the path? */
399  cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &UIP_IP_BUF->destipaddr, 16));
400  cmpre = cmpri;
401 
402  LOG_DBG("SRH Hop ");
403  LOG_DBG_6ADDR(&node_addr);
404  LOG_DBG_("\n");
405  node = node->parent;
406  path_len++;
407  }
408 
409  /* Extension header length: fixed headers + (n-1) * (16-ComprI) + (16-ComprE)*/
410  ext_len = RPL_RH_LEN + RPL_SRH_LEN
411  + (path_len - 1) * (16 - cmpre)
412  + (16 - cmpri);
413 
414  padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8));
415  ext_len += padding;
416 
417  LOG_DBG("SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n",
418  path_len, cmpri, cmpre, ext_len, padding);
419 
420  /* Check if there is enough space to store the extension header */
421  if(uip_len + ext_len > UIP_BUFSIZE - UIP_LLH_LEN) {
422  LOG_ERR("Packet too long: impossible to add source routing header (%u bytes)\n", ext_len);
423  return 0;
424  }
425 
426  /* Move existing ext headers and payload uip_ext_len further */
427  memmove(uip_buf + uip_l2_l3_hdr_len + ext_len,
428  uip_buf + uip_l2_l3_hdr_len, uip_len - UIP_IPH_LEN);
429  memset(uip_buf + uip_l2_l3_hdr_len, 0, ext_len);
430 
431  /* Insert source routing header */
432  UIP_RH_BUF->next = UIP_IP_BUF->proto;
433  UIP_IP_BUF->proto = UIP_PROTO_ROUTING;
434 
435  /* Initialize IPv6 Routing Header */
436  UIP_RH_BUF->len = (ext_len - 8) / 8;
437  UIP_RH_BUF->routing_type = RPL_RH_TYPE_SRH;
438  UIP_RH_BUF->seg_left = path_len;
439 
440  /* Initialize RPL Source Routing Header */
441  UIP_RPL_SRH_BUF->cmpr = (cmpri << 4) + cmpre;
442  UIP_RPL_SRH_BUF->pad = padding << 4;
443 
444  /* Initialize addresses field (the actual source route).
445  * From last to first. */
446  node = dest_node;
447  hop_ptr = ((uint8_t *)UIP_RH_BUF) + ext_len - padding; /* Pointer where to write the next hop compressed address */
448 
449  while(node != NULL && node->parent != root_node) {
450  NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
451 
452  hop_ptr -= (16 - cmpri);
453  memcpy(hop_ptr, ((uint8_t*)&node_addr) + cmpri, 16 - cmpri);
454 
455  node = node->parent;
456  }
457 
458  /* The next hop (i.e. node whose parent is the root) is placed as the current IPv6 destination */
459  NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
460  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &node_addr);
461 
462  /* In-place update of IPv6 length field */
463  temp_len = UIP_IP_BUF->len[1];
464  UIP_IP_BUF->len[1] += ext_len;
465  if(UIP_IP_BUF->len[1] < temp_len) {
466  UIP_IP_BUF->len[0]++;
467  }
468 
469  uip_ext_len += ext_len;
470  uip_len += ext_len;
471 
472  return 1;
473 }
474 /*---------------------------------------------------------------------------*/
475 static int
476 update_hbh_header(void)
477 {
478  rpl_instance_t *instance;
479  int uip_ext_opt_offset;
480  int last_uip_ext_len;
481  rpl_parent_t *parent;
482 
483  last_uip_ext_len = uip_ext_len;
484  uip_ext_len = 0;
485  uip_ext_opt_offset = 2;
486 
487  if(UIP_IP_BUF->proto == UIP_PROTO_HBHO && UIP_EXT_HDR_OPT_RPL_BUF->opt_type == UIP_EXT_HDR_OPT_RPL) {
488  if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
489  || UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
490 
491  LOG_ERR("Hop-by-hop extension header has wrong size (%u %u)\n",
492  UIP_EXT_HDR_OPT_RPL_BUF->opt_len,
493  uip_ext_len);
494  return 0; /* Drop */
495  }
496 
497  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
498  if(instance == NULL || !instance->used || !instance->current_dag->joined) {
499  LOG_ERR("Unable to add/update hop-by-hop extension header: incorrect instance\n");
500  uip_ext_len = last_uip_ext_len;
501  return 0; /* Drop */
502  }
503 
504  LOG_INFO("Updating RPL option\n");
505  /* Update sender rank and instance, will update flags next */
506  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);
507  UIP_EXT_HDR_OPT_RPL_BUF->instance = instance->instance_id;
508 
509  if(RPL_IS_STORING(instance)) { /* In non-storing mode, downwards traffic does not have the HBH option */
510  /* Check the direction of the down flag, as per Section 11.2.2.3,
511  which states that if a packet is going down it should in
512  general not go back up again. If this happens, a
513  RPL_HDR_OPT_FWD_ERR should be flagged. */
514  if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
515  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
516  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
517  LOG_WARN("RPL forwarding error\n");
518  /* We should send back the packet to the originating parent,
519  but it is not feasible yet, so we send a No-Path DAO instead */
520  LOG_WARN("RPL generate No-Path DAO\n");
521  parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
522  if(parent != NULL) {
523  dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
524  }
525  /* Drop packet */
526  return 0;
527  }
528  } else {
529  /* Set the down extension flag correctly as described in Section
530  11.2 of RFC6550. If the packet progresses along a DAO route,
531  the down flag should be set. */
532  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
533  /* No route was found, so this packet will go towards the RPL
534  root. If so, we should not set the down flag. */
535  UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
536  LOG_DBG("RPL option going up\n");
537  } else {
538  /* A DAO route was found so we set the down flag. */
539  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
540  LOG_DBG("RPL option going down\n");
541  }
542  }
543  }
544  }
545 
546  uip_ext_len = last_uip_ext_len;
547  return 1;
548 }
549 /*---------------------------------------------------------------------------*/
550 static int
551 insert_hbh_header(const rpl_instance_t *instance)
552 {
553  int uip_ext_opt_offset;
554  int last_uip_ext_len;
555  uint8_t temp_len;
556 
557  last_uip_ext_len = uip_ext_len;
558  uip_ext_len = 0;
559  uip_ext_opt_offset = 2;
560 
561  /* Insert hop-by-hop header */
562  LOG_DBG("Creating hop-by-hop option\n");
563  if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE - UIP_LLH_LEN) {
564  LOG_ERR("Packet too long: impossible to add hop-by-hop option\n");
565  uip_ext_len = last_uip_ext_len;
566  return 0;
567  }
568 
569  /* Move existing ext headers and payload UIP_EXT_BUF further */
570  memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
571  memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN);
572 
573  /* Update IP and HBH protocol and fields */
574  UIP_HBHO_BUF->next = UIP_IP_BUF->proto;
575  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
576 
577  /* Initialize HBH option */
578  UIP_HBHO_BUF->len = (RPL_HOP_BY_HOP_LEN - 8) / 8;
579  UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
580  UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
581  UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
582  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);
583  UIP_EXT_HDR_OPT_RPL_BUF->instance = instance->instance_id;
584  uip_len += RPL_HOP_BY_HOP_LEN;
585  temp_len = UIP_IP_BUF->len[1];
586  UIP_IP_BUF->len[1] += RPL_HOP_BY_HOP_LEN;
587  if(UIP_IP_BUF->len[1] < temp_len) {
588  UIP_IP_BUF->len[0]++;
589  }
590 
591  uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
592 
593  /* Update header before returning */
594  return update_hbh_header();
595 }
596 /*---------------------------------------------------------------------------*/
597 void
599 {
600  uint8_t temp_len;
601  uint8_t rpl_ext_hdr_len;
602  int uip_ext_opt_offset;
603  uint8_t *uip_next_hdr;
604 
605  uip_ext_len = 0;
606  uip_ext_opt_offset = 2;
607  uip_next_hdr = &UIP_IP_BUF->proto;
608 
609  /* Look for hop-by-hop and routing headers */
610  while(uip_next_hdr != NULL) {
611  switch(*uip_next_hdr) {
612  case UIP_PROTO_HBHO:
613  case UIP_PROTO_ROUTING:
614  if((*uip_next_hdr != UIP_PROTO_HBHO || UIP_EXT_HDR_OPT_RPL_BUF->opt_type == UIP_EXT_HDR_OPT_RPL)) {
615  /* Remove hop-by-hop and routing headers */
616  *uip_next_hdr = UIP_EXT_BUF->next;
617  rpl_ext_hdr_len = (UIP_EXT_BUF->len * 8) + 8;
618  temp_len = UIP_IP_BUF->len[1];
619  uip_len -= rpl_ext_hdr_len;
620  UIP_IP_BUF->len[1] -= rpl_ext_hdr_len;
621  if(UIP_IP_BUF->len[1] > temp_len) {
622  UIP_IP_BUF->len[0]--;
623  }
624  LOG_DBG("Removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len);
625  memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN);
626  } else {
627  uip_next_hdr = &UIP_EXT_BUF->next;
628  uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
629  }
630  break;
631  case UIP_PROTO_DESTO:
632  /*
633  * As per RFC 2460, any header other than the Destination
634  * Options header does not appear between the Hop-by-Hop
635  * Options header and the Routing header.
636  *
637  * We're moving to the next header only if uip_next_hdr has
638  * UIP_PROTO_DESTO. Otherwise, we'll return.
639  */
640  /* Move to next header */
641  uip_next_hdr = &UIP_EXT_BUF->next;
642  uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
643  break;
644  default:
645  return;
646  }
647  }
648 }
649 /*---------------------------------------------------------------------------*/
650 int
652 {
653  if(default_instance == NULL || default_instance->current_dag == NULL
654  || uip_is_addr_linklocal(&UIP_IP_BUF->destipaddr) || uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
655  return 1;
656  }
657 
658  if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
659  /* At the root, remove headers if any, and insert SRH or HBH
660  * (SRH is inserted only if the destination is in the DODAG) */
662  if(rpl_get_dag(&UIP_IP_BUF->destipaddr) != NULL) {
663  /* dest is in a DODAG; the packet is going down. */
664  if(RPL_IS_NON_STORING(default_instance)) {
665  return insert_srh_header();
666  } else {
667  return insert_hbh_header(default_instance);
668  }
669  } else {
670  /* dest is outside of DODAGs; no ext header is needed. */
671  return 1;
672  }
673  } else {
674  if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)
675  && UIP_IP_BUF->ttl == uip_ds6_if.cur_hop_limit) {
676  /* Insert HBH option at source. Checking the address is not sufficient because
677  * in non-storing mode, a packet may go up and then down the same path again */
678  return insert_hbh_header(default_instance);
679  } else {
680  /* Update HBH option at forwarders */
681  return update_hbh_header();
682  }
683  }
684 }
685 
686 /** @}*/
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:125
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:97
void rpl_ext_header_remove(void)
Removes all RPL extension headers.
Header for the Contiki/uIP interface.
#define uip_l2_l3_hdr_len
The sums below are quite used in ND.
Definition: uip.h:75
RPL DAG structure.
Definition: rpl.h:135
RPL instance structure.
Definition: rpl.h:219
int rpl_ext_header_hbh_update(int uip_ext_opt_offset)
Process and update the RPL hop-by-hop extension headers of the current uIP packet.
#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:179
#define UIP_PROTO_HBHO
extension headers types
Definition: uip.h:1904
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:154
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.
Source routing support.
Header file for IPv6-related data structures.
An entry in the routing table.
uint8_t uip_ext_opt_offset
length of the header options read
Definition: uip6.c:134
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:141
Routing driver header file
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:513
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1018
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:2107
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1230
Header file for the uIP TCP/IP stack.
uint8_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:132
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
uint8_t * uip_next_hdr
Type of the next header in IPv6 header or extension headers.
Definition: uip6.c:125
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:90
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:2023
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.