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