Contiki-Inga 3.x
rpl-ext-header.c
Go to the documentation of this file.
1 /**
2  * \addtogroup uip6
3  * @{
4  */
5 /*
6  * Copyright (c) 2009, Swedish Institute of Computer Science.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the Institute nor the names of its contributors
18  * may be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * This file is part of the Contiki operating system.
34  */
35 /**
36  * \file
37  * Management of extension headers for ContikiRPL.
38  *
39  * \author Vincent Brillault <vincent.brillault@imag.fr>,
40  * Joakim Eriksson <joakime@sics.se>,
41  * Niclas Finne <nfi@sics.se>,
42  * Nicolas Tsiftes <nvt@sics.se>.
43  */
44 
45 #include "net/ip/uip.h"
46 #include "net/ip/tcpip.h"
47 #include "net/ipv6/uip-ds6.h"
48 #include "net/rpl/rpl-private.h"
49 
50 #define DEBUG DEBUG_NONE
51 #include "net/ip/uip-debug.h"
52 
53 #include <limits.h>
54 #include <string.h>
55 
56 /*---------------------------------------------------------------------------*/
57 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
58 #define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len])
59 #define UIP_HBHO_BUF ((struct uip_hbho_hdr *)&uip_buf[uip_l2_l3_hdr_len])
60 #define UIP_HBHO_NEXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_HOP_BY_HOP_LEN])
61 #define UIP_EXT_HDR_OPT_BUF ((struct uip_ext_hdr_opt *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
62 #define UIP_EXT_HDR_OPT_PADN_BUF ((struct uip_ext_hdr_opt_padn *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
63 #define UIP_EXT_HDR_OPT_RPL_BUF ((struct uip_ext_hdr_opt_rpl *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
64 /*---------------------------------------------------------------------------*/
65 #if UIP_CONF_IPV6
66 int
67 rpl_verify_header(int uip_ext_opt_offset)
68 {
69  rpl_instance_t *instance;
70  int down;
71  uint8_t sender_closer;
72  uip_ds6_route_t *route;
73 
74  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
75  PRINTF("RPL: Bad header option! (wrong length)\n");
76  return 1;
77  }
78 
79  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
80  if(instance == NULL) {
81  PRINTF("RPL: Unknown instance: %u\n",
82  UIP_EXT_HDR_OPT_RPL_BUF->instance);
83  return 1;
84  }
85 
86  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
87  PRINTF("RPL: Forward error!\n");
88  /* We should try to repair it by removing the neighbor that caused
89  the packet to be forwareded in the first place. We drop any
90  routes that go through the neighbor that sent the packet to
91  us. */
92  route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
93  if(route != NULL) {
94  uip_ds6_route_rm(route);
95 
96  /* If we are the root and just needed to remove a DAO route,
97  chances are that the network needs to be repaired. The
98  rpl_repair_root() function will cause a global repair if we
99  happen to be the root node of the dag. */
100  PRINTF("RPL: initiate global repair\n");
101  rpl_repair_root(instance->instance_id);
102  }
103 
104  /* Remove the forwarding error flag and return 0 to let the packet
105  be forwarded again. */
106  UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_FWD_ERR;
107  return 0;
108  }
109 
110  if(!instance->current_dag->joined) {
111  PRINTF("RPL: No DAG in the instance\n");
112  return 1;
113  }
114 
115  down = 0;
116  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) {
117  down = 1;
118  }
119 
120  sender_closer = UIP_EXT_HDR_OPT_RPL_BUF->senderrank < instance->current_dag->rank;
121 
122  PRINTF("RPL: Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up",
123  sender_closer,
124  UIP_EXT_HDR_OPT_RPL_BUF->senderrank,
125  instance->current_dag->rank
126  );
127 
128  if((down && !sender_closer) || (!down && sender_closer)) {
129  PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
130  UIP_EXT_HDR_OPT_RPL_BUF->senderrank, instance->current_dag->rank,
131  sender_closer);
132  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) {
133  PRINTF("RPL: Rank error signalled in RPL option!\n");
134  /* We should try to repair it, not implemented for the moment */
135  rpl_reset_dio_timer(instance);
136  /* Forward the packet anyway. */
137  return 0;
138  }
139  PRINTF("RPL: Single error tolerated\n");
140  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR;
141  return 0;
142  }
143 
144  PRINTF("RPL: Rank OK\n");
145 
146  return 0;
147 }
148 /*---------------------------------------------------------------------------*/
149 static void
150 set_rpl_opt(unsigned uip_ext_opt_offset)
151 {
152  uint8_t temp_len;
153 
154  memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
155  memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN);
156  UIP_HBHO_BUF->next = UIP_IP_BUF->proto;
157  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
158  UIP_HBHO_BUF->len = RPL_HOP_BY_HOP_LEN - 8;
159  UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
160  UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
161  UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
162  UIP_EXT_HDR_OPT_RPL_BUF->instance = 0;
163  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0;
164  uip_len += RPL_HOP_BY_HOP_LEN;
165  temp_len = UIP_IP_BUF->len[1];
166  UIP_IP_BUF->len[1] += UIP_HBHO_BUF->len + 8;
167  if(UIP_IP_BUF->len[1] < temp_len) {
168  UIP_IP_BUF->len[0]++;
169  }
170 }
171 /*---------------------------------------------------------------------------*/
172 void
173 rpl_update_header_empty(void)
174 {
175  rpl_instance_t *instance;
176  int uip_ext_opt_offset;
177  int last_uip_ext_len;
178 
179  last_uip_ext_len = uip_ext_len;
180  uip_ext_len = 0;
181  uip_ext_opt_offset = 2;
182 
183  PRINTF("RPL: Verifying the presence of the RPL header option\n");
184 
185  switch(UIP_IP_BUF->proto) {
186  case UIP_PROTO_HBHO:
187  if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
188  PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n");
189  uip_ext_len = last_uip_ext_len;
190  return;
191  }
192  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
193  if(instance == NULL || !instance->used || !instance->current_dag->joined) {
194  PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n");
195  return;
196  }
197  break;
198  default:
199  PRINTF("RPL: No hop-by-hop option found, creating it\n");
200  if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
201  PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
202  uip_ext_len = last_uip_ext_len;
203  return;
204  }
205  set_rpl_opt(uip_ext_opt_offset);
206  uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
207  return;
208  }
209 
210  switch(UIP_EXT_HDR_OPT_BUF->type) {
211  case UIP_EXT_HDR_OPT_RPL:
212  PRINTF("RPL: Updating RPL option\n");
213  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = instance->current_dag->rank;
214 
215  /* Check the direction of the down flag, as per Section 11.2.2.3,
216  which states that if a packet is going down it should in
217  general not go back up again. If this happens, a
218  RPL_HDR_OPT_FWD_ERR should be flagged. */
219  if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
220  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
221  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
222  PRINTF("RPL forwarding error\n");
223  }
224  } else {
225  /* Set the down extension flag correctly as described in Section
226  11.2 of RFC6550. If the packet progresses along a DAO route,
227  the down flag should be set. */
228  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
229  /* No route was found, so this packet will go towards the RPL
230  root. If so, we should not set the down flag. */
231  UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
232  PRINTF("RPL option going up\n");
233  } else {
234  /* A DAO route was found so we set the down flag. */
235  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
236  PRINTF("RPL option going down\n");
237  }
238  }
239 
240  uip_ext_len = last_uip_ext_len;
241  return;
242  default:
243  PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
244  uip_ext_len = last_uip_ext_len;
245  return;
246  }
247 }
248 /*---------------------------------------------------------------------------*/
249 int
250 rpl_update_header_final(uip_ipaddr_t *addr)
251 {
252  rpl_parent_t *parent;
253  int uip_ext_opt_offset;
254  int last_uip_ext_len;
255 
256  last_uip_ext_len = uip_ext_len;
257  uip_ext_len = 0;
258  uip_ext_opt_offset = 2;
259 
260  if(UIP_IP_BUF->proto == UIP_PROTO_HBHO) {
261  if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
262  PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n");
263  uip_ext_len = last_uip_ext_len;
264  return 0;
265  }
266 
267  if(UIP_EXT_HDR_OPT_BUF->type == UIP_EXT_HDR_OPT_RPL) {
268  if(UIP_EXT_HDR_OPT_RPL_BUF->senderrank == 0) {
269  PRINTF("RPL: Updating RPL option\n");
270  if(default_instance == NULL || !default_instance->used || !default_instance->current_dag->joined) {
271  PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect default instance\n");
272  return 1;
273  }
274  parent = rpl_find_parent(default_instance->current_dag, addr);
275  if(parent == NULL || parent != parent->dag->preferred_parent) {
276  UIP_EXT_HDR_OPT_RPL_BUF->flags = RPL_HDR_OPT_DOWN;
277  }
278  UIP_EXT_HDR_OPT_RPL_BUF->instance = default_instance->instance_id;
279  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = default_instance->current_dag->rank;
280  uip_ext_len = last_uip_ext_len;
281  }
282  }
283  }
284  return 0;
285 }
286 /*---------------------------------------------------------------------------*/
287 void
288 rpl_remove_header(void)
289 {
290  uint8_t temp_len;
291 
292  uip_ext_len = 0;
293 
294  PRINTF("RPL: Verifying the presence of the RPL header option\n");
295  switch(UIP_IP_BUF->proto){
296  case UIP_PROTO_HBHO:
297  PRINTF("RPL: Removing the RPL header option\n");
298  UIP_IP_BUF->proto = UIP_HBHO_BUF->next;
299  temp_len = UIP_IP_BUF->len[1];
300  uip_len -= UIP_HBHO_BUF->len + 8;
301  UIP_IP_BUF->len[1] -= UIP_HBHO_BUF->len + 8;
302  if(UIP_IP_BUF->len[1] > temp_len) {
303  UIP_IP_BUF->len[0]--;
304  }
305  memmove(UIP_EXT_BUF, UIP_HBHO_NEXT_BUF, uip_len - UIP_IPH_LEN);
306  break;
307  default:
308  PRINTF("RPL: No hop-by-hop Option found\n");
309  }
310 }
311 /*---------------------------------------------------------------------------*/
312 uint8_t
313 rpl_invert_header(void)
314 {
315  uint8_t uip_ext_opt_offset;
316  uint8_t last_uip_ext_len;
317 
318  last_uip_ext_len = uip_ext_len;
319  uip_ext_len = 0;
320  uip_ext_opt_offset = 2;
321 
322  PRINTF("RPL: Verifying the presence of the RPL header option\n");
323  switch(UIP_IP_BUF->proto) {
324  case UIP_PROTO_HBHO:
325  break;
326  default:
327  PRINTF("RPL: No hop-by-hop Option found\n");
328  uip_ext_len = last_uip_ext_len;
329  return 0;
330  }
331 
332  switch (UIP_EXT_HDR_OPT_BUF->type) {
333  case UIP_EXT_HDR_OPT_RPL:
334  PRINTF("RPL: Updating RPL option (switching direction)\n");
335  UIP_EXT_HDR_OPT_RPL_BUF->flags &= RPL_HDR_OPT_DOWN;
336  UIP_EXT_HDR_OPT_RPL_BUF->flags ^= RPL_HDR_OPT_DOWN;
337  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance)->current_dag->rank;
338  uip_ext_len = last_uip_ext_len;
339  return RPL_HOP_BY_HOP_LEN;
340  default:
341  PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
342  uip_ext_len = last_uip_ext_len;
343  return 0;
344  }
345 }
346 /*---------------------------------------------------------------------------*/
347 void
348 rpl_insert_header(void)
349 {
350  uint8_t uip_ext_opt_offset;
351  if(default_instance != NULL) {
352  uip_ext_opt_offset = 2;
353  if(UIP_EXT_HDR_OPT_BUF->type == UIP_EXT_HDR_OPT_RPL) {
354  rpl_update_header_empty();
355  }
356  }
357 }
358 /*---------------------------------------------------------------------------*/
359 #endif /* UIP_CONF_IPV6 */