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