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 
52 #define DEBUG DEBUG_NONE
53 #include "net/ip/uip-debug.h"
54 
55 #include <limits.h>
56 #include <string.h>
57 
58 /*---------------------------------------------------------------------------*/
59 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
60 #define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len])
61 #define UIP_HBHO_BUF ((struct uip_hbho_hdr *)&uip_buf[uip_l2_l3_hdr_len])
62 #define UIP_HBHO_NEXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_HOP_BY_HOP_LEN])
63 #define UIP_EXT_HDR_OPT_BUF ((struct uip_ext_hdr_opt *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
64 #define UIP_EXT_HDR_OPT_PADN_BUF ((struct uip_ext_hdr_opt_padn *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
65 #define UIP_EXT_HDR_OPT_RPL_BUF ((struct uip_ext_hdr_opt_rpl *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
66 /*---------------------------------------------------------------------------*/
67 #if UIP_CONF_IPV6
68 int
69 rpl_verify_header(int uip_ext_opt_offset)
70 {
71  rpl_instance_t *instance;
72  int down;
73  uint16_t sender_rank;
74  uint8_t sender_closer;
75  uip_ds6_route_t *route;
76 
77  if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
78  PRINTF("RPL: Hop-by-hop extension header has wrong size\n");
79  return 1;
80  }
81 
82  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) {
83  PRINTF("RPL: Non RPL Hop-by-hop option\n");
84  return 1;
85  }
86 
87  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
88  PRINTF("RPL: Bad header option! (wrong length)\n");
89  return 1;
90  }
91 
92  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
93  if(instance == NULL) {
94  PRINTF("RPL: Unknown instance: %u\n",
95  UIP_EXT_HDR_OPT_RPL_BUF->instance);
96  return 1;
97  }
98 
99  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
100  PRINTF("RPL: Forward error!\n");
101  /* We should try to repair it by removing the neighbor that caused
102  the packet to be forwareded in the first place. We drop any
103  routes that go through the neighbor that sent the packet to
104  us. */
105  route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
106  if(route != NULL) {
107  uip_ds6_route_rm(route);
108 
109  /* If we are the root and just needed to remove a DAO route,
110  chances are that the network needs to be repaired. The
111  rpl_repair_root() function will cause a global repair if we
112  happen to be the root node of the dag. */
113  PRINTF("RPL: initiate global repair\n");
114  rpl_repair_root(instance->instance_id);
115  }
116 
117  /* Remove the forwarding error flag and return 0 to let the packet
118  be forwarded again. */
119  UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_FWD_ERR;
120  return 0;
121  }
122 
123  if(!instance->current_dag->joined) {
124  PRINTF("RPL: No DAG in the instance\n");
125  return 1;
126  }
127 
128  down = 0;
129  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) {
130  down = 1;
131  }
132 
133  sender_rank = UIP_HTONS(UIP_EXT_HDR_OPT_RPL_BUF->senderrank);
134  sender_closer = sender_rank < instance->current_dag->rank;
135 
136  PRINTF("RPL: Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up",
137  sender_closer,
138  sender_rank,
139  instance->current_dag->rank
140  );
141 
142  if((down && !sender_closer) || (!down && sender_closer)) {
143  PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
144  sender_rank, instance->current_dag->rank,
145  sender_closer);
146  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) {
147  PRINTF("RPL: Rank error signalled in RPL option!\n");
148  /* We should try to repair it, not implemented for the moment */
149  rpl_reset_dio_timer(instance);
150  /* Forward the packet anyway. */
151  return 0;
152  }
153  PRINTF("RPL: Single error tolerated\n");
154  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR;
155  return 0;
156  }
157 
158  PRINTF("RPL: Rank OK\n");
159 
160  return 0;
161 }
162 /*---------------------------------------------------------------------------*/
163 static void
164 set_rpl_opt(unsigned uip_ext_opt_offset)
165 {
166  uint8_t temp_len;
167 
168  memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
169  memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN);
170  UIP_HBHO_BUF->next = UIP_IP_BUF->proto;
171  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
172  UIP_HBHO_BUF->len = RPL_HOP_BY_HOP_LEN - 8;
173  UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
174  UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
175  UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
176  UIP_EXT_HDR_OPT_RPL_BUF->instance = 0;
177  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0;
178  uip_len += RPL_HOP_BY_HOP_LEN;
179  temp_len = UIP_IP_BUF->len[1];
180  UIP_IP_BUF->len[1] += UIP_HBHO_BUF->len + 8;
181  if(UIP_IP_BUF->len[1] < temp_len) {
182  UIP_IP_BUF->len[0]++;
183  }
184 }
185 /*---------------------------------------------------------------------------*/
186 void
187 rpl_update_header_empty(void)
188 {
189  rpl_instance_t *instance;
190  int uip_ext_opt_offset;
191  int last_uip_ext_len;
192 
193  last_uip_ext_len = uip_ext_len;
194  uip_ext_len = 0;
195  uip_ext_opt_offset = 2;
196 
197  PRINTF("RPL: Verifying the presence of the RPL header option\n");
198 
199  switch(UIP_IP_BUF->proto) {
200  case UIP_PROTO_HBHO:
201  if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
202  PRINTF("RPL: Hop-by-hop extension header has wrong size\n");
203  uip_ext_len = last_uip_ext_len;
204  return;
205  }
206  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) {
207  PRINTF("RPL: Non RPL Hop-by-hop option support not implemented\n");
208  uip_ext_len = last_uip_ext_len;
209  return;
210  }
211  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
212  PRINTF("RPL: RPL Hop-by-hop option has wrong length\n");
213  uip_ext_len = last_uip_ext_len;
214  return;
215  }
216  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
217  if(instance == NULL || !instance->used || !instance->current_dag->joined) {
218  PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n");
219  return;
220  }
221  break;
222  default:
223  PRINTF("RPL: No hop-by-hop option found, creating it\n");
224  if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
225  PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
226  uip_ext_len = last_uip_ext_len;
227  return;
228  }
229  set_rpl_opt(uip_ext_opt_offset);
230  uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
231  return;
232  }
233 
234  switch(UIP_EXT_HDR_OPT_BUF->type) {
235  case UIP_EXT_HDR_OPT_RPL:
236  PRINTF("RPL: Updating RPL option\n");
237  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);
238 
239  /* Check the direction of the down flag, as per Section 11.2.2.3,
240  which states that if a packet is going down it should in
241  general not go back up again. If this happens, a
242  RPL_HDR_OPT_FWD_ERR should be flagged. */
243  if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
244  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
245  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
246  PRINTF("RPL forwarding error\n");
247  }
248  } else {
249  /* Set the down extension flag correctly as described in Section
250  11.2 of RFC6550. If the packet progresses along a DAO route,
251  the down flag should be set. */
252  if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
253  /* No route was found, so this packet will go towards the RPL
254  root. If so, we should not set the down flag. */
255  UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
256  PRINTF("RPL option going up\n");
257  } else {
258  /* A DAO route was found so we set the down flag. */
259  UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
260  PRINTF("RPL option going down\n");
261  }
262  }
263 
264  uip_ext_len = last_uip_ext_len;
265  return;
266  default:
267  PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
268  uip_ext_len = last_uip_ext_len;
269  return;
270  }
271 }
272 /*---------------------------------------------------------------------------*/
273 int
274 rpl_update_header_final(uip_ipaddr_t *addr)
275 {
276  rpl_parent_t *parent;
277  int uip_ext_opt_offset;
278  int last_uip_ext_len;
279 
280  last_uip_ext_len = uip_ext_len;
281  uip_ext_len = 0;
282  uip_ext_opt_offset = 2;
283 
284  if(UIP_IP_BUF->proto == UIP_PROTO_HBHO) {
285  if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
286  PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n");
287  uip_ext_len = last_uip_ext_len;
288  return 0;
289  }
290 
291  if(UIP_EXT_HDR_OPT_BUF->type == UIP_EXT_HDR_OPT_RPL) {
292  if(UIP_EXT_HDR_OPT_RPL_BUF->senderrank == 0) {
293  PRINTF("RPL: Updating RPL option\n");
294  if(default_instance == NULL || !default_instance->used || !default_instance->current_dag->joined) {
295  PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect default instance\n");
296  return 1;
297  }
298  parent = rpl_find_parent(default_instance->current_dag, addr);
299  if(parent == NULL || parent != parent->dag->preferred_parent) {
300  UIP_EXT_HDR_OPT_RPL_BUF->flags = RPL_HDR_OPT_DOWN;
301  }
302  UIP_EXT_HDR_OPT_RPL_BUF->instance = default_instance->instance_id;
303  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(default_instance->current_dag->rank);
304  }
305  }
306  }
307  return 0;
308 }
309 /*---------------------------------------------------------------------------*/
310 void
311 rpl_remove_header(void)
312 {
313  uint8_t temp_len;
314 
315  uip_ext_len = 0;
316 
317  PRINTF("RPL: Verifying the presence of the RPL header option\n");
318  switch(UIP_IP_BUF->proto){
319  case UIP_PROTO_HBHO:
320  PRINTF("RPL: Removing the RPL header option\n");
321  UIP_IP_BUF->proto = UIP_HBHO_BUF->next;
322  temp_len = UIP_IP_BUF->len[1];
323  uip_len -= UIP_HBHO_BUF->len + 8;
324  UIP_IP_BUF->len[1] -= UIP_HBHO_BUF->len + 8;
325  if(UIP_IP_BUF->len[1] > temp_len) {
326  UIP_IP_BUF->len[0]--;
327  }
328  memmove(UIP_EXT_BUF, UIP_HBHO_NEXT_BUF, uip_len - UIP_IPH_LEN);
329  break;
330  default:
331  PRINTF("RPL: No hop-by-hop Option found\n");
332  }
333 }
334 /*---------------------------------------------------------------------------*/
335 uint8_t
336 rpl_invert_header(void)
337 {
338  uint8_t uip_ext_opt_offset;
339  uint8_t last_uip_ext_len;
340 
341  last_uip_ext_len = uip_ext_len;
342  uip_ext_len = 0;
343  uip_ext_opt_offset = 2;
344 
345  PRINTF("RPL: Verifying the presence of the RPL header option\n");
346  switch(UIP_IP_BUF->proto) {
347  case UIP_PROTO_HBHO:
348  break;
349  default:
350  PRINTF("RPL: No hop-by-hop Option found\n");
351  uip_ext_len = last_uip_ext_len;
352  return 0;
353  }
354 
355  switch (UIP_EXT_HDR_OPT_BUF->type) {
356  case UIP_EXT_HDR_OPT_RPL:
357  PRINTF("RPL: Updating RPL option (switching direction)\n");
358  UIP_EXT_HDR_OPT_RPL_BUF->flags &= RPL_HDR_OPT_DOWN;
359  UIP_EXT_HDR_OPT_RPL_BUF->flags ^= RPL_HDR_OPT_DOWN;
360  UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance)->current_dag->rank);
361  uip_ext_len = last_uip_ext_len;
362  return RPL_HOP_BY_HOP_LEN;
363  default:
364  PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
365  uip_ext_len = last_uip_ext_len;
366  return 0;
367  }
368 }
369 /*---------------------------------------------------------------------------*/
370 void
371 rpl_insert_header(void)
372 {
373  if(default_instance != NULL && !uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
374  rpl_update_header_empty();
375  }
376 }
377 /*---------------------------------------------------------------------------*/
378 #endif /* UIP_CONF_IPV6 */
379 
380 /** @}*/
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
An entry in the routing table.
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 3513 a is of type uip_ipaddr_t*
Definition: uip.h:2095
Header file for the uIP TCP/IP stack.
Header for the Contiki/uIP interface.
Network interface and stateless autoconfiguration (RFC 4862)
#define NULL
The null pointer.
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:173
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1238
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:104
uint8_t uip_ext_opt_offset
length of the header options read
Definition: uip6.c:139
uint8_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:137
#define UIP_PROTO_HBHO
extension headers types
Definition: uip.h:1886
A set of debugging macros.