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