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