Contiki-NG
esmrf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Loughborough University - 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  * This file shows the implementations of the Enhanced Stateless
35  * Multicast RPL Forwarding (ESMRF)
36  *
37  * It will only work in RPL networks in MOP 3 "Storing with Multicast"
38  *
39  * \author
40  * Khaled Qorany kqorany2@gmail.com
41  */
42 
43 #include "contiki.h"
44 #include "contiki-net.h"
49 #include "net/routing/routing.h"
50 #include "net/ipv6/uip.h"
51 #include "net/netstack.h"
52 #include "net/packetbuf.h"
53 #if ROUTING_CONF_RPL_LITE
54 #include "net/routing/rpl-lite/rpl.h"
55 #endif /* ROUTING_CONF_RPL_LITE */
56 #if ROUTING_CONF_RPL_CLASSIC
57 #include "net/routing/rpl-classic/rpl.h"
58 #endif /* ROUTING_CONF_RPL_CLASSIC */
59 #include <string.h>
60 
61 extern uint16_t uip_slen;
62 
63 #define DEBUG NONE
64 #include "net/ipv6/uip-debug.h"
65 
66 #define ESMRF_VERBOSE NONE
67 
68 #if DEBUG && ESMRF_VERBOSE
69 #define VERBOSE_PRINTF(...) PRINTF(__VA_ARGS__)
70 #define VERBOSE_PRINT_SEED(s) PRINT_SEED(s)
71 #else
72 #define VERBOSE_PRINTF(...)
73 #define VERBOSE_PRINT_SEED(...)
74 #endif
75 
76 /*---------------------------------------------------------------------------*/
77 /* Maintain Stats */
78 #if UIP_MCAST6_STATS
79 static struct esmrf_stats stats;
80 
81 #define ESMRF_STATS_ADD(x) stats.x++
82 #define ESMRF_STATS_INIT() do { memset(&stats, 0, sizeof(stats)); } while(0)
83 #else /* UIP_MCAST6_STATS */
84 #define ESMRF_STATS_ADD(x)
85 #define ESMRF_STATS_INIT()
86 #endif
87 /*---------------------------------------------------------------------------*/
88 /* Macros */
89 /*---------------------------------------------------------------------------*/
90 /* CCI */
91 #define ESMRF_FWD_DELAY() (CLOCK_SECOND / 8)
92 /* Number of slots in the next 500ms */
93 #define ESMRF_INTERVAL_COUNT ((CLOCK_SECOND >> 2) / fwd_delay)
94 /*---------------------------------------------------------------------------*/
95 /* Internal Data */
96 /*---------------------------------------------------------------------------*/
97 static struct ctimer mcast_periodic;
98 static uint8_t mcast_len;
99 static uip_buf_t mcast_buf;
100 static uint8_t fwd_delay;
101 static uint8_t fwd_spread;
102 static struct uip_udp_conn *c;
103 static uip_ipaddr_t src_ip;
104 static uip_ipaddr_t des_ip;
105 /*---------------------------------------------------------------------------*/
106 /* uIPv6 Pointers */
107 /*---------------------------------------------------------------------------*/
108 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
109 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
110 #define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len])
111 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN])
112 /*---------------------------------------------------------------------------*/
113 /* Local function prototypes */
114 /*---------------------------------------------------------------------------*/
115 static void icmp_input(void);
116 static void icmp_output(void);
117 static void mcast_fwd(void *p);
118 int remove_ext_hdr(void);
119 /*---------------------------------------------------------------------------*/
120 /* Internal Data Structures */
121 /*---------------------------------------------------------------------------*/
122 struct multicast_on_behalf{ /* ICMP message of multicast_on_behalf */
123  uint16_t mcast_port;
124  uip_ipaddr_t mcast_ip;
125  uint8_t mcast_payload[UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN];
126 };
127 #define UIP_ICMP_MOB 18 /* Size of multicast_on_behalf ICMP header */
128 /*---------------------------------------------------------------------------*/
129 /* Temporary Stores */
130 /*---------------------------------------------------------------------------*/
131 static struct multicast_on_behalf *locmobptr;
132 static int loclen;
133 /*---------------------------------------------------------------------------*/
134 /* ESMRF ICMPv6 handler declaration */
135 UIP_ICMP6_HANDLER(esmrf_icmp_handler, ICMP6_ESMRF,
136  UIP_ICMP6_HANDLER_CODE_ANY, icmp_input);
137 /*---------------------------------------------------------------------------*/
138 static void
139 icmp_output()
140 {
141  uint16_t payload_len=0;
142  rpl_dag_t *dag_t;
143 
144  struct multicast_on_behalf *mob;
145  mob = (struct multicast_on_behalf *)UIP_ICMP_PAYLOAD;
146  memcpy(&mob->mcast_payload, &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN], uip_slen);
147 
148  UIP_IP_BUF->vtc = 0x60;
149  UIP_IP_BUF->tcflow = 0;
150  UIP_IP_BUF->flow = 0;
151  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
152  UIP_IP_BUF->ttl = ESMRF_IP_HOP_LIMIT;
153 
154  mob->mcast_port = (uint16_t) uip_udp_conn->rport;
155  uip_ipaddr_copy(&mob->mcast_ip, &UIP_IP_BUF->destipaddr);
156 
157  payload_len = UIP_ICMP_MOB + uip_slen;
158 
159  dag_t = rpl_get_any_dag();
160  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &dag_t->dag_id);
161  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
162 
163  VERBOSE_PRINTF("ESMRF: ICMPv6 Out - Hdr @ %p, payload @ %p to: ", UIP_ICMP_BUF, mob);
164  PRINT6ADDR(&UIP_IP_BUF->destipaddr);
165  PRINTF("\n");
166 
167  UIP_IP_BUF->len[0] = (UIP_ICMPH_LEN + payload_len) >> 8;
168  UIP_IP_BUF->len[1] = (UIP_ICMPH_LEN + payload_len) & 0xff;
169 
170  UIP_ICMP_BUF->type = ICMP6_ESMRF;
171  UIP_ICMP_BUF->icode = ESMRF_ICMP_CODE;
172 
173  UIP_ICMP_BUF->icmpchksum = 0;
174  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
175 
176  uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
177 
178  VERBOSE_PRINTF("ESMRF: ICMPv6 Out - %u bytes, uip_len %u bytes, uip_ext_len %u bytes\n",
179  payload_len, uip_len, uip_ext_len);
180 
182  ESMRF_STATS_ADD(icmp_out);
183  return;
184 }
185 /*---------------------------------------------------------------------------*/
186 static void
187 icmp_input()
188 {
189 #if UIP_CONF_IPV6_CHECKS
190  if(UIP_ICMP_BUF->icode != ESMRF_ICMP_CODE) {
191  PRINTF("ESMRF: ICMPv6 In, bad ICMP code\n");
192  ESMRF_STATS_ADD(icmp_bad);
193  return;
194  }
195  if(UIP_IP_BUF->ttl <= 1) {
196  PRINTF("ESMRF: ICMPv6 In, bad TTL\n");
197  ESMRF_STATS_ADD(icmp_bad);
198  return;
199  }
200 #endif
201 
202  remove_ext_hdr();
203 
204  PRINTF("ESMRF: ICMPv6 In from ");
205  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
206  PRINTF(" len %u, ext %u\n", uip_len, uip_ext_len);
207 
208  ESMRF_STATS_ADD(icmp_in);
209 
210  VERBOSE_PRINTF("ESMRF: ICMPv6 In, parse from %p to %p\n",
211  UIP_ICMP_PAYLOAD,
212  (uint8_t *)UIP_ICMP_PAYLOAD + uip_len -
213  uip_l2_l3_icmp_hdr_len);
214 
215 
216  locmobptr = (struct multicast_on_behalf *) UIP_ICMP_PAYLOAD;
217  loclen = uip_len - (uip_l2_l3_icmp_hdr_len + UIP_ICMP_MOB);
218 
219  uip_ipaddr_copy(&src_ip, &UIP_IP_BUF->srcipaddr);
220  uip_ipaddr_copy(&des_ip, &UIP_IP_BUF->destipaddr);
221 
222  /* Extract the original multicast message */
223  uip_ipaddr_copy(&c->ripaddr, &locmobptr->mcast_ip);
224  c->rport = locmobptr->mcast_port;
225  uip_slen = loclen;
226  uip_udp_conn=c;
227  memcpy(&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN], locmobptr->mcast_payload,
228  loclen > UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN?
229  UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN: loclen);
230 
231  uip_process(UIP_UDP_SEND_CONN);
232 
233  memcpy(&mcast_buf, &uip_buf[UIP_LLH_LEN], uip_len);
234  mcast_len = uip_len;
235  /* pass the packet to our uip_process to check if it is allowed to
236  * accept this packet or not */
237  uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &src_ip);
238  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &des_ip);
239  UIP_UDP_BUF->udpchksum = 0;
240 
241  uip_process(UIP_DATA);
242 
243  memcpy(&uip_buf[UIP_LLH_LEN], &mcast_buf, mcast_len);
244  uip_len = mcast_len;
245  /* Return the IP of the original Multicast sender */
246  uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &src_ip);
247  UIP_UDP_BUF->udpchksum = 0;
248  /* If we have an entry in the multicast routing table, something with
249  * a higher RPL rank (somewhere down the tree) is a group member */
250  if(uip_mcast6_route_lookup(&UIP_IP_BUF->destipaddr)) {
251  PRINTF("ESMRF: Forward this packet\n");
252  /* If we enter here, we will definitely forward */
254  }
255  uip_clear_buf();
256 }
257 /*---------------------------------------------------------------------------*/
258 static void
259 mcast_fwd(void *p)
260 {
261  memcpy(&uip_buf[UIP_LLH_LEN], &mcast_buf, mcast_len);
262  uip_len = mcast_len;
263  UIP_IP_BUF->ttl--;
264  tcpip_output(NULL);
265  uip_clear_buf();
266 }
267 /*---------------------------------------------------------------------------*/
268 static uint8_t
269 in()
270 {
271  rpl_dag_t *d; /* Our DODAG */
272  uip_ipaddr_t *parent_ipaddr; /* Our pref. parent's IPv6 address */
273  const uip_lladdr_t *parent_lladdr; /* Our pref. parent's LL address */
274 
275  /*
276  * Fetch a pointer to the LL address of our preferred parent
277  *
278  * ToDo: This rpl_get_any_dag() call is a dirty replacement of the previous
279  * rpl_get_dag(RPL_DEFAULT_INSTANCE);
280  * so that things can compile with the new RPL code. This needs updated to
281  * read instance ID from the RPL HBHO and use the correct parent accordingly
282  */
283  d = rpl_get_any_dag();
284  if(!d) {
285  PRINTF("ESMRF: No DODAG\n");
286  UIP_MCAST6_STATS_ADD(mcast_dropped);
287  return UIP_MCAST6_DROP;
288  }
289 
290  /* Retrieve our preferred parent's LL address */
291  parent_ipaddr = rpl_parent_get_ipaddr(d->preferred_parent);
292  parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr);
293 
294  if(parent_lladdr == NULL) {
295  PRINTF("ESMRF: No Parent found\n");
296  UIP_MCAST6_STATS_ADD(mcast_dropped);
297  return UIP_MCAST6_DROP;
298  }
299 
300  /*
301  * We accept a datagram if it arrived from our preferred parent, discard
302  * otherwise.
303  */
304  if(memcmp(parent_lladdr, packetbuf_addr(PACKETBUF_ADDR_SENDER),
305  UIP_LLADDR_LEN)) {
306  PRINTF("ESMRF: Routable in but ESMRF ignored it\n");
307  UIP_MCAST6_STATS_ADD(mcast_dropped);
308  return UIP_MCAST6_DROP;
309  }
310 
311  if(UIP_IP_BUF->ttl <= 1) {
312  UIP_MCAST6_STATS_ADD(mcast_dropped);
313  PRINTF("ESMRF: TTL too low\n");
314  return UIP_MCAST6_DROP;
315  }
316 
317  UIP_MCAST6_STATS_ADD(mcast_in_all);
318  UIP_MCAST6_STATS_ADD(mcast_in_unique);
319 
320  /* If we have an entry in the mcast routing table, something with
321  * a higher RPL rank (somewhere down the tree) is a group member */
322  if(uip_mcast6_route_lookup(&UIP_IP_BUF->destipaddr)) {
323  /* If we enter here, we will definitely forward */
324  UIP_MCAST6_STATS_ADD(mcast_fwd);
325 
326  /*
327  * Add a delay (D) of at least ESMRF_FWD_DELAY() to compensate for how
328  * contikimac handles broadcasts. We can't start our TX before the sender
329  * has finished its own.
330  */
331  fwd_delay = ESMRF_FWD_DELAY();
332 
333  /* Finalise D: D = min(ESMRF_FWD_DELAY(), ESMRF_MIN_FWD_DELAY) */
334 #if ESMRF_MIN_FWD_DELAY
335  if(fwd_delay < ESMRF_MIN_FWD_DELAY) {
336  fwd_delay = ESMRF_MIN_FWD_DELAY;
337  }
338 #endif
339 
340  if(fwd_delay == 0) {
341  /* No delay required, send it, do it now, why wait? */
342  UIP_IP_BUF->ttl--;
343  tcpip_output(NULL);
344  UIP_IP_BUF->ttl++; /* Restore before potential upstack delivery */
345  } else {
346  /* Randomise final delay in [D , D*Spread], step D */
347  fwd_spread = ESMRF_INTERVAL_COUNT;
348  if(fwd_spread > ESMRF_MAX_SPREAD) {
349  fwd_spread = ESMRF_MAX_SPREAD;
350  }
351  if(fwd_spread) {
352  fwd_delay = fwd_delay * (1 + ((random_rand() >> 11) % fwd_spread));
353  }
354 
355  memcpy(&mcast_buf, &uip_buf[UIP_LLH_LEN], uip_len);
356  mcast_len = uip_len;
357  ctimer_set(&mcast_periodic, fwd_delay, mcast_fwd, NULL);
358  }
359  PRINTF("ESMRF: %u bytes: fwd in %u [%u]\n",
360  uip_len, fwd_delay, fwd_spread);
361  } else {
362  PRINTF("ESMRF: Group unknown, dropping\n");
363  }
364 
365  /* Done with this packet unless we are a member of the mcast group */
366  if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) {
367  PRINTF("ESMRF: Not a group member. No further processing\n");
368  return UIP_MCAST6_DROP;
369  } else {
370  PRINTF("ESMRF: Ours. Deliver to upper layers\n");
371  UIP_MCAST6_STATS_ADD(mcast_in_ours);
372  return UIP_MCAST6_ACCEPT;
373  }
374 }
375 /*---------------------------------------------------------------------------*/
376 static void
377 init()
378 {
379  ESMRF_STATS_INIT();
380  UIP_MCAST6_STATS_INIT(&stats);
381 
383  /* Register the ICMPv6 input handler */
384  uip_icmp6_register_input_handler(&esmrf_icmp_handler);
385  c = udp_new(NULL, 0, NULL);
386 }
387 /*---------------------------------------------------------------------------*/
388 static void
389 out(void)
390 {
391  rpl_dag_t *dag_t;
392  dag_t = rpl_get_any_dag();
393  if (!dag_t){
394  PRINTF("ESMRF: There is no DODAG\n");
395  return;
396  }
397  if(dag_t->rank == 256){
398  PRINTF("ESMRF: I am the Root, thus send the multicast packet normally. \n");
399  return;
400  }
401  else{
402  PRINTF("ESMRF: I am not the Root\n");
403  PRINTF("Send multicast-on-befalf message (ICMPv6) instead to ");
404  PRINT6ADDR(&dag_t->dag_id);
405  PRINTF("\n");
406  icmp_output();
407  uip_slen=0;
408  return;
409  }
410 }
411 /*---------------------------------------------------------------------------*/
412 const struct uip_mcast6_driver esmrf_driver = {
413  "ESMRF",
414  init,
415  out,
416  in,
417 };
418 /*---------------------------------------------------------------------------*/
void uip_mcast6_route_init()
Multicast routing table init routine.
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:97
uint8_t tcpip_output(const uip_lladdr_t *a)
Output packet to layer 2 The eventual parameter is the MAC address of the destination.
Definition: tcpip.c:110
RPL DAG structure.
Definition: rpl.h:135
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:179
The data structure used to represent a multicast engine.
Definition: uip-mcast6.h:100
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
Definition: tcpip.c:636
void uip_process(uint8_t flag)
process the options within a hop by hop or destination option header
Definition: uip6.c:921
#define UIP_ICMP_BUF
Pointer to ICMP header.
Definition: uip-nd6.c:98
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:154
A set of debugging macros for the IP stack
#define UIP_LLADDR_LEN
802.15.4 address
Definition: uip.h:148
This header file contains configuration directives for uIPv6 multicast support.
uint8_t(* in)(void)
Process an incoming multicast datagram and determine whether it should be delivered up the stack or n...
Definition: uip-mcast6.h:138
#define ICMP6_ESMRF
ESMRF Multicast.
Definition: uip-icmp6.h:72
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:141
struct uip_udp_conn * udp_new(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Create a new UDP connection.
Definition: tcpip.c:265
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
Routing driver header file
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:513
rpl_dag_t * rpl_get_any_dag(void)
Returns pointer to any DAG (for compatibility with legagy RPL code)
Definition: rpl-dag.c:1050
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1018
Header file for multicast routing table manipulation.
void(* out)(void)
Process an outgoing datagram with a multicast IPv6 destination address.
Definition: uip-mcast6.h:120
Header file for the uIP TCP/IP stack.
void(* init)(void)
Initialize the multicast engine.
Definition: uip-mcast6.h:105
uint8_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:132
uint16_t uip_icmp6chksum(void)
Calculate the ICMP checksum of the packet in uip_buf.
Definition: uip6.c:384
uip_ipaddr_t ripaddr
The IP address of the remote peer.
Definition: uip.h:1398
Header file for IPv6 multicast forwarding stats maintenance
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
Register a handler which can handle a specific ICMPv6 message type.
Definition: uip-icmp6.c:106
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
uip_mcast6_route_t * uip_mcast6_route_lookup(uip_ipaddr_t *group)
Lookup a multicast route.
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
Definition: uip-ds6.c:519
uint16_t rport
The remote port number in network byte order.
Definition: uip.h:1400
Header file for the Enhanced Stateless Multicast RPL Forwarding (ESMRF)
Representation of a uIP UDP connection.
Definition: uip.h:1397
The uIP packet buffer.
Definition: uip.h:505