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 /* Local function prototypes */
107 /*---------------------------------------------------------------------------*/
108 static void icmp_input(void);
109 static void icmp_output(void);
110 static void mcast_fwd(void *p);
111 /*---------------------------------------------------------------------------*/
112 /* Internal Data Structures */
113 /*---------------------------------------------------------------------------*/
114 struct multicast_on_behalf{ /* ICMP message of multicast_on_behalf */
115  uint16_t mcast_port;
116  uip_ipaddr_t mcast_ip;
117  uint8_t mcast_payload[UIP_BUFSIZE - UIP_IPUDPH_LEN];
118 };
119 #define UIP_ICMP_MOB 18 /* Size of multicast_on_behalf ICMP header */
120 /*---------------------------------------------------------------------------*/
121 /* Temporary Stores */
122 /*---------------------------------------------------------------------------*/
123 static struct multicast_on_behalf *locmobptr;
124 static int loclen;
125 /*---------------------------------------------------------------------------*/
126 /* ESMRF ICMPv6 handler declaration */
127 UIP_ICMP6_HANDLER(esmrf_icmp_handler, ICMP6_ESMRF,
128  UIP_ICMP6_HANDLER_CODE_ANY, icmp_input);
129 /*---------------------------------------------------------------------------*/
130 static void
131 icmp_output()
132 {
133  uint16_t payload_len=0;
134  rpl_dag_t *dag_t;
135 
136  struct multicast_on_behalf *mob;
137  mob = (struct multicast_on_behalf *)UIP_ICMP_PAYLOAD;
138  memcpy(&mob->mcast_payload, &uip_buf[UIP_IPUDPH_LEN], uip_slen);
139 
140  UIP_IP_BUF->vtc = 0x60;
141  UIP_IP_BUF->tcflow = 0;
142  UIP_IP_BUF->flow = 0;
143  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
144  UIP_IP_BUF->ttl = ESMRF_IP_HOP_LIMIT;
145 
146  mob->mcast_port = (uint16_t) uip_udp_conn->rport;
147  uip_ipaddr_copy(&mob->mcast_ip, &UIP_IP_BUF->destipaddr);
148 
149  payload_len = UIP_ICMP_MOB + uip_slen;
150 
151  dag_t = rpl_get_any_dag();
152  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &dag_t->dag_id);
153  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
154 
155  VERBOSE_PRINTF("ESMRF: ICMPv6 Out - Hdr @ %p, payload @ %p to: ", UIP_ICMP_BUF, mob);
156  PRINT6ADDR(&UIP_IP_BUF->destipaddr);
157  PRINTF("\n");
158 
159  uipbuf_set_len_field(UIP_IP_BUF, UIP_ICMPH_LEN + payload_len);
160 
161  UIP_ICMP_BUF->type = ICMP6_ESMRF;
162  UIP_ICMP_BUF->icode = ESMRF_ICMP_CODE;
163 
164  UIP_ICMP_BUF->icmpchksum = 0;
165  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
166 
167  uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
168 
169  VERBOSE_PRINTF("ESMRF: ICMPv6 Out - %u bytes, uip_len %u bytes, uip_ext_len %u bytes\n",
170  payload_len, uip_len, uip_ext_len);
171 
173  ESMRF_STATS_ADD(icmp_out);
174  return;
175 }
176 /*---------------------------------------------------------------------------*/
177 static void
178 icmp_input()
179 {
180 #if UIP_CONF_IPV6_CHECKS
181  if(UIP_ICMP_BUF->icode != ESMRF_ICMP_CODE) {
182  PRINTF("ESMRF: ICMPv6 In, bad ICMP code\n");
183  ESMRF_STATS_ADD(icmp_bad);
184  return;
185  }
186  if(UIP_IP_BUF->ttl <= 1) {
187  PRINTF("ESMRF: ICMPv6 In, bad TTL\n");
188  ESMRF_STATS_ADD(icmp_bad);
189  return;
190  }
191 #endif
192 
194 
195  PRINTF("ESMRF: ICMPv6 In from ");
196  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
197  PRINTF(" len %u, ext %u\n", uip_len, uip_ext_len);
198 
199  ESMRF_STATS_ADD(icmp_in);
200 
201  VERBOSE_PRINTF("ESMRF: ICMPv6 In, parse from %p to %p\n",
202  UIP_ICMP_PAYLOAD,
203  (uint8_t *)UIP_ICMP_PAYLOAD + uip_len -
204  uip_l3_icmp_hdr_len);
205 
206 
207  locmobptr = (struct multicast_on_behalf *) UIP_ICMP_PAYLOAD;
208  loclen = uip_len - (uip_l3_icmp_hdr_len + UIP_ICMP_MOB);
209 
210  uip_ipaddr_copy(&src_ip, &UIP_IP_BUF->srcipaddr);
211  uip_ipaddr_copy(&des_ip, &UIP_IP_BUF->destipaddr);
212 
213  /* Extract the original multicast message */
214  uip_ipaddr_copy(&c->ripaddr, &locmobptr->mcast_ip);
215  c->rport = locmobptr->mcast_port;
216  uip_slen = loclen;
217  uip_udp_conn=c;
218  memcpy(&uip_buf[UIP_IPUDPH_LEN], locmobptr->mcast_payload,
219  loclen > UIP_BUFSIZE - UIP_IPUDPH_LEN?
220  UIP_BUFSIZE - UIP_IPUDPH_LEN: loclen);
221 
222  uip_process(UIP_UDP_SEND_CONN);
223 
224  memcpy(&mcast_buf, uip_buf, uip_len);
225  mcast_len = uip_len;
226  /* pass the packet to our uip_process to check if it is allowed to
227  * accept this packet or not */
228  uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &src_ip);
229  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &des_ip);
230  UIP_UDP_BUF->udpchksum = 0;
231 
232  uip_process(UIP_DATA);
233 
234  memcpy(uip_buf, &mcast_buf, mcast_len);
235  uip_len = mcast_len;
236  /* Return the IP of the original Multicast sender */
237  uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &src_ip);
238  UIP_UDP_BUF->udpchksum = 0;
239  /* If we have an entry in the multicast routing table, something with
240  * a higher RPL rank (somewhere down the tree) is a group member */
241  if(uip_mcast6_route_lookup(&UIP_IP_BUF->destipaddr)) {
242  PRINTF("ESMRF: Forward this packet\n");
243  /* If we enter here, we will definitely forward */
245  }
246  uipbuf_clear();
247 }
248 /*---------------------------------------------------------------------------*/
249 static void
250 mcast_fwd(void *p)
251 {
252  memcpy(uip_buf, &mcast_buf, mcast_len);
253  uip_len = mcast_len;
254  UIP_IP_BUF->ttl--;
255  tcpip_output(NULL);
256  uipbuf_clear();
257 }
258 /*---------------------------------------------------------------------------*/
259 static uint8_t
260 in()
261 {
262  rpl_dag_t *d; /* Our DODAG */
263  uip_ipaddr_t *parent_ipaddr; /* Our pref. parent's IPv6 address */
264  const uip_lladdr_t *parent_lladdr; /* Our pref. parent's LL address */
265 
266  /*
267  * Fetch a pointer to the LL address of our preferred parent
268  *
269  * ToDo: This rpl_get_any_dag() call is a dirty replacement of the previous
270  * rpl_get_dag(RPL_DEFAULT_INSTANCE);
271  * so that things can compile with the new RPL code. This needs updated to
272  * read instance ID from the RPL HBHO and use the correct parent accordingly
273  */
274  d = rpl_get_any_dag();
275  if(!d) {
276  PRINTF("ESMRF: No DODAG\n");
277  UIP_MCAST6_STATS_ADD(mcast_dropped);
278  return UIP_MCAST6_DROP;
279  }
280 
281  /* Retrieve our preferred parent's LL address */
282  parent_ipaddr = rpl_parent_get_ipaddr(d->preferred_parent);
283  parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr);
284 
285  if(parent_lladdr == NULL) {
286  PRINTF("ESMRF: No Parent found\n");
287  UIP_MCAST6_STATS_ADD(mcast_dropped);
288  return UIP_MCAST6_DROP;
289  }
290 
291  /*
292  * We accept a datagram if it arrived from our preferred parent, discard
293  * otherwise.
294  */
295  if(memcmp(parent_lladdr, packetbuf_addr(PACKETBUF_ADDR_SENDER),
296  UIP_LLADDR_LEN)) {
297  PRINTF("ESMRF: Routable in but ESMRF ignored it\n");
298  UIP_MCAST6_STATS_ADD(mcast_dropped);
299  return UIP_MCAST6_DROP;
300  }
301 
302  if(UIP_IP_BUF->ttl <= 1) {
303  UIP_MCAST6_STATS_ADD(mcast_dropped);
304  PRINTF("ESMRF: TTL too low\n");
305  return UIP_MCAST6_DROP;
306  }
307 
308  UIP_MCAST6_STATS_ADD(mcast_in_all);
309  UIP_MCAST6_STATS_ADD(mcast_in_unique);
310 
311  /* If we have an entry in the mcast routing table, something with
312  * a higher RPL rank (somewhere down the tree) is a group member */
313  if(uip_mcast6_route_lookup(&UIP_IP_BUF->destipaddr)) {
314  /* If we enter here, we will definitely forward */
315  UIP_MCAST6_STATS_ADD(mcast_fwd);
316 
317  /*
318  * Add a delay (D) of at least ESMRF_FWD_DELAY() to compensate for how
319  * contikimac handles broadcasts. We can't start our TX before the sender
320  * has finished its own.
321  */
322  fwd_delay = ESMRF_FWD_DELAY();
323 
324  /* Finalise D: D = min(ESMRF_FWD_DELAY(), ESMRF_MIN_FWD_DELAY) */
325 #if ESMRF_MIN_FWD_DELAY
326  if(fwd_delay < ESMRF_MIN_FWD_DELAY) {
327  fwd_delay = ESMRF_MIN_FWD_DELAY;
328  }
329 #endif
330 
331  if(fwd_delay == 0) {
332  /* No delay required, send it, do it now, why wait? */
333  UIP_IP_BUF->ttl--;
334  tcpip_output(NULL);
335  UIP_IP_BUF->ttl++; /* Restore before potential upstack delivery */
336  } else {
337  /* Randomise final delay in [D , D*Spread], step D */
338  fwd_spread = ESMRF_INTERVAL_COUNT;
339  if(fwd_spread > ESMRF_MAX_SPREAD) {
340  fwd_spread = ESMRF_MAX_SPREAD;
341  }
342  if(fwd_spread) {
343  fwd_delay = fwd_delay * (1 + ((random_rand() >> 11) % fwd_spread));
344  }
345 
346  memcpy(&mcast_buf, uip_buf, uip_len);
347  mcast_len = uip_len;
348  ctimer_set(&mcast_periodic, fwd_delay, mcast_fwd, NULL);
349  }
350  PRINTF("ESMRF: %u bytes: fwd in %u [%u]\n",
351  uip_len, fwd_delay, fwd_spread);
352  } else {
353  PRINTF("ESMRF: Group unknown, dropping\n");
354  }
355 
356  /* Done with this packet unless we are a member of the mcast group */
357  if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) {
358  PRINTF("ESMRF: Not a group member. No further processing\n");
359  return UIP_MCAST6_DROP;
360  } else {
361  PRINTF("ESMRF: Ours. Deliver to upper layers\n");
362  UIP_MCAST6_STATS_ADD(mcast_in_ours);
363  return UIP_MCAST6_ACCEPT;
364  }
365 }
366 /*---------------------------------------------------------------------------*/
367 static void
368 init()
369 {
370  ESMRF_STATS_INIT();
371  UIP_MCAST6_STATS_INIT(&stats);
372 
374  /* Register the ICMPv6 input handler */
375  uip_icmp6_register_input_handler(&esmrf_icmp_handler);
376  c = udp_new(NULL, 0, NULL);
377 }
378 /*---------------------------------------------------------------------------*/
379 static void
380 out(void)
381 {
382  rpl_dag_t *dag_t;
383  dag_t = rpl_get_any_dag();
384  if (!dag_t){
385  PRINTF("ESMRF: There is no DODAG\n");
386  return;
387  }
388  if(dag_t->rank == 256){
389  PRINTF("ESMRF: I am the Root, thus send the multicast packet normally. \n");
390  return;
391  }
392  else{
393  PRINTF("ESMRF: I am not the Root\n");
394  PRINTF("Send multicast-on-befalf message (ICMPv6) instead to ");
395  PRINT6ADDR(&dag_t->dag_id);
396  PRINTF("\n");
397  icmp_output();
398  uip_slen=0;
399  return;
400  }
401 }
402 /*---------------------------------------------------------------------------*/
403 const struct uip_mcast6_driver esmrf_driver = {
404  "ESMRF",
405  init,
406  out,
407  in,
408 };
409 /*---------------------------------------------------------------------------*/
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
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:1070
#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