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
63extern 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
81static 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/*---------------------------------------------------------------------------*/
99static struct ctimer mcast_periodic;
100static uint8_t mcast_len;
101static uip_buf_t mcast_buf;
102static uint8_t fwd_delay;
103static uint8_t fwd_spread;
104static struct uip_udp_conn *c;
105static uip_ipaddr_t src_ip;
106static uip_ipaddr_t des_ip;
107/*---------------------------------------------------------------------------*/
108/* Local function prototypes */
109/*---------------------------------------------------------------------------*/
110static void icmp_input(void);
111static void icmp_output(void);
112static void mcast_fwd(void *p);
113/*---------------------------------------------------------------------------*/
114/* Internal Data Structures */
115/*---------------------------------------------------------------------------*/
116struct 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/*---------------------------------------------------------------------------*/
125static struct multicast_on_behalf *locmobptr;
126static int loclen;
127/*---------------------------------------------------------------------------*/
128/* ESMRF ICMPv6 handler declaration */
129UIP_ICMP6_HANDLER(esmrf_icmp_handler, ICMP6_ESMRF,
130 UIP_ICMP6_HANDLER_CODE_ANY, icmp_input);
131/*---------------------------------------------------------------------------*/
132static void
133icmp_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
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/*---------------------------------------------------------------------------*/
179static void
180icmp_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/*---------------------------------------------------------------------------*/
251static void
252mcast_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/*---------------------------------------------------------------------------*/
261static uint8_t
262in()
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),
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/*---------------------------------------------------------------------------*/
369static void
370init()
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/*---------------------------------------------------------------------------*/
381static void
382out(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/*---------------------------------------------------------------------------*/
405const struct uip_mcast6_driver esmrf_driver = {
406 "ESMRF",
407 init,
408 out,
409 in,
410};
411/*---------------------------------------------------------------------------*/
Header file for the Enhanced Stateless Multicast RPL Forwarding (ESMRF)
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
static void icmp_in(void)
Definition: mpl.c:1063
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
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
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
Definition: tcpip.c:631
uip_mcast6_route_t * uip_mcast6_route_lookup(uip_ipaddr_t *group)
Lookup a multicast route.
void uip_mcast6_route_init()
Multicast routing table init routine.
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_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_LLADDR_LEN
802.15.4 address
Definition: uip.h:145
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
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
Definition: uip-ds6.c:538
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
#define ICMP6_ESMRF
ESMRF Multicast.
Definition: uip-icmp6.h:73
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
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition: uip.h:71
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:969
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:465
uint16_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:122
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:93
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Routing driver header file.
Public configuration and API declarations for ContikiRPL.
RPL DAG structure.
Definition: rpl.h:135
The data structure used to represent a multicast engine.
Definition: uip-mcast6.h:101
void(* out)(void)
Process an outgoing datagram with a multicast IPv6 destination address.
Definition: uip-mcast6.h:121
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
void(* init)(void)
Initialize the multicast engine.
Definition: uip-mcast6.h:106
Representation of a uIP UDP connection.
Definition: uip.h:1309
uip_ipaddr_t ripaddr
The IP address of the remote peer.
Definition: uip.h:1310
uint16_t rport
The remote port number in network byte order.
Definition: uip.h:1312
A set of debugging macros for the IP stack.
Header file for multicast routing table manipulation.
Header file for IPv6 multicast forwarding stats maintenance.
This header file contains configuration directives for uIPv6 multicast support.
Header file for the uIP TCP/IP stack.
The uIP packet buffer.
Definition: uip.h:457