Contiki-NG
Loading...
Searching...
No Matches
roll-tm.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 * \addtogroup roll-tm
34 * @{
35 */
36/**
37 * \file
38 * Implementation of the ROLL TM multicast engine
39 * \author
40 * George Oikonomou - <oikonomou@users.sourceforge.net>
41 */
42
43#include "contiki.h"
44#include "contiki-lib.h"
45#include "contiki-net.h"
46#include "net/ipv6/uip-icmp6.h"
49#include "dev/watchdog.h"
50#include <string.h>
51
52#define DEBUG DEBUG_NONE
53#include "net/ipv6/uip-debug.h"
54
55#define TRICKLE_VERBOSE 0
56
57#if DEBUG && TRICKLE_VERBOSE
58#define VERBOSE_PRINTF(...) PRINTF(__VA_ARGS__)
59#define VERBOSE_PRINT_SEED(s) PRINT_SEED(s)
60#else
61#define VERBOSE_PRINTF(...)
62#define VERBOSE_PRINT_SEED(...)
63#endif
64
65/*---------------------------------------------------------------------------*/
66/* Data Representation */
67/*---------------------------------------------------------------------------*/
68#if ROLL_TM_SHORT_SEEDS
69typedef union seed_id_u {
70 uint8_t u8[2];
71 uint16_t id; /* Big Endian */
72} seed_id_t;
73
74#define seed_is_null(s) ((s)->id == 0)
75#define PRINT_SEED(s) PRINTF("0x%02x%02x", (s)->u8[0], (s)->u8[1])
76#else /* ROLL_TM_SHORT_SEEDS */
77typedef uip_ip6addr_t seed_id_t;
78
79#define seed_is_null(s) uip_is_addr_unspecified(s)
80#define PRINT_SEED(s) PRINT6ADDR(s)
81#endif /* ROLL_TM_SHORT_SEEDS */
82#define seed_id_cmp(a, b) (memcmp((a), (b), sizeof(seed_id_t)) == 0)
83#define seed_id_cpy(a, b) (memcpy((a), (b), sizeof(seed_id_t)))
84
85/* Trickle Timers */
86struct trickle_param {
87 clock_time_t i_min; /* Clock ticks */
88 clock_time_t t_start; /* Start of the interval (absolute clock_time) */
89 clock_time_t t_end; /* End of the interval (absolute clock_time) */
90 clock_time_t t_next; /* Clock ticks, randomised in [I/2, I) */
91 clock_time_t t_last_trigger;
92 struct ctimer ct;
93 uint8_t i_current; /* Current doublings from i_min */
94 uint8_t i_max; /* Max number of doublings */
95 uint8_t k; /* Redundancy Constant */
96 uint8_t t_active; /* Units of Imax */
97 uint8_t t_dwell; /* Units of Imax */
98 uint8_t c; /* Consistency Counter */
99 uint8_t inconsistency;
100};
101
102/**
103 * \brief Convert a timer to a sane clock_time_t value after d doublings
104 * m is a value of Imin, d is a number of doublings
105 * Careful of overflows
106 */
107#define TRICKLE_TIME(m, d) ((clock_time_t)((m) << (d)))
108
109/**
110 * \brief Convert Imax from number of doublings to clock_time_t units for
111 * trickle_param t. Again, watch out for overflows */
112#define TRICKLE_IMAX(t) ((uint32_t)((t)->i_min << (t)->i_max))
113
114/**
115 * \brief Convert Tactive for a trickle timer to a sane clock_time_t value
116 * t is a pointer to the timer
117 * Careful of overflows
118 */
119#define TRICKLE_ACTIVE(t) ((uint32_t)(TRICKLE_IMAX(t) * t->t_active))
120
121/**
122 * \brief Convert Tdwell for a trickle timer to a sane clock_time_t value
123 * t is a pointer to the timer
124 * Careful of overflows
125 */
126#define TRICKLE_DWELL(t) ((uint32_t)(TRICKLE_IMAX(t) * t->t_dwell))
127
128/**
129 * \brief Check if suppression is enabled for trickle_param t
130 * t is a pointer to the timer
131 */
132#define SUPPRESSION_ENABLED(t) ((t)->k != ROLL_TM_INFINITE_REDUNDANCY)
133
134/**
135 * \brief Check if suppression is disabled for trickle_param t
136 * t is a pointer to the timer
137 */
138#define SUPPRESSION_DISABLED(t) ((t)->k == ROLL_TM_INFINITE_REDUNDANCY)
139
140/**
141 * \brief Init trickle_timer[m]
142 */
143#define TIMER_CONFIGURE(m) do { \
144 t[m].i_min = ROLL_TM_IMIN_##m; \
145 t[m].i_max = ROLL_TM_IMAX_##m; \
146 t[m].k = ROLL_TM_K_##m; \
147 t[m].t_active = ROLL_TM_T_ACTIVE_##m; \
148 t[m].t_dwell = ROLL_TM_T_DWELL_##m; \
149 t[m].t_last_trigger = clock_time(); \
150} while(0)
151/*---------------------------------------------------------------------------*/
152/* Sequence Values and Serial Number Arithmetic
153 *
154 * Sequence Number Comparisons as per RFC1982 "Serial Number Arithmetic"
155 * Our 'SERIAL_BITS' value is 15 here
156 *
157 * NOTE: There can be pairs of sequence numbers s1 and s2 with an undefined
158 * ordering. All three macros would evaluate as 0, as in:
159 * SEQ_VAL_IS_EQUAL(s1, s2) == 0 and
160 * SEQ_VAL_IS_GT(s1, s2) == 0 and
161 * SEQ_VAL_IS_LT(s1, s2) == 0
162 *
163 * This is not a bug of this implementation, it's an RFC design choice
164 */
165
166/**
167 * \brief s1 is said to be equal s2 iif SEQ_VAL_IS_EQ(s1, s2) == 1
168 */
169#define SEQ_VAL_IS_EQ(i1, i2) ((i1) == (i2))
170
171/**
172 * \brief s1 is said to be less than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
173 */
174#define SEQ_VAL_IS_LT(i1, i2) \
175 ( \
176 ((i1) != (i2)) && \
177 ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) < 0x4000)) || \
178 (((i1) > (i2)) && ((int16_t)((i1) - (i2)) > 0x4000))) \
179 )
180
181/**
182 * \brief s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
183 */
184#define SEQ_VAL_IS_GT(i1, i2) \
185( \
186 ((i1) != (i2)) && \
187 ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) > 0x4000)) || \
188 (((i1) > (i2)) && ((int16_t)((i1) - (i2)) < 0x4000))) \
189)
190
191/**
192 * \brief Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000)
193 */
194#define SEQ_VAL_ADD(s, n) (((s) + (n)) % 0x8000)
195/*---------------------------------------------------------------------------*/
196/* Sliding Windows */
197struct sliding_window {
198 seed_id_t seed_id;
199 int16_t lower_bound; /* lolipop */
200 int16_t upper_bound; /* lolipop */
201 int16_t min_listed; /* lolipop */
202 uint8_t flags; /* Is used, Trickle param, Is listed */
203 uint8_t count;
204};
205
206#define SLIDING_WINDOW_U_BIT 0x80 /* Is used */
207#define SLIDING_WINDOW_M_BIT 0x40 /* Window trickle parametrization */
208#define SLIDING_WINDOW_L_BIT 0x20 /* Current ICMP message lists us */
209#define SLIDING_WINDOW_B_BIT 0x10 /* Used when updating bounds */
210
211/**
212 * \brief Is Occupied sliding window location w
213 * w: pointer to a sliding window
214 */
215#define SLIDING_WINDOW_IS_USED(w) ((w)->flags & SLIDING_WINDOW_U_BIT)
216
217/**
218 * \brief Set 'Is Used' bit for window w
219 * w: pointer to a sliding window
220 */
221#define SLIDING_WINDOW_IS_USED_SET(w) ((w)->flags |= SLIDING_WINDOW_U_BIT)
222
223/**
224 * \brief Clear 'Is Used' bit for window w
225 * w: pointer to a sliding window
226 */
227#define SLIDING_WINDOW_IS_USED_CLR(w) ((w)->flags &= ~SLIDING_WINDOW_U_BIT)
228#define window_free(w) SLIDING_WINDOW_IS_USED_CLR(w)
229
230/**
231 * \brief Set 'Is Seen' bit for window w
232 * w: pointer to a sliding window
233 */
234#define SLIDING_WINDOW_LISTED_SET(w) ((w)->flags |= SLIDING_WINDOW_L_BIT)
235
236/**
237 * \brief Clear 'Is Seen' bit for window w
238 * w: pointer to a sliding window
239 */
240#define SLIDING_WINDOW_LISTED_CLR(w) ((w)->flags &= ~SLIDING_WINDOW_L_BIT)
241
242/**
243 * \brief Is the sliding window at location w listed in current ICMP message?
244 * w: pointer to a sliding window
245 */
246#define SLIDING_WINDOW_IS_LISTED(w) ((w)->flags & SLIDING_WINDOW_L_BIT)
247
248/**
249 * \brief Set M bit for window w
250 * w: pointer to a sliding window
251 */
252#define SLIDING_WINDOW_M_SET(w) ((w)->flags |= SLIDING_WINDOW_M_BIT)
253
254/**
255 * \brief Clear M bit for window w
256 * w: pointer to a sliding window
257 */
258#define SLIDING_WINDOW_M_CLR(w) ((w)->flags &= ~SLIDING_WINDOW_M_BIT)
259
260/**
261 * \brief Retrieve trickle parametrization for sliding window at location w
262 * w: pointer to a sliding window
263 */
264#define SLIDING_WINDOW_GET_M(w) \
265 ((uint8_t)(((w)->flags & SLIDING_WINDOW_M_BIT) == SLIDING_WINDOW_M_BIT))
266/*---------------------------------------------------------------------------*/
267/* Multicast Packet Buffers */
268struct mcast_packet {
269#if ROLL_TM_SHORT_SEEDS
270 /* Short seeds are stored inside the message */
271 seed_id_t seed_id;
272#endif
273 uint32_t active; /* Starts at 0 and increments */
274 uint32_t dwell; /* Starts at 0 and increments */
275 uint16_t buff_len;
276 uint16_t seq_val; /* host-byte order */
277 struct sliding_window *sw; /* Pointer to the SW this packet belongs to */
278 uint8_t flags; /* Is-Used, Must Send, Is Listed */
279 uint8_t buff[UIP_BUFSIZE];
280};
281
282/* Flag bits */
283#define MCAST_PACKET_U_BIT 0x80 /* Is Used */
284#define MCAST_PACKET_S_BIT 0x20 /* Must Send Next Pass */
285#define MCAST_PACKET_L_BIT 0x10 /* Is listed in ICMP message */
286
287/* Fetch a pointer to the Seed ID of a buffered message p */
288#if ROLL_TM_SHORT_SEEDS
289#define MCAST_PACKET_GET_SEED(p) ((seed_id_t *)&((p)->seed_id))
290#else
291#define MCAST_PACKET_GET_SEED(p) \
292 ((seed_id_t *)&((struct uip_ip_hdr *)&(p)->buff[0])->srcipaddr)
293#endif
294
295/**
296 * \brief Get the TTL of a buffered packet
297 * p: pointer to a packet buffer
298 */
299#define MCAST_PACKET_TTL(p) \
300 (((struct uip_ip_hdr *)(p)->buff)->ttl)
301
302/**
303 * \brief Set 'Is Used' bit for packet p
304 * p: pointer to a packet buffer
305 */
306#define MCAST_PACKET_USED_SET(p) ((p)->flags |= MCAST_PACKET_U_BIT)
307
308/**
309 * \brief Clear 'Is Used' bit for packet p
310 * p: pointer to a packet buffer
311 */
312#define MCAST_PACKET_USED_CLR(p) ((p)->flags &= ~MCAST_PACKET_U_BIT)
313
314/**
315 * \brief Is Occupied buffer location p
316 */
317#define MCAST_PACKET_IS_USED(p) ((p)->flags & MCAST_PACKET_U_BIT)
318
319/**
320 * \brief Must we send this message this pass?
321 */
322#define MCAST_PACKET_MUST_SEND(p) ((p)->flags & MCAST_PACKET_S_BIT)
323
324/**
325 * \brief Set 'Must Send' bit for message p
326 * p: pointer to a struct mcast_packet
327 */
328#define MCAST_PACKET_SEND_SET(p) ((p)->flags |= MCAST_PACKET_S_BIT)
329
330/**
331 * \brief Clear 'Must Send' bit for message p
332 * p: pointer to a struct mcast_packet
333 */
334#define MCAST_PACKET_SEND_CLR(p) ((p)->flags &= ~MCAST_PACKET_S_BIT)
335
336/**
337 * \brief Is the message p listed in current ICMP message?
338 * p: pointer to a struct mcast_packet
339 */
340#define MCAST_PACKET_IS_LISTED(p) ((p)->flags & MCAST_PACKET_L_BIT)
341
342/**
343 * \brief Set 'Is Listed' bit for message p
344 * p: pointer to a struct mcast_packet
345 */
346#define MCAST_PACKET_LISTED_SET(p) ((p)->flags |= MCAST_PACKET_L_BIT)
347
348/**
349 * \brief Clear 'Is Listed' bit for message p
350 * p: pointer to a struct mcast_packet
351 */
352#define MCAST_PACKET_LISTED_CLR(p) ((p)->flags &= ~MCAST_PACKET_L_BIT)
353
354/**
355 * \brief Free a multicast packet buffer
356 * p: pointer to a struct mcast_packet
357 */
358#define MCAST_PACKET_FREE(p) ((p)->flags = 0)
359/*---------------------------------------------------------------------------*/
360/* Sequence Lists in Multicast Trickle ICMP messages */
361struct sequence_list_header {
362 uint8_t flags; /* S: Seed ID length, M: Trickle parametrization */
363 uint8_t seq_len;
364 seed_id_t seed_id;
365};
366
367#define SEQUENCE_LIST_S_BIT 0x80
368#define SEQUENCE_LIST_M_BIT 0x40
369#define SEQUENCE_LIST_RES 0x3F
370
371/**
372 * \brief Get the Trickle Parametrization for an ICMPv6 sequence list
373 * l: pointer to a sequence list structure
374 */
375#define SEQUENCE_LIST_GET_M(l) \
376 ((uint8_t)(((l)->flags & SEQUENCE_LIST_M_BIT) == SEQUENCE_LIST_M_BIT))
377
378/**
379 * \brief Get the Seed ID Length for an ICMPv6 sequence list
380 * l: pointer to a sequence list structure
381 */
382#define SEQUENCE_LIST_GET_S(l) \
383 ((uint8_t)(((l)->flags & SEQUENCE_LIST_S_BIT) == SEQUENCE_LIST_S_BIT))
384/*---------------------------------------------------------------------------*/
385/* Trickle Multicast HBH Option */
386struct hbho_mcast {
387 uint8_t type;
388 uint8_t len;
389#if ROLL_TM_SHORT_SEEDS
390 seed_id_t seed_id;
391#endif
392 uint8_t flags; /* M, Seq ID MSB */
393 uint8_t seq_id_lsb;
394#if !ROLL_TM_SHORT_SEEDS
395 /* Need to Pad to 8 bytes with PadN */
396 uint8_t padn_type; /* 1: PadN */
397 uint8_t padn_len; /* 0->2 bytes */
398#endif
399};
400
401#define HBHO_OPT_TYPE_TRICKLE 0x0C
402#define HBHO_LEN_LONG_SEED 2
403#define HBHO_LEN_SHORT_SEED 4
404#define HBHO_TOTAL_LEN 8
405/**
406 * \brief Get the Trickle Parametrization for a multicast HBHO header
407 * m: pointer to the HBHO header
408 */
409#define HBH_GET_M(h) (((h)->flags & 0x80) == 0x80)
410
411/**
412 * \brief Set the Trickle Parametrization bit for a multicast HBHO header
413 * m: pointer to the HBHO header
414 */
415#define HBH_SET_M(h) ((h)->flags |= 0x80)
416
417/**
418 * \brief Retrieve the Sequence Value MSB from a multicast HBHO header
419 * m: pointer to the HBHO header
420 */
421#define HBH_GET_SV_MSB(h) ((h)->flags & 0x7F)
422/*---------------------------------------------------------------------------*/
423/* Destination for our ICMPv6 datagrams */
424#if ROLL_TM_CONF_DEST_ALL_NODES
425#define roll_tm_create_dest(a) uip_create_linklocal_allnodes_mcast(a)
426#else
427#define roll_tm_create_dest(a) uip_create_linklocal_allrouters_mcast(a)
428#endif
429/*---------------------------------------------------------------------------*/
430/* Maintain Stats */
431#if UIP_MCAST6_STATS
432static struct roll_tm_stats stats;
433
434#define ROLL_TM_STATS_ADD(x) stats.x++
435#define ROLL_TM_STATS_INIT() do { memset(&stats, 0, sizeof(stats)); } while(0)
436#else /* UIP_MCAST6_STATS */
437#define ROLL_TM_STATS_ADD(x)
438#define ROLL_TM_STATS_INIT()
439#endif
440/*---------------------------------------------------------------------------*/
441/* Internal Data Structures */
442/*---------------------------------------------------------------------------*/
443static struct trickle_param t[2];
444static struct sliding_window windows[ROLL_TM_WINS];
445static struct mcast_packet buffered_msgs[ROLL_TM_BUFF_NUM];
446/*---------------------------------------------------------------------------*/
447/* Temporary Stores */
448/*---------------------------------------------------------------------------*/
449static struct trickle_param *loctpptr;
450static struct sequence_list_header *locslhptr;
451static struct sliding_window *locswptr;
452static struct sliding_window *iterswptr;
453static struct mcast_packet *locmpptr;
454static struct hbho_mcast *lochbhmptr;
455static uint16_t last_seq;
456/*---------------------------------------------------------------------------*/
457/* uIPv6 Pointers */
458/*---------------------------------------------------------------------------*/
459#define UIP_EXT_BUF ((struct uip_ext_hdr *)UIP_IP_PAYLOAD(0))
460#define UIP_EXT_BUF_NEXT ((uint8_t *)(UIP_IP_PAYLOAD(HBHO_TOTAL_LEN)))
461#define UIP_EXT_OPT_FIRST ((struct hbho_mcast *)(UIP_IP_PAYLOAD(0) + 2))
462extern uint16_t uip_slen;
463/*---------------------------------------------------------------------------*/
464/* Local function prototypes */
465/*---------------------------------------------------------------------------*/
466static void icmp_input(void);
467static void icmp_output(void);
468static void window_update_bounds(void);
469static void reset_trickle_timer(uint8_t);
470static void handle_timer(void *);
471/*---------------------------------------------------------------------------*/
472/* ROLL TM ICMPv6 handler declaration */
473UIP_ICMP6_HANDLER(roll_tm_icmp_handler, ICMP6_ROLL_TM,
474 UIP_ICMP6_HANDLER_CODE_ANY, icmp_input);
475/*---------------------------------------------------------------------------*/
476/* Return a random number in [I/2, I), for a timer with Imin when the timer's
477 * current number of doublings is d */
478static clock_time_t
479random_interval(clock_time_t i_min, uint8_t d)
480{
481 clock_time_t min = TRICKLE_TIME(i_min >> 1, d);
482
483 VERBOSE_PRINTF("ROLL TM: Random [%lu, %lu)\n", (unsigned long)min,
484 (unsigned long)(TRICKLE_TIME(i_min, d)));
485
486 return min + (random_rand() % (TRICKLE_TIME(i_min, d) - 1 - min));
487}
488/*---------------------------------------------------------------------------*/
489/* Called at the end of the current interval for timer ptr */
490static void
491double_interval(void *ptr)
492{
493 struct trickle_param *param = (struct trickle_param *)ptr;
494 int16_t offset;
495 clock_time_t next;
496
497 /*
498 * If we got called long past our expiration, store the offset and try to
499 * compensate this period
500 */
501 offset = (int16_t)(clock_time() - param->t_end);
502
503 /* Calculate next interval */
504 if(param->i_current < param->i_max) {
505 param->i_current++;
506 }
507
508 param->t_start = param->t_end;
509 param->t_end = param->t_start + (param->i_min << param->i_current);
510
511 next = random_interval(param->i_min, param->i_current);
512 if(next > offset) {
513 next -= offset;
514 } else {
515 next = 0;
516 }
517 param->t_next = next;
518 ctimer_set(&param->ct, param->t_next, handle_timer, (void *)param);
519
520 VERBOSE_PRINTF("ROLL TM: Doubling at %lu (offset %d), Start %lu, End %lu,"
521 " Periodic in %lu\n", clock_time(), offset,
522 (unsigned long)param->t_start,
523 (unsigned long)param->t_end, (unsigned long)param->t_next);
524}
525/*---------------------------------------------------------------------------*/
526/*
527 * Called at a random point in [I/2,I) of the current interval for ptr
528 * PARAM is a pointer to the timer that triggered the callback (&t[index])
529 */
530static void
531handle_timer(void *ptr)
532{
533 struct trickle_param *param;
534 clock_time_t diff_last; /* Time diff from last pass */
535 clock_time_t diff_start; /* Time diff from interval start */
536 uint8_t m;
537
538 param = (struct trickle_param *)ptr;
539 if(param == &t[0]) {
540 m = 0;
541 } else if(param == &t[1]) {
542 m = 1;
543 } else {
544 /* This is an ooops and a serious one too */
545 return;
546 }
547
548 /* Bail out pronto if our uIPv6 stack is not ready to send messages */
549 if(uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) {
550 VERBOSE_PRINTF
551 ("ROLL TM: Suppressing timer processing. Stack not ready\n");
552 reset_trickle_timer(m);
553 return;
554 }
555
556 VERBOSE_PRINTF("ROLL TM: M=%u Periodic at %lu, last=%lu\n",
557 m, (unsigned long)clock_time(),
558 (unsigned long)param->t_last_trigger);
559
560 /* Temporarily store 'now' in t_next and calculate diffs */
561 param->t_next = clock_time();
562 diff_last = param->t_next - param->t_last_trigger;
563 diff_start = param->t_next - param->t_start;
564 param->t_last_trigger = param->t_next;
565
566 VERBOSE_PRINTF
567 ("ROLL TM: M=%u Periodic diff from last %lu, from start %lu\n", m,
568 (unsigned long)diff_last, (unsigned long)diff_start);
569
570 /* Handle all buffered messages */
571 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
572 locmpptr >= buffered_msgs; locmpptr--) {
573 if(MCAST_PACKET_IS_USED(locmpptr)
574 && (SLIDING_WINDOW_GET_M(locmpptr->sw) == m)) {
575
576 /*
577 * if()
578 * If the packet was received during the last interval, its reception
579 * caused an inconsistency (and thus a timer reset). This means that
580 * the packet was received at about t_start, we increment by diff_start
581 *
582 * else()
583 * If the packet was not received during the last window, it is safe to
584 * increase its lifetime counters by the time diff from last pass
585 *
586 * if active == dwell == 0 but i_current != 0, this is an oops
587 * (new packet that didn't reset us). We don't handle it
588 */
589 if(locmpptr->active == 0) {
590 locmpptr->active += diff_start;
591 locmpptr->dwell += diff_start;
592 } else {
593 locmpptr->active += diff_last;
594 locmpptr->dwell += diff_last;
595 }
596
597 VERBOSE_PRINTF("ROLL TM: M=%u Packet %u active %lu of %lu\n",
598 m, locmpptr->seq_val, locmpptr->active,
599 TRICKLE_ACTIVE(param));
600
601 if(locmpptr->dwell > TRICKLE_DWELL(param)) {
602 locmpptr->sw->count--;
603 PRINTF("ROLL TM: M=%u Free Packet %u (%lu > %lu), Window now at %u\n",
604 m, locmpptr->seq_val, locmpptr->dwell,
605 TRICKLE_DWELL(param), locmpptr->sw->count);
606 if(locmpptr->sw->count == 0) {
607 PRINTF("ROLL TM: M=%u Free Window ", m);
608 PRINT_SEED(&locmpptr->sw->seed_id);
609 PRINTF("\n");
610 window_free(locmpptr->sw);
611 }
612 MCAST_PACKET_FREE(locmpptr);
613 } else if(MCAST_PACKET_TTL(locmpptr) > 0) {
614 /* Handle multicast transmissions */
615 if(locmpptr->active < TRICKLE_ACTIVE(param) &&
616 ((SUPPRESSION_ENABLED(param) && MCAST_PACKET_MUST_SEND(locmpptr)) ||
617 SUPPRESSION_DISABLED(param))) {
618 PRINTF("ROLL TM: M=%u Periodic - Sending packet from Seed ", m);
619 PRINT_SEED(&locmpptr->sw->seed_id);
620 PRINTF(" seq %u\n", locmpptr->seq_val);
621 uip_len = locmpptr->buff_len;
622 memcpy(UIP_IP_BUF, &locmpptr->buff, uip_len);
623
624 UIP_MCAST6_STATS_ADD(mcast_fwd);
625 tcpip_output(NULL);
626 MCAST_PACKET_SEND_CLR(locmpptr);
628 }
629 }
630 }
631 }
632
633 /* Suppression Enabled - Send an ICMP */
634 if(SUPPRESSION_ENABLED(param)) {
635 if(param->c < param->k) {
636 icmp_output();
637 }
638 }
639
640 /* Done handling inconsistencies for this timer */
641 param->inconsistency = 0;
642 param->c = 0;
643
644 window_update_bounds();
645
646 /* Temporarily store 'now' in t_next */
647 param->t_next = clock_time();
648 if(param->t_next >= param->t_end) {
649 /* took us too long to process things, double interval asap */
650 param->t_next = 0;
651 } else {
652 param->t_next = param->t_end - param->t_next;
653 }
654 VERBOSE_PRINTF
655 ("ROLL TM: M=%u Periodic at %lu, Interval End at %lu in %lu\n", m,
656 (unsigned long)clock_time(), (unsigned long)param->t_end,
657 (unsigned long)param->t_next);
658 ctimer_set(&param->ct, param->t_next, double_interval, (void *)param);
659
660 return;
661}
662/*---------------------------------------------------------------------------*/
663static void
664reset_trickle_timer(uint8_t index)
665{
666 t[index].t_start = clock_time();
667 t[index].t_end = t[index].t_start + (t[index].i_min);
668 t[index].i_current = 0;
669 t[index].c = 0;
670 t[index].t_next = random_interval(t[index].i_min, t[index].i_current);
671
672 VERBOSE_PRINTF
673 ("ROLL TM: M=%u Reset at %lu, Start %lu, End %lu, New Interval %lu\n",
674 index, (unsigned long)t[index].t_start, (unsigned long)t[index].t_start,
675 (unsigned long)t[index].t_end, (unsigned long)t[index].t_next);
676
677 ctimer_set(&t[index].ct, t[index].t_next, handle_timer, (void *)&t[index]);
678}
679/*---------------------------------------------------------------------------*/
680static struct sliding_window *
681window_allocate()
682{
683 for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
684 iterswptr--) {
685 if(!SLIDING_WINDOW_IS_USED(iterswptr)) {
686 iterswptr->count = 0;
687 iterswptr->lower_bound = -1;
688 iterswptr->upper_bound = -1;
689 iterswptr->min_listed = -1;
690 return iterswptr;
691 }
692 }
693 return NULL;
694}
695/*---------------------------------------------------------------------------*/
696static struct sliding_window *
697window_lookup(seed_id_t *s, uint8_t m)
698{
699 for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
700 iterswptr--) {
701 VERBOSE_PRINTF("ROLL TM: M=%u (%u) ", SLIDING_WINDOW_GET_M(iterswptr), m);
702 VERBOSE_PRINT_SEED(&iterswptr->seed_id);
703 VERBOSE_PRINTF("\n");
704 if(seed_id_cmp(s, &iterswptr->seed_id) &&
705 SLIDING_WINDOW_GET_M(iterswptr) == m) {
706 return iterswptr;
707 }
708 }
709 return NULL;
710}
711/*---------------------------------------------------------------------------*/
712static void
713window_update_bounds()
714{
715 for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
716 iterswptr--) {
717 iterswptr->lower_bound = -1;
718 }
719
720 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
721 locmpptr >= buffered_msgs; locmpptr--) {
722 if(MCAST_PACKET_IS_USED(locmpptr)) {
723 iterswptr = locmpptr->sw;
724 VERBOSE_PRINTF("ROLL TM: Update Bounds: [%d - %d] vs %u\n",
725 iterswptr->lower_bound, iterswptr->upper_bound,
726 locmpptr->seq_val);
727 if(iterswptr->lower_bound < 0
728 || SEQ_VAL_IS_LT(locmpptr->seq_val, iterswptr->lower_bound)) {
729 iterswptr->lower_bound = locmpptr->seq_val;
730 }
731 if(iterswptr->upper_bound < 0 ||
732 SEQ_VAL_IS_GT(locmpptr->seq_val, iterswptr->upper_bound)) {
733 iterswptr->upper_bound = locmpptr->seq_val;
734 }
735 }
736 }
737}
738/*---------------------------------------------------------------------------*/
739static struct mcast_packet *
740buffer_reclaim()
741{
742 struct sliding_window *largest = windows;
743 struct mcast_packet *rv;
744
745 for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
746 iterswptr--) {
747 if(iterswptr->count > largest->count) {
748 largest = iterswptr;
749 }
750 }
751
752 if(largest->count == 1) {
753 /* Can't reclaim last entry for a window and this is the largest window */
754 return NULL;
755 }
756
757 PRINTF("ROLL TM: Reclaim from Seed ");
758 PRINT_SEED(&largest->seed_id);
759 PRINTF(" M=%u, count was %u\n",
760 SLIDING_WINDOW_GET_M(largest), largest->count);
761 /* Find the packet at the lowest bound for the largest window */
762 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
763 locmpptr >= buffered_msgs; locmpptr--) {
764 if(MCAST_PACKET_IS_USED(locmpptr) && (locmpptr->sw == largest) &&
765 SEQ_VAL_IS_EQ(locmpptr->seq_val, largest->lower_bound)) {
766 rv = locmpptr;
767 PRINTF("ROLL TM: Reclaim seq. val %u\n", locmpptr->seq_val);
769 largest->count--;
770 window_update_bounds();
771 VERBOSE_PRINTF("ROLL TM: Reclaim - new bounds [%u , %u]\n",
772 largest->lower_bound, largest->upper_bound);
773 return rv;
774 }
775 }
776
777 /* oops */
778 return NULL;
779}
780/*---------------------------------------------------------------------------*/
781static struct mcast_packet *
782buffer_allocate()
783{
784 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
785 locmpptr >= buffered_msgs; locmpptr--) {
786 if(!MCAST_PACKET_IS_USED(locmpptr)) {
787 return locmpptr;
788 }
789 }
790 return NULL;
791}
792/*---------------------------------------------------------------------------*/
793static void
794icmp_output()
795{
796 struct sequence_list_header *sl;
797 uint8_t *buffer;
798 uint16_t payload_len;
799
800 PRINTF("ROLL TM: ICMPv6 Out\n");
801
802 UIP_IP_BUF->vtc = 0x60;
803 UIP_IP_BUF->tcflow = 0;
804 UIP_IP_BUF->flow = 0;
805 UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
807
808 sl = (struct sequence_list_header *)UIP_ICMP_PAYLOAD;
809 payload_len = 0;
810
811 VERBOSE_PRINTF("ROLL TM: ICMPv6 Out - Hdr @ %p, payload @ %p\n", UIP_ICMP_BUF, sl);
812
813 for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
814 iterswptr--) {
815 if(SLIDING_WINDOW_IS_USED(iterswptr) && iterswptr->count > 0) {
816 memset(sl, 0, sizeof(struct sequence_list_header));
817#if ROLL_TM_SHORT_SEEDS
818 sl->flags = SEQUENCE_LIST_S_BIT;
819#endif
820 if(SLIDING_WINDOW_GET_M(iterswptr)) {
821 sl->flags |= SEQUENCE_LIST_M_BIT;
822 }
823 seed_id_cpy(&sl->seed_id, &iterswptr->seed_id);
824
825 PRINTF("ROLL TM: ICMPv6 Out - Seq. F=0x%02x, Seed ID=", sl->flags);
826 PRINT_SEED(&sl->seed_id);
827
828 buffer = (uint8_t *)sl + sizeof(struct sequence_list_header);
829
830 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
831 locmpptr >= buffered_msgs; locmpptr--) {
832 if(MCAST_PACKET_IS_USED(locmpptr) &&
833 locmpptr->active < TRICKLE_ACTIVE((&t[SLIDING_WINDOW_GET_M(iterswptr)]))) {
834 if(locmpptr->sw == iterswptr) {
835 sl->seq_len++;
836 PRINTF(", %u", locmpptr->seq_val);
837 *buffer = (uint8_t)(locmpptr->seq_val >> 8);
838 buffer++;
839 *buffer = (uint8_t)(locmpptr->seq_val & 0xFF);
840 buffer++;
841 }
842 }
843 }
844 PRINTF(", Len=%u\n", sl->seq_len);
845
846 /* Scrap the entire window if it has no content */
847 if(sl->seq_len > 0) {
848 payload_len += sizeof(struct sequence_list_header) + sl->seq_len * 2;
849 sl = (struct sequence_list_header *)buffer;
850 }
851 }
852 }
853
854 if(payload_len == 0) {
855 VERBOSE_PRINTF("ROLL TM: ICMPv6 Out - nothing to send\n");
856 return;
857 }
858
859 roll_tm_create_dest(&UIP_IP_BUF->destipaddr);
860 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
861
862 uipbuf_set_len_field(UIP_IP_BUF, UIP_ICMPH_LEN + payload_len);
863
866
867 UIP_ICMP_BUF->icmpchksum = 0;
868 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
869
870 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
871
872 VERBOSE_PRINTF("ROLL TM: ICMPv6 Out - %u bytes\n", payload_len);
873
875 ROLL_TM_STATS_ADD(icmp_out);
876 return;
877}
878/*---------------------------------------------------------------------------*/
879/**
880 * \brief Processes an incoming or outgoing multicast message and determines
881 * whether it should be dropped or accepted
882 *
883 * \param in 1: Incoming packet, 0: Outgoing (we are the seed)
884 *
885 * \return 0: Drop, 1: Accept
886 */
887static uint8_t
888accept(uint8_t in)
889{
890 seed_id_t *seed_ptr;
891 uint8_t m;
892 uint16_t seq_val;
893
894 PRINTF("ROLL TM: Multicast I/O\n");
895
896#if UIP_CONF_IPV6_CHECKS
898 PRINTF("ROLL TM: Mcast I/O, bad destination\n");
899 UIP_MCAST6_STATS_ADD(mcast_bad);
900 return UIP_MCAST6_DROP;
901 }
902 /*
903 * Abort transmission if the v6 src is unspecified. This may happen if the
904 * seed tries to TX while it's still performing DAD or waiting for a prefix
905 */
906 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
907 PRINTF("ROLL TM: Mcast I/O, bad source\n");
908 UIP_MCAST6_STATS_ADD(mcast_bad);
909 return UIP_MCAST6_DROP;
910 }
911#endif
912
913 /* Check the Next Header field: Must be HBHO */
914 if(UIP_IP_BUF->proto != UIP_PROTO_HBHO) {
915 PRINTF("ROLL TM: Mcast I/O, bad proto\n");
916 UIP_MCAST6_STATS_ADD(mcast_bad);
917 return UIP_MCAST6_DROP;
918 } else {
919 /* Check the Option Type */
920 if(UIP_EXT_OPT_FIRST->type != HBHO_OPT_TYPE_TRICKLE) {
921 PRINTF("ROLL TM: Mcast I/O, bad HBHO type\n");
922 UIP_MCAST6_STATS_ADD(mcast_bad);
923 return UIP_MCAST6_DROP;
924 }
925 }
926 lochbhmptr = UIP_EXT_OPT_FIRST;
927
928 PRINTF("ROLL TM: HBHO T=%u, L=%u, M=%u, S=0x%02x%02x\n",
929 lochbhmptr->type, lochbhmptr->len, HBH_GET_M(lochbhmptr),
930 HBH_GET_SV_MSB(lochbhmptr), lochbhmptr->seq_id_lsb);
931
932 /* Drop unsupported Seed ID Lengths. S bit: 0->short, 1->long */
933#if ROLL_TM_SHORT_SEEDS
934 /* Short Seed ID: Len MUST be 4 */
935 if(lochbhmptr->len != HBHO_LEN_SHORT_SEED) {
936 PRINTF("ROLL TM: Mcast I/O, bad length\n");
937 UIP_MCAST6_STATS_ADD(mcast_bad);
938 return UIP_MCAST6_DROP;
939 }
940#else
941 /* Long Seed ID: Len MUST be 2 (Seed ID is elided) */
942 if(lochbhmptr->len != HBHO_LEN_LONG_SEED) {
943 PRINTF("ROLL TM: Mcast I/O, bad length\n");
944 UIP_MCAST6_STATS_ADD(mcast_bad);
945 return UIP_MCAST6_DROP;
946 }
947#endif
948
949#if UIP_MCAST6_STATS
950 if(in == ROLL_TM_DGRAM_IN) {
951 UIP_MCAST6_STATS_ADD(mcast_in_all);
952 }
953#endif
954
955 /* Is this for a known window? */
956#if ROLL_TM_SHORT_SEEDS
957 seed_ptr = &lochbhmptr->seed_id;
958#else
959 seed_ptr = &UIP_IP_BUF->srcipaddr;
960#endif
961 m = HBH_GET_M(lochbhmptr);
962
963 locswptr = window_lookup(seed_ptr, m);
964
965 seq_val = lochbhmptr->seq_id_lsb;
966 seq_val |= HBH_GET_SV_MSB(lochbhmptr) << 8;
967
968 if(locswptr) {
969 if(SEQ_VAL_IS_LT(seq_val, locswptr->lower_bound)) {
970 /* Too old, drop */
971 PRINTF("ROLL TM: Too old\n");
972 UIP_MCAST6_STATS_ADD(mcast_dropped);
973 return UIP_MCAST6_DROP;
974 }
975 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
976 locmpptr >= buffered_msgs; locmpptr--) {
977 if(MCAST_PACKET_IS_USED(locmpptr) &&
978 locmpptr->sw == locswptr &&
979 SLIDING_WINDOW_GET_M(locmpptr->sw) == m &&
980 SEQ_VAL_IS_EQ(seq_val, locmpptr->seq_val)) {
981 /* Seen before , drop */
982 PRINTF("ROLL TM: Seen before\n");
983 UIP_MCAST6_STATS_ADD(mcast_dropped);
984 return UIP_MCAST6_DROP;
985 }
986 }
987 }
988
989 PRINTF("ROLL TM: New message\n");
990
991 /* We have not seen this message before */
992 /* Allocate a window if we have to */
993 if(!locswptr) {
994 locswptr = window_allocate();
995 PRINTF("ROLL TM: New seed\n");
996 }
997 if(!locswptr) {
998 /* Couldn't allocate window, drop */
999 PRINTF("ROLL TM: Failed to allocate window\n");
1000 UIP_MCAST6_STATS_ADD(mcast_dropped);
1001 return UIP_MCAST6_DROP;
1002 }
1003
1004 /* Allocate a buffer */
1005 locmpptr = buffer_allocate();
1006 if(!locmpptr) {
1007 PRINTF("ROLL TM: Buffer allocation failed, reclaiming\n");
1008 locmpptr = buffer_reclaim();
1009 }
1010
1011 if(!locmpptr) {
1012 /* Failed to allocate / reclaim a buffer. If the window has only just been
1013 * allocated, free it before dropping */
1014 PRINTF("ROLL TM: Buffer reclaim failed\n");
1015 if(locswptr->count == 0) {
1016 window_free(locswptr);
1017 UIP_MCAST6_STATS_ADD(mcast_dropped);
1018 return UIP_MCAST6_DROP;
1019 }
1020 }
1021#if UIP_MCAST6_STATS
1022 if(in == ROLL_TM_DGRAM_IN) {
1023 UIP_MCAST6_STATS_ADD(mcast_in_unique);
1024 }
1025#endif
1026
1027 /* We have a window and we have a buffer. Accept this message */
1028 /* Set the seed ID and correct M for this window */
1029 SLIDING_WINDOW_M_CLR(locswptr);
1030 if(m) {
1031 SLIDING_WINDOW_M_SET(locswptr);
1032 }
1034 seed_id_cpy(&locswptr->seed_id, seed_ptr);
1035 PRINTF("ROLL TM: Window for seed ");
1036 PRINT_SEED(&locswptr->seed_id);
1037 PRINTF(" M=%u, count=%u\n",
1038 SLIDING_WINDOW_GET_M(locswptr), locswptr->count);
1039
1040 /* If this window was previously empty, set its lower bound to this packet */
1041 if(locswptr->count == 0) {
1042 locswptr->lower_bound = seq_val;
1043 VERBOSE_PRINTF("ROLL TM: New Lower Bound %u\n", locswptr->lower_bound);
1044 }
1045
1046 /* If this is a new Seq Num, update the window upper bound */
1047 if(locswptr->count == 0 || SEQ_VAL_IS_GT(seq_val, locswptr->upper_bound)) {
1048 locswptr->upper_bound = seq_val;
1049 VERBOSE_PRINTF("ROLL TM: New Upper Bound %u\n", locswptr->upper_bound);
1050 }
1051
1052 locswptr->count++;
1053
1054 memset(locmpptr, 0, sizeof(struct mcast_packet));
1055 memcpy(&locmpptr->buff, UIP_IP_BUF, uip_len);
1056 locmpptr->sw = locswptr;
1057 locmpptr->buff_len = uip_len;
1058 locmpptr->seq_val = seq_val;
1059 MCAST_PACKET_USED_SET(locmpptr);
1060
1061 PRINTF("ROLL TM: Window for seed ");
1062 PRINT_SEED(&locswptr->seed_id);
1063 PRINTF(" M=%u, %u values within [%u , %u]\n",
1064 SLIDING_WINDOW_GET_M(locswptr), locswptr->count,
1065 locswptr->lower_bound, locswptr->upper_bound);
1066
1067 /*
1068 * If this is an incoming packet, it is inconsistent and we need to decrement
1069 * its TTL before we start forwarding it.
1070 * If on the other hand we are the seed, the caller will trigger a
1071 * transmission so we don't flag inconsistency and we leave the TTL alone
1072 */
1073 if(in == ROLL_TM_DGRAM_IN) {
1074 MCAST_PACKET_SEND_SET(locmpptr);
1075 MCAST_PACKET_TTL(locmpptr)--;
1076
1077 t[m].inconsistency = 1;
1078
1079 PRINTF("ROLL TM: Inconsistency. Reset T%u\n", m);
1080 reset_trickle_timer(m);
1081 }
1082
1083 /* Deliver if necessary */
1084 return UIP_MCAST6_ACCEPT;
1085}
1086/*---------------------------------------------------------------------------*/
1087/* ROLL TM ICMPv6 Input Handler */
1088static void
1089icmp_input()
1090{
1091 uint8_t inconsistency;
1092 uint16_t *seq_ptr;
1093 uint16_t *end_ptr;
1094 uint16_t val;
1095
1096#if UIP_CONF_IPV6_CHECKS
1097 if(!uip_is_addr_linklocal(&UIP_IP_BUF->srcipaddr)) {
1098 PRINTF("ROLL TM: ICMPv6 In, bad source ");
1099 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
1100 PRINTF(" to ");
1101 PRINT6ADDR(&UIP_IP_BUF->destipaddr);
1102 PRINTF("\n");
1103 ROLL_TM_STATS_ADD(icmp_bad);
1104 goto discard;
1105 }
1106
1109 PRINTF("ROLL TM: ICMPv6 In, bad destination\n");
1110 ROLL_TM_STATS_ADD(icmp_bad);
1111 goto discard;
1112 }
1113
1114 if(UIP_ICMP_BUF->icode != ROLL_TM_ICMP_CODE) {
1115 PRINTF("ROLL TM: ICMPv6 In, bad ICMP code\n");
1116 ROLL_TM_STATS_ADD(icmp_bad);
1117 goto discard;
1118 }
1119
1120 if(UIP_IP_BUF->ttl != ROLL_TM_IP_HOP_LIMIT) {
1121 PRINTF("ROLL TM: ICMPv6 In, bad TTL\n");
1122 ROLL_TM_STATS_ADD(icmp_bad);
1123 goto discard;
1124 }
1125#endif
1126
1127 PRINTF("ROLL TM: ICMPv6 In from ");
1128 PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
1129 PRINTF(" len %u, ext %u\n", uip_len, uip_ext_len);
1130
1131 ROLL_TM_STATS_ADD(icmp_in);
1132
1133 /* Reset Is-Listed bit for all windows */
1134 for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
1135 iterswptr--) {
1136 SLIDING_WINDOW_LISTED_CLR(iterswptr);
1137 }
1138
1139 /* Reset Is-Listed bit for all cached packets */
1140 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
1141 locmpptr >= buffered_msgs; locmpptr--) {
1142 MCAST_PACKET_LISTED_CLR(locmpptr);
1143 }
1144
1145 locslhptr = (struct sequence_list_header *)UIP_ICMP_PAYLOAD;
1146
1147 VERBOSE_PRINTF("ROLL TM: ICMPv6 In, parse from %p to %p\n",
1148 UIP_ICMP_PAYLOAD,
1149 (uint8_t *)UIP_ICMP_PAYLOAD + uip_len -
1150 uip_l3_icmp_hdr_len);
1151 while(locslhptr <
1152 (struct sequence_list_header *)((uint8_t *)UIP_ICMP_PAYLOAD +
1153 uip_len - uip_l3_icmp_hdr_len)) {
1154 VERBOSE_PRINTF("ROLL TM: ICMPv6 In, seq hdr @ %p\n", locslhptr);
1155
1156 if((locslhptr->flags & SEQUENCE_LIST_RES) != 0) {
1157 PRINTF("ROLL TM: ICMPv6 In, non-zero reserved bits\n");
1158 goto drop;
1159 }
1160
1161 /* Drop unsupported Seed ID Lengths. S bit: 0->short, 1->long */
1162#if ROLL_TM_SHORT_SEEDS
1163 if(!SEQUENCE_LIST_GET_S(locslhptr)) {
1164 ROLL_TM_STATS_ADD(icmp_bad);
1165 goto drop;
1166 }
1167#else
1168 if(SEQUENCE_LIST_GET_S(locslhptr)) {
1169 ROLL_TM_STATS_ADD(icmp_bad);
1170 goto drop;
1171 }
1172#endif
1173
1174 PRINTF("ROLL TM: ICMPv6 In, Sequence List for Seed ID ");
1175 PRINT_SEED(&locslhptr->seed_id);
1176 PRINTF(" M=%u, S=%u, Len=%u\n", SEQUENCE_LIST_GET_M(locslhptr),
1177 SEQUENCE_LIST_GET_S(locslhptr), locslhptr->seq_len);
1178
1179 seq_ptr = (uint16_t *)((uint8_t *)locslhptr
1180 + sizeof(struct sequence_list_header));
1181 end_ptr = (uint16_t *)((uint8_t *)locslhptr
1182 + sizeof(struct sequence_list_header) +
1183 locslhptr->seq_len * 2);
1184
1185 /* Fetch a pointer to the corresponding trickle timer */
1186 loctpptr = &t[SEQUENCE_LIST_GET_M(locslhptr)];
1187
1188 locswptr = NULL;
1189
1190 /* Find the sliding window for this Seed ID */
1191 locswptr = window_lookup(&locslhptr->seed_id,
1192 SEQUENCE_LIST_GET_M(locslhptr));
1193
1194 /* If we have a window, iterate sequence values and check consistency */
1195 if(locswptr) {
1196 SLIDING_WINDOW_LISTED_SET(locswptr);
1197 locswptr->min_listed = -1;
1198 PRINTF("ROLL TM: ICMPv6 In, Window bounds [%u , %u]\n",
1199 locswptr->lower_bound, locswptr->upper_bound);
1200 for(; seq_ptr < end_ptr; seq_ptr++) {
1201 /* Check for "They have new" */
1202 /* If an advertised seq. val is GT our upper bound */
1203 val = uip_htons(*seq_ptr);
1204 PRINTF("ROLL TM: ICMPv6 In, Check seq %u @ %p\n", val, seq_ptr);
1205 if(SEQ_VAL_IS_GT(val, locswptr->upper_bound)) {
1206 PRINTF("ROLL TM: Inconsistency - Advertised Seq. ID %u GT upper"
1207 " bound %u\n", val, locswptr->upper_bound);
1208 loctpptr->inconsistency = 1;
1209 }
1210
1211 /* If an advertised seq. val is within our bounds */
1212 if((SEQ_VAL_IS_LT(val, locswptr->upper_bound) ||
1213 SEQ_VAL_IS_EQ(val, locswptr->upper_bound)) &&
1214 (SEQ_VAL_IS_GT(val, locswptr->lower_bound) ||
1215 SEQ_VAL_IS_EQ(val, locswptr->lower_bound))) {
1216
1217 inconsistency = 1;
1218 /* Check if the advertised sequence is in our buffer */
1219 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
1220 locmpptr >= buffered_msgs; locmpptr--) {
1221 if(MCAST_PACKET_IS_USED(locmpptr) && locmpptr->sw == locswptr) {
1222 if(SEQ_VAL_IS_EQ(locmpptr->seq_val, val)) {
1223
1224 inconsistency = 0;
1225 MCAST_PACKET_LISTED_SET(locmpptr);
1226 PRINTF("ROLL TM: ICMPv6 In, %u listed\n", locmpptr->seq_val);
1227
1228 /* Update lowest seq. num listed for this window
1229 * We need this to check for "we have new" */
1230 if(locswptr->min_listed == -1 ||
1231 SEQ_VAL_IS_LT(val, locswptr->min_listed)) {
1232 locswptr->min_listed = val;
1233 }
1234 break;
1235 }
1236 }
1237 }
1238 if(inconsistency) {
1239 PRINTF("ROLL TM: Inconsistency - ");
1240 PRINTF("Advertised Seq. ID %u within bounds", val);
1241 PRINTF(" [%u, %u] but no matching entry\n",
1242 locswptr->lower_bound, locswptr->upper_bound);
1243 loctpptr->inconsistency = 1;
1244 }
1245 }
1246 }
1247 } else {
1248 /* A new sliding window in an ICMP message is not explicitly stated
1249 * in the draft as inconsistency. Until this is clarified, we consider
1250 * this to be a point where we diverge from the draft for performance
1251 * improvement reasons (or as some would say, 'this is an extension') */
1252 PRINTF("ROLL TM: Inconsistency - Advertised window unknown to us\n");
1253 loctpptr->inconsistency = 1;
1254 }
1255 locslhptr = (struct sequence_list_header *)(((uint8_t *)locslhptr) +
1256 sizeof(struct sequence_list_header) + (2 * locslhptr->seq_len));
1257 }
1258 /* Done parsing the message */
1259
1260 /* Check for "We have new */
1261 PRINTF("ROLL TM: ICMPv6 In, Check our buffer\n");
1262 for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1];
1263 locmpptr >= buffered_msgs; locmpptr--) {
1264 if(MCAST_PACKET_IS_USED(locmpptr)) {
1265 locswptr = locmpptr->sw;
1266 PRINTF("ROLL TM: ICMPv6 In, ");
1267 PRINTF("Check %u, Seed L: %u, This L: %u Min L: %d\n",
1268 locmpptr->seq_val, SLIDING_WINDOW_IS_LISTED(locswptr),
1269 MCAST_PACKET_IS_LISTED(locmpptr), locswptr->min_listed);
1270
1271 /* Point to the sliding window's trickle param */
1272 loctpptr = &t[SLIDING_WINDOW_GET_M(locswptr)];
1273 if(!SLIDING_WINDOW_IS_LISTED(locswptr)) {
1274 /* If a buffered packet's Seed ID was not listed */
1275 PRINTF("ROLL TM: Inconsistency - Seed ID ");
1276 PRINT_SEED(&locswptr->seed_id);
1277 PRINTF(" was not listed\n");
1278 loctpptr->inconsistency = 1;
1279 MCAST_PACKET_SEND_SET(locmpptr);
1280 } else {
1281 /* This packet was not listed but a prior one was */
1282 if(!MCAST_PACKET_IS_LISTED(locmpptr) &&
1283 (locswptr->min_listed >= 0) &&
1284 SEQ_VAL_IS_GT(locmpptr->seq_val, locswptr->min_listed)) {
1285 PRINTF("ROLL TM: Inconsistency - ");
1286 PRINTF("Seq. %u was not listed but %u was\n",
1287 locmpptr->seq_val, locswptr->min_listed);
1288 loctpptr->inconsistency = 1;
1289 MCAST_PACKET_SEND_SET(locmpptr);
1290 }
1291 }
1292 }
1293 }
1294
1295drop:
1296
1297 if(t[0].inconsistency) {
1298 reset_trickle_timer(0);
1299 } else {
1300 t[0].c++;
1301 }
1302 if(t[1].inconsistency) {
1303 reset_trickle_timer(1);
1304 } else {
1305 t[1].c++;
1306 }
1307
1308discard:
1309
1310 uip_len = 0;
1311 return;
1312}
1313/*---------------------------------------------------------------------------*/
1314static void
1315out()
1316{
1317
1318 if(uip_len + HBHO_TOTAL_LEN > UIP_BUFSIZE) {
1319 PRINTF("ROLL TM: Multicast Out can not add HBHO. Packet too long\n");
1320 goto drop;
1321 }
1322
1323 /* Slide 'right' by HBHO_TOTAL_LEN bytes */
1324 memmove(UIP_EXT_BUF_NEXT, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
1325 memset(UIP_EXT_BUF, 0, HBHO_TOTAL_LEN);
1326
1327 UIP_EXT_BUF->next = UIP_IP_BUF->proto;
1328 UIP_EXT_BUF->len = 0;
1329
1330 lochbhmptr = UIP_EXT_OPT_FIRST;
1331 lochbhmptr->type = HBHO_OPT_TYPE_TRICKLE;
1332
1333 /* Set the sequence ID */
1334 last_seq = SEQ_VAL_ADD(last_seq, 1);
1335 lochbhmptr->flags = last_seq >> 8;
1336 lochbhmptr->seq_id_lsb = last_seq & 0xFF;
1337#if ROLL_TM_SHORT_SEEDS
1338 seed_id_cpy(&lochbhmptr->seed_id, &uip_lladdr.addr[UIP_LLADDR_LEN - 2]);
1339 lochbhmptr->len = HBHO_LEN_SHORT_SEED;
1340#else
1341 lochbhmptr->len = HBHO_LEN_LONG_SEED;
1342 /* PadN */
1343 lochbhmptr->padn_type = UIP_EXT_HDR_OPT_PADN;
1344 lochbhmptr->padn_len = 0;
1345#endif
1346
1347 /* Set the M bit for our outgoing messages, if necessary */
1348#if ROLL_TM_SET_M_BIT
1349 HBH_SET_M(lochbhmptr);
1350#endif
1351
1352 uipbuf_add_ext_hdr(HBHO_TOTAL_LEN);
1353
1354 /* Update the proto and length field in the v6 header */
1355 UIP_IP_BUF->proto = UIP_PROTO_HBHO;
1356 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
1357
1358 PRINTF("ROLL TM: Multicast Out, HBHO: T=%u, L=%u, M=%u, S=0x%02x%02x\n",
1359 lochbhmptr->type, lochbhmptr->len, HBH_GET_M(lochbhmptr),
1360 HBH_GET_SV_MSB(lochbhmptr), lochbhmptr->seq_id_lsb);
1361
1362 /*
1363 * We need to remember this message and advertise it in subsequent ICMP
1364 * messages. Otherwise, our neighs will think we are inconsistent and will
1365 * bounce it back to us.
1366 *
1367 * Queue this message but don't set its MUST_SEND flag. We reset the trickle
1368 * timer and we send it immediately. We then set uip_len = 0 to stop the core
1369 * from re-sending it.
1370 */
1371 if(accept(ROLL_TM_DGRAM_OUT)) {
1372 tcpip_output(NULL);
1373 UIP_MCAST6_STATS_ADD(mcast_out);
1374 }
1375
1376drop:
1377 uip_slen = 0;
1378 uipbuf_clear();
1379}
1380/*---------------------------------------------------------------------------*/
1381static uint8_t
1382in()
1383{
1384 /*
1385 * We call accept() which will sort out caching and forwarding. Depending
1386 * on accept()'s return value, we then need to signal the core
1387 * whether to deliver this to higher layers
1388 */
1389 if(accept(ROLL_TM_DGRAM_IN) == UIP_MCAST6_DROP) {
1390 return UIP_MCAST6_DROP;
1391 }
1392
1393 if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) {
1394 PRINTF("ROLL TM: Not a group member. No further processing\n");
1395 return UIP_MCAST6_DROP;
1396 } else {
1397 PRINTF("ROLL TM: Ours. Deliver to upper layers\n");
1398 UIP_MCAST6_STATS_ADD(mcast_in_ours);
1399 return UIP_MCAST6_ACCEPT;
1400 }
1401}
1402/*---------------------------------------------------------------------------*/
1403static void
1404init()
1405{
1406 PRINTF("ROLL TM: ROLL Multicast - Draft #%u\n", ROLL_TM_VER);
1407
1408 memset(windows, 0, sizeof(windows));
1409 memset(buffered_msgs, 0, sizeof(buffered_msgs));
1410 memset(t, 0, sizeof(t));
1411
1412 ROLL_TM_STATS_INIT();
1413 UIP_MCAST6_STATS_INIT(&stats);
1414
1415 /* Register the ICMPv6 input handler */
1416 uip_icmp6_register_input_handler(&roll_tm_icmp_handler);
1417
1418 for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
1419 iterswptr--) {
1420 iterswptr->lower_bound = -1;
1421 iterswptr->upper_bound = -1;
1422 iterswptr->min_listed = -1;
1423 }
1424
1425 TIMER_CONFIGURE(0);
1426 reset_trickle_timer(0);
1427 TIMER_CONFIGURE(1);
1428 reset_trickle_timer(1);
1429 return;
1430}
1431/*---------------------------------------------------------------------------*/
1432/**
1433 * \brief The ROLL TM engine driver
1434 */
1436 "ROLL TM",
1437 init,
1438 out,
1439 in,
1440};
1441/*---------------------------------------------------------------------------*/
1442/** @} */
clock_time_t clock_time(void)
Get the current clock time.
Definition clock.c:118
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition random.c:58
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition watchdog.c:85
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition ctimer.h:137
#define seed_id_cpy(a, b)
Copy one seed_id_t into another.
Definition mpl.c:141
static void icmp_in(void)
Definition mpl.c:1062
#define seed_id_cmp(a, b)
Compare two contiki seed ids represented as seed_id_t types a: First value to compare b: Second value...
Definition mpl.c:135
#define SLIDING_WINDOW_IS_USED(w)
Is Occupied sliding window location w w: pointer to a sliding window.
Definition roll-tm.c:215
#define TIMER_CONFIGURE(m)
Init trickle_timer[m].
Definition roll-tm.c:143
#define SUPPRESSION_ENABLED(t)
Check if suppression is enabled for trickle_param t t is a pointer to the timer.
Definition roll-tm.c:132
#define SLIDING_WINDOW_M_SET(w)
Set M bit for window w w: pointer to a sliding window.
Definition roll-tm.c:252
#define SLIDING_WINDOW_IS_LISTED(w)
Is the sliding window at location w listed in current ICMP message? w: pointer to a sliding window.
Definition roll-tm.c:246
#define MCAST_PACKET_IS_USED(p)
Is Occupied buffer location p.
Definition roll-tm.c:317
#define ROLL_TM_WINS
Number of Sliding Windows In essence: How many unique sources of simultaneous multicast traffic do we...
Definition roll-tm.h:175
#define ROLL_TM_ICMP_CODE
ROLL TM ICMPv6 code field.
Definition roll-tm.h:73
#define HBH_GET_M(h)
Get the Trickle Parametrization for a multicast HBHO header m: pointer to the HBHO header.
Definition roll-tm.c:409
#define SUPPRESSION_DISABLED(t)
Check if suppression is disabled for trickle_param t t is a pointer to the timer.
Definition roll-tm.c:138
#define ROLL_TM_VER
Supported Draft Version.
Definition roll-tm.h:72
#define MCAST_PACKET_LISTED_CLR(p)
Clear 'Is Listed' bit for message p p: pointer to a struct mcast_packet.
Definition roll-tm.c:352
#define MCAST_PACKET_USED_SET(p)
Set 'Is Used' bit for packet p p: pointer to a packet buffer.
Definition roll-tm.c:306
#define SLIDING_WINDOW_LISTED_CLR(w)
Clear 'Is Seen' bit for window w w: pointer to a sliding window.
Definition roll-tm.c:240
#define SEQ_VAL_ADD(s, n)
Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000)
Definition roll-tm.c:194
#define HBH_GET_SV_MSB(h)
Retrieve the Sequence Value MSB from a multicast HBHO header m: pointer to the HBHO header.
Definition roll-tm.c:421
static uint8_t accept(uint8_t in)
Processes an incoming or outgoing multicast message and determines whether it should be dropped or ac...
Definition roll-tm.c:888
#define MCAST_PACKET_TTL(p)
Get the TTL of a buffered packet p: pointer to a packet buffer.
Definition roll-tm.c:299
#define SEQ_VAL_IS_LT(i1, i2)
s1 is said to be less than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
Definition roll-tm.c:174
const struct uip_mcast6_driver roll_tm_driver
The ROLL TM engine driver.
Definition roll-tm.c:1435
#define SLIDING_WINDOW_IS_USED_SET(w)
Set 'Is Used' bit for window w w: pointer to a sliding window.
Definition roll-tm.c:221
#define MCAST_PACKET_SEND_CLR(p)
Clear 'Must Send' bit for message p p: pointer to a struct mcast_packet.
Definition roll-tm.c:334
#define TRICKLE_TIME(m, d)
Convert a timer to a sane clock_time_t value after d doublings m is a value of Imin,...
Definition roll-tm.c:107
#define TRICKLE_DWELL(t)
Convert Tdwell for a trickle timer to a sane clock_time_t value t is a pointer to the timer Careful o...
Definition roll-tm.c:126
#define SEQ_VAL_IS_EQ(i1, i2)
s1 is said to be equal s2 iif SEQ_VAL_IS_EQ(s1, s2) == 1
Definition roll-tm.c:169
#define MCAST_PACKET_LISTED_SET(p)
Set 'Is Listed' bit for message p p: pointer to a struct mcast_packet.
Definition roll-tm.c:346
#define MCAST_PACKET_FREE(p)
Free a multicast packet buffer p: pointer to a struct mcast_packet.
Definition roll-tm.c:358
#define ROLL_TM_IP_HOP_LIMIT
Hop limit for ICMP messages.
Definition roll-tm.h:74
#define SLIDING_WINDOW_LISTED_SET(w)
Set 'Is Seen' bit for window w w: pointer to a sliding window.
Definition roll-tm.c:234
#define SLIDING_WINDOW_M_CLR(w)
Clear M bit for window w w: pointer to a sliding window.
Definition roll-tm.c:258
#define SEQUENCE_LIST_GET_M(l)
Get the Trickle Parametrization for an ICMPv6 sequence list l: pointer to a sequence list structure.
Definition roll-tm.c:375
#define SEQUENCE_LIST_GET_S(l)
Get the Seed ID Length for an ICMPv6 sequence list l: pointer to a sequence list structure.
Definition roll-tm.c:382
#define MCAST_PACKET_MUST_SEND(p)
Must we send this message this pass?
Definition roll-tm.c:322
#define SEQ_VAL_IS_GT(i1, i2)
s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
Definition roll-tm.c:184
#define MCAST_PACKET_IS_LISTED(p)
Is the message p listed in current ICMP message? p: pointer to a struct mcast_packet.
Definition roll-tm.c:340
#define MCAST_PACKET_SEND_SET(p)
Set 'Must Send' bit for message p p: pointer to a struct mcast_packet.
Definition roll-tm.c:328
#define SLIDING_WINDOW_GET_M(w)
Retrieve trickle parametrization for sliding window at location w w: pointer to a sliding window.
Definition roll-tm.c:264
#define TRICKLE_ACTIVE(t)
Convert Tactive for a trickle timer to a sane clock_time_t value t is a pointer to the timer Careful ...
Definition roll-tm.c:119
#define HBH_SET_M(h)
Set the Trickle Parametrization bit for a multicast HBHO header m: pointer to the HBHO header.
Definition roll-tm.c:415
#define ROLL_TM_BUFF_NUM
Maximum Number of Buffered Multicast Messages This buffer is shared across all Seed IDs,...
Definition roll-tm.h:187
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
#define ICMP6_ROLL_TM
ROLL Trickle Multicast.
Definition uip-icmp6.h:72
uip_lladdr_t uip_lladdr
Host L2 address.
Definition uip6.c:107
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Definition uip.h:1725
#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
#define uip_is_addr_mcast_non_routable(a)
is address a non-routable multicast address.
Definition uip.h:1877
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC 4291 i.e.
Definition uip.h:1766
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
Definition uip-ds6.c:530
#define uip_is_addr_linklocal_allrouters_mcast(a)
Is IPv6 address a the link local all-routers multicast address.
Definition uip.h:1749
#define uip_is_addr_linklocal_allnodes_mcast(a)
Is IPv6 address a the link local all-nodes multicast address.
Definition uip.h:1736
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 UIP_PROTO_HBHO
extension headers types
Definition uip.h:1663
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition uip.h:71
uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
Definition uip6.c:2341
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
Header file for the implementation of the ROLL-TM multicast engine.
Multicast stats extension for the ROLL TM engine.
Definition roll-tm.h:230
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
A set of debugging macros for the IP stack.
Header file for ICMPv6 message and error handing (RFC 4443)
This header file contains configuration directives for uIPv6 multicast support.