Contiki-NG
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
69 typedef 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 */
77 typedef 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 */
86 struct 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 */
197 struct 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 */
268 struct 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 */
361 struct 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 */
386 struct 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
432 static 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 /*---------------------------------------------------------------------------*/
443 static struct trickle_param t[2];
444 static struct sliding_window windows[ROLL_TM_WINS];
445 static struct mcast_packet buffered_msgs[ROLL_TM_BUFF_NUM];
446 /*---------------------------------------------------------------------------*/
447 /* Temporary Stores */
448 /*---------------------------------------------------------------------------*/
449 static struct trickle_param *loctpptr;
450 static struct sequence_list_header *locslhptr;
451 static struct sliding_window *locswptr;
452 static struct sliding_window *iterswptr;
453 static struct mcast_packet *locmpptr;
454 static struct hbho_mcast *lochbhmptr;
455 static 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))
462 extern uint16_t uip_slen;
463 /*---------------------------------------------------------------------------*/
464 /* Local function prototypes */
465 /*---------------------------------------------------------------------------*/
466 static void icmp_input(void);
467 static void icmp_output(void);
468 static void window_update_bounds(void);
469 static void reset_trickle_timer(uint8_t);
470 static void handle_timer(void *);
471 /*---------------------------------------------------------------------------*/
472 /* ROLL TM ICMPv6 handler declaration */
473 UIP_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 */
478 static clock_time_t
479 random_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 */
490 static void
491 double_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  */
530 static void
531 handle_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 /*---------------------------------------------------------------------------*/
663 static void
664 reset_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 /*---------------------------------------------------------------------------*/
680 static struct sliding_window *
681 window_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 /*---------------------------------------------------------------------------*/
696 static struct sliding_window *
697 window_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 /*---------------------------------------------------------------------------*/
712 static void
713 window_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 /*---------------------------------------------------------------------------*/
739 static struct mcast_packet *
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);
768  MCAST_PACKET_FREE(rv);
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 /*---------------------------------------------------------------------------*/
781 static struct mcast_packet *
782 buffer_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 /*---------------------------------------------------------------------------*/
793 static void
794 icmp_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 
864  UIP_ICMP_BUF->type = ICMP6_ROLL_TM;
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  */
887 static uint8_t
888 accept(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
897  if(uip_is_addr_mcast_non_routable(&UIP_IP_BUF->destipaddr)) {
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  }
1033  SLIDING_WINDOW_IS_USED_SET(locswptr);
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 */
1088 static void
1089 icmp_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 
1295 drop:
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 
1308 discard:
1309 
1310  uip_len = 0;
1311  return;
1312 }
1313 /*---------------------------------------------------------------------------*/
1314 static void
1315 out()
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 
1376 drop:
1377  uip_slen = 0;
1378  uipbuf_clear();
1379 }
1380 /*---------------------------------------------------------------------------*/
1381 static uint8_t
1382 in()
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 /*---------------------------------------------------------------------------*/
1403 static void
1404 init()
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 /** @} */
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition: uip.h:71
#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 SLIDING_WINDOW_M_CLR(w)
Clear M bit for window w w: pointer to a sliding window.
Definition: roll-tm.c:258
#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
uip_lladdr_t uip_lladdr
Host L2 address.
Definition: uip6.c:107
uint8_t tcpip_output(const uip_lladdr_t *a)
Output packet to layer 2 The eventual parameter is the MAC address of the destination.
Definition: tcpip.c:106
#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:234
Header file for ICMPv6 message and error handing (RFC 4443)
Multicast stats extension for the ROLL TM engine.
Definition: roll-tm.h:230
Header file for the implementation of the ROLL-TM multicast engine.
#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:107
#define uip_is_addr_linklocal_allrouters_mcast(a)
Is IPv6 address a the link local all-routers multicast address.
Definition: uip.h:1860
#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
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
#define ROLL_TM_IP_HOP_LIMIT
Hop limit for ICMP messages.
Definition: roll-tm.h:74
#define ICMP6_ROLL_TM
ROLL Trickle Multicast.
Definition: uip-icmp6.h:72
The data structure used to represent a multicast engine.
Definition: uip-mcast6.h:101
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
Definition: tcpip.c:631
#define SLIDING_WINDOW_IS_USED(w)
Is Occupied sliding window location w w: pointer to a sliding window.
Definition: roll-tm.c:215
#define ROLL_TM_ICMP_CODE
ROLL TM ICMPv6 code field.
Definition: roll-tm.h:73
#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 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 UIP_PROTO_HBHO
extension headers types
Definition: uip.h:1764
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:134
static void icmp_in(void)
Definition: mpl.c:1063
static struct mpl_msg * buffer_reclaim(void)
Definition: mpl.c:489
A set of debugging macros for the IP stack
#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:334
#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 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
uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
Definition: uip6.c:2334
#define UIP_LLADDR_LEN
802.15.4 address
Definition: uip.h:145
const struct uip_mcast6_driver roll_tm_driver
The ROLL TM engine driver.
Definition: roll-tm.c:1435
#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
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:252
uint16_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:122
uint8_t(* in)(void)
Process an incoming multicast datagram and determine whether it should be delivered up the stack or n...
Definition: uip-mcast6.h:139
#define 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 uip_is_addr_mcast_non_routable(a)
is address a non-routable multicast address.
Definition: uip.h:1978
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 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:221
#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
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Definition: uip.h:1836
#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:306
#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
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:118
#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 MCAST_PACKET_MUST_SEND(p)
Must we send this message this pass?
Definition: roll-tm.c:322
#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 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:328
#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
void(* out)(void)
Process an outgoing datagram with a multicast IPv6 destination address.
Definition: uip-mcast6.h:121
#define ROLL_TM_BUFF_NUM
Maximum Number of Buffered Multicast Messages This buffer is shared across all Seed IDs...
Definition: roll-tm.h:187
#define ROLL_TM_VER
Supported Draft Version.
Definition: roll-tm.h:72
void(* init)(void)
Initialize the multicast engine.
Definition: uip-mcast6.h:106
#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_LISTED_CLR(w)
Clear &#39;Is Seen&#39; bit for window w w: pointer to a sliding window.
Definition: roll-tm.c:240
uint16_t uip_icmp6chksum(void)
Calculate the ICMP checksum of the packet in uip_buf.
Definition: uip6.c:363
#define uip_is_addr_linklocal_allnodes_mcast(a)
Is IPv6 address a the link local all-nodes multicast address.
Definition: uip.h:1847
#define seed_id_cpy(a, b)
Copy one seed_id_t into another.
Definition: mpl.c:141
#define MCAST_PACKET_FREE(p)
Free a multicast packet buffer p: pointer to a struct mcast_packet.
Definition: roll-tm.c:358
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 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:352
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
#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
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC 4291 i.e.
Definition: uip.h:1877
#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:346
#define MCAST_PACKET_TTL(p)
Get the TTL of a buffered packet p: pointer to a packet buffer.
Definition: roll-tm.c:299
#define MCAST_PACKET_IS_USED(p)
Is Occupied buffer location p.
Definition: roll-tm.c:317
#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
#define TIMER_CONFIGURE(m)
Init trickle_timer[m].
Definition: roll-tm.c:143
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
Definition: uip-ds6.c:538
#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 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