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