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