Contiki-NG
mpl.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018, University of Bristol - http://www.bristol.ac.uk/
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 mpl
34  * @{
35  */
36 /**
37  * \file
38  * Implementation of the MPL protocol
39  * \author
40  * Ed Rose - <er15406@bris.ac.uk>
41  */
42 
43 #include "contiki.h"
44 #include "contiki-lib.h"
45 #include "contiki-net.h"
46 #include "net/ipv6/uip.h"
47 #include "net/ipv6/uip-ds6.h"
48 #include "net/ipv6/uip-icmp6.h"
50 #include "net/ipv6/multicast/mpl.h"
51 #include "dev/watchdog.h"
52 #include "os/lib/trickle-timer.h"
53 #include "os/lib/list.h"
54 #include "sys/ctimer.h"
55 #include <string.h>
56 
57 #include "sys/log.h"
58 #define LOG_MODULE "MPL"
59 #define LOG_LEVEL LOG_LEVEL_NONE
60 
61 /*---------------------------------------------------------------------------*/
62 /* Check Parameters are Correct */
63 /*---------------------------------------------------------------------------*/
64 /* MPL Seed IDs */
65 #if MPL_SEED_ID_TYPE < 0 || MPL_SEED_ID_TYPE > 3
66 #error Invalid value for MPL_SEED_ID_TYPE
67 #endif
68 #if MPL_SEED_ID_TYPE == 0 && (MPL_SEED_ID_H > 0x00 || MPL_SEED_ID_L > 0x00)
69 #warning MPL Seed ID Set but not used due to Seed ID type setting
70 #endif
71 #if MPL_SEED_ID_TYPE == 1 && MPL_SEED_ID_H > 0x00
72 #warning MPL Seed ID upper 64 bits set but not used due to Seed ID type setting
73 #endif
74 #if MPL_SEED_ID_TYPE == 1 && MPL_SEED_ID_L > 0xFFFF
75 #error MPL Seed ID too large for Seed ID type setting
76 #endif
77 #if MPL_SEED_ID_TYPE == 2 && MPL_SEED_ID_H > 0x00
78 #warning MPL Seed ID upper 64 bits set yet not used due to Seed ID type setting
79 #endif
80 /*---------------------------------------------------------------------------*/
81 /* Data Representation */
82 /*---------------------------------------------------------------------------*/
83 /* MPL Seed IDs */
84 typedef struct seed_id_s {
85  uint8_t s;
86  uint8_t id[16];
87 } seed_id_t;
88 #define MPL_SEED_ID_UNKNOWN 0xFF
89 /* Define a way of logging the seed id */
90 #define LOG_SEED(level, seed_id) do { \
91  if(level <= (LOG_LEVEL)) { \
92  LOG_OUTPUT("0x%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx%.2hx", \
93  seed_id.id[15], seed_id.id[14], seed_id.id[13], seed_id.id[12], \
94  seed_id.id[11], seed_id.id[10], seed_id.id[9], seed_id.id[8], \
95  seed_id.id[7], seed_id.id[6], seed_id.id[5], seed_id.id[4], \
96  seed_id.id[3], seed_id.id[2], seed_id.id[1], seed_id.id[0]); \
97  } \
98 } while(0);
99 /* Macros to print seed id in logs */
100 #define LOG_INFO_SEED(...) LOG_SEED(LOG_LEVEL_INFO, __VA_ARGS__)
101 #define LOG_WARN_SEED(...) LOG_SEED(LOG_LEVEL_WARN, __VA_ARGS__)
102 #define LOG_ERR_SEED(...) LOG_SEED(LOG_LEVEL_ERR, __VA_ARGS__)
103 #define LOG_DBG_SEED(...) LOG_SEED(LOG_LEVEL_DBG, __VA_ARGS__)
104 
105 /* MPL Seed IDs can be either 16 bits, 64 bits, or 128 bits. If they are 128
106  * bits then the IPV6 Source address may also be used as the seed ID.
107  * These are always represented in contiki as a 128 bit number in the type
108  * seed_id_t. The functions below convert a seed id of various lengths to
109  * this 128 bit representation.
110  */
111 /**
112  * \brief Set the seed id to a 16 bit constant
113  * dst: seed_id_t to set to the constant
114  * src: 16 bit integer to set
115  */
116 #define SEED_ID_S1(dst, src) { (*(uint16_t *)&(dst)->id) = (src); (dst)->s = 1; }
117 /**
118  * \brief Set the seed id to a 64 bit constant
119  * dst: seed_id_t to set to the constant
120  * src: 64 bit integer to set
121  */
122 #define SEED_ID_S2(dst, src) { (*(uint64_t *)&(dst)->id) = (src); (dst)->s = 2; }
123 /**
124  * \brief Set the seed id to a 128 bit constant
125  * dst: seed_id_t to set to the constant
126  * l: Lower 64 bits of the seed id to set
127  * h: Upper 64 bits of the seed id to set
128  */
129 #define SEED_ID_S3(dst, l, h) { (*(uint64_t *)&(dst)->id) = (l); (*(uint64_t *)&(dst)->id[8]) = (h); (dst)->s = 3; }
130 /**
131  * \brief Compare two contiki seed ids represented as seed_id_t types
132  * a: First value to compare
133  * b: Second value to compare
134  */
135 #define seed_id_cmp(a, b) (memcmp((a)->id, (b)->id, sizeof(uint8_t) * 16) == 0)
136 /**
137  * \brief Copy one seed_id_t into another.
138  * a: Destination
139  * b: Source
140  */
141 #define seed_id_cpy(a, b) (memcpy((a), (b), sizeof(seed_id_t)))
142 /**
143  * \brief Clear a seed id value to zero
144  * a: Value to clear
145  */
146 #define seed_id_clr(a) (memset((a), 0, sizeof(seed_id_t)))
147 /*---------------------------------------------------------------------------*/
148 /* Buffered message set
149  * This is implemented as a linked list since the majority of operations
150  * involve finding the minimum sequence number and iterating up the list.
151  */
152 struct mpl_msg {
153  struct mpl_msg *next; /* Next message in the set, or NULL if this is largest */
154  struct mpl_seed *seed; /* The seed set this message belongs to */
155  struct trickle_timer tt; /* The trickle timer associated with this msg */
156  uip_ip6addr_t srcipaddr; /* The original ip this message was sent from */
157  uint16_t size; /* Side of the data stored above */
158  uint8_t seq; /* The sequence number of the message */
159  uint8_t e; /* Expiration count for trickle timer */
160  uint8_t data[UIP_BUFSIZE]; /* Message payload */
161 };
162 /**
163  * \brief Get the state of the used flag in the buffered message set entry
164  * h: pointer to the message set entry
165  */
166 #define MSG_SET_IS_USED(h) ((h)->seed != NULL)
167 /**
168  * \brief Clear the state of the used flag in the buffered message set entry
169  * h: pointer to the message set entry
170  */
171 #define MSG_SET_CLEAR_USED(h) ((h)->seed = NULL)
172 /* RFC 1982 Serial Number Arithmetic */
173 /**
174  * \brief s1 is said to be equal s2 if SEQ_VAL_IS_EQ(s1, s2) == 1
175  */
176 #define SEQ_VAL_IS_EQ(i1, i2) ((i1) == (i2))
177 
178 /**
179  * \brief s1 is said to be less than s2 if SEQ_VAL_IS_LT(s1, s2) == 1
180  */
181 #define SEQ_VAL_IS_LT(i1, i2) \
182  ( \
183  ((i1) != (i2)) && \
184  ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) < 0x100)) || \
185  (((i1) > (i2)) && ((int16_t)((i1) - (i2)) > 0x100))) \
186  )
187 
188 /**
189  * \brief s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
190  */
191 #define SEQ_VAL_IS_GT(i1, i2) \
192  ( \
193  ((i1) != (i2)) && \
194  ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) > 0x100)) || \
195  (((i1) > (i2)) && ((int16_t)((i1) - (i2)) < 0x100))) \
196  )
197 
198 /**
199  * \brief Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000)
200  */
201 #define SEQ_VAL_ADD(s, n) (((s) + (n)) % 0x100)
202 /*---------------------------------------------------------------------------*/
203 /* Seed Set */
204 struct mpl_seed {
205  seed_id_t seed_id;
206  uint8_t min_seqno; /* Used when the seed set is empty */
207  uint8_t lifetime; /* Decrements by one every minute */
208  uint8_t count; /* Only used for determining largest msg set during reclaim */
209  LIST_STRUCT(min_seq); /* Pointer to the first msg in this seed's set */
210  struct mpl_domain *domain; /* The domain this seed belongs to */
211 };
212 /**
213  * \brief Get the state of the used flag in the buffered message set entry
214  * h: pointer to the message set entry
215  */
216 #define SEED_SET_IS_USED(h) (((h)->domain != NULL))
217 /**
218  * \brief Clear the state of the used flag in the buffered message set entry
219  * h: pointer to the message set entry
220  */
221 #define SEED_SET_CLEAR_USED(h) ((h)->domain = NULL)
222 /*---------------------------------------------------------------------------*/
223 /* Domain Set */
224 struct mpl_domain {
225  uip_ip6addr_t data_addr; /* Data address for this MPL domain */
226  uip_ip6addr_t ctrl_addr; /* Link-local scoped version of data address */
227  struct trickle_timer tt;
228  uint8_t e; /* Expiration count for trickle timer */
229 };
230 /**
231  * \brief Get the state of the used flag in the buffered message set entry
232  * h: pointer to the message set entry
233  */
234 #define DOMAIN_SET_IS_USED(h) (uip_is_addr_mcast(&(h)->data_addr))
235 /**
236  * \brief Clear the state of the used flag in the buffered message set entry
237  * h: pointer to the message set entry
238  */
239 #define DOMAIN_SET_CLEAR_USED(h) (memset(&(h)->data_addr, 0, sizeof(uip_ip6addr_t)))
240 /*---------------------------------------------------------------------------*/
241 /**
242  * Hop-by-Hop Options Header
243  * The header can take different forms depending on the length of the seed id,
244  * so all the different representations are shown here.
245  */
246 struct mpl_hbho {
247  uint8_t type;
248  uint8_t len;
249  uint8_t flags;
250  uint8_t seq;
251  struct uip_ext_hdr_opt_padn padn;
252 };
253 struct mpl_hbho_s1 {
254  uint8_t type;
255  uint8_t len;
256  uint8_t flags;
257  uint8_t seq;
258  uint16_t seed_id;
259 };
260 struct mpl_hbho_s2 {
261  uint8_t type;
262  uint8_t len;
263  uint8_t flags;
264  uint8_t seq;
265  uint64_t seed_id;
266  struct uip_ext_hdr_opt_padn padn;
267 };
268 struct mpl_hbho_s3 {
269  uint8_t type;
270  uint8_t len;
271  uint8_t flags;
272  uint8_t seq;
273  uint8_t seed_id[16];
274  struct uip_ext_hdr_opt_padn padn;
275 };
276 /**
277  * \brief Get the MPL Parametrization for a multicast HBHO header
278  * m: pointer to the HBHO header
279  */
280 #define HBH_GET_S(h) (((h)->flags & 0xC0) >> 6)
281 
282 /**
283  * \brief Set the MPL Parametrization bit for a multicast HBHO header
284  * m: pointer to the HBHO header
285  */
286 #define HBH_SET_S(h, s) ((h)->flags |= ((s & 0x03) << 6))
287 
288 /**
289  * \brief Clear the MPL Parametrization bit for a multicast HBHO header
290  * m: pointer to the HBHO header
291  */
292 #define HBH_CLR_S(h) ((h)->flags &= ~0xC0)
293 
294 /**
295  * \brief Get the MPL Parametrization for a multicast HBHO header
296  * m: pointer to the HBHO header
297  */
298 #define HBH_GET_M(h) (((h)->flags & 0x20) == 0x20)
299 
300 /**
301  * \brief Set the MPL Parametrization bit for a multicast HBHO header
302  * m: pointer to the HBHO header
303  */
304 #define HBH_SET_M(h) ((h)->flags |= 0x20)
305 
306 /**
307  * \brief Get the MPL Parametrization for a multicast HBHO header
308  * m: pointer to the HBHO header
309  */
310 #define HBH_GET_V(h) (((h)->flags & 0x10) == 0x10)
311 
312 /**
313  * \brief Set the MPL Parametrization bit for a multicast HBHO header
314  * m: pointer to the HBHO header
315  */
316 #define HBH_CLR_V(h) ((h)->flags &= ~0x10)
317 /* Outdoing msg HBHO Sizes */
318 #if MPL_SEED_ID_TYPE == 0
319 #define HBHO_TOTAL_LEN HBHO_BASE_LEN + HBHO_S0_LEN
320 #elif MPL_SEED_ID_TYPE == 1
321 #define HBHO_TOTAL_LEN HBHO_BASE_LEN + HBHO_S1_LEN
322 #elif MPL_SEED_ID_TYPE == 2
323 #define HBHO_TOTAL_LEN HBHO_BASE_LEN + HBHO_S2_LEN
324 #elif MPL_SEED_ID_TYPE == 3
325 #define HBHO_TOTAL_LEN HBHO_BASE_LEN + HBHO_S3_LEN
326 #endif
327 /*---------------------------------------------------------------------------*/
328 /** Seed Info Payload
329  * This is the payload sent in ICMP Control messages. It changes based on the
330  * Seed ID length being sent, so all the different representations it can take
331  * are shown here.
332  */
333 struct seed_info {
334  uint8_t min_seqno;
335  uint8_t bm_len_S; /* First 6 bits bm-len, last 2 S */
336 };
337 struct seed_info_s1 {
338  uint8_t min_seqno;
339  uint8_t bm_len_S; /* First 6 bits bm-len, last 2 S */
340  uint16_t seed_id;
341 };
342 struct seed_info_s2 {
343  uint8_t min_seqno;
344  uint8_t bm_len_S; /* First 6 bits bm-len, last 2 S */
345  uint64_t seed_id;
346 };
347 struct seed_info_s3 {
348  uint8_t min_seqno;
349  uint8_t bm_len_S; /* First 6 bits bm-len, last 2 S */
350  uint8_t seed_id[16];
351 };
352 /**
353  * \brief Get the S bits in the length/S field in the seed info header
354  * h: pointer to the seed info struct
355  */
356 #define SEED_INFO_GET_S(h) ((h)->bm_len_S & 0x03)
357 /**
358  * \brief Clear the S bits within the length/S field in the seed info header
359  * h: pointer to the seed info struct
360  */
361 #define SEED_INFO_CLR_S(h) ((h)->bm_len_S &= ~0x03)
362 /**
363  * \brief Set the S bits within the seed info struct. These must be cleared beforehand.
364  * h: Pointer to the seed info struct
365  * s: value (0-3) that the S bits should be set to
366  */
367 #define SEED_INFO_SET_S(h, s) ((h)->bm_len_S |= (s & 0x03))
368 /**
369  * \brief Get the length bits from the seed info struct.
370  * h: pointer to seed info struct.
371  */
372 #define SEED_INFO_GET_LEN(h) ((h)->bm_len_S >> 2)
373 /**
374  * \brief Clear the length bits in the seed info struct.
375  * h: pointer to the seed info struct
376  */
377 #define SEED_INFO_CLR_LEN(h) ((h)->bm_len_S &= 0x03)
378 /**
379  * \brief Set the length bits in the seed info struct. These must be cleared beforehand.
380  * h: pointer to the seed info struct
381  * l: Length value (0-63) that the length bits should be set to
382  */
383 #define SEED_INFO_SET_LEN(h, l) ((h)->bm_len_S |= (l << 2))
384 /*---------------------------------------------------------------------------*/
385 /* Maintain Stats */
386 /*---------------------------------------------------------------------------*/
387 #if UIP_MCAST6_STATS
388 static struct mpl_stats stats;
389 
390 #define MPL_STATS_ADD(x) stats.x++
391 #define MPL_STATS_INIT() do { memset(&stats, 0, sizeof(stats)); } while(0)
392 #else /* UIP_MCAST6_STATS */
393 #define MPL_STATS_ADD(x)
394 #define MPL_STATS_INIT()
395 #endif
396 /*---------------------------------------------------------------------------*/
397 /* Internal Data Structures */
398 /*---------------------------------------------------------------------------*/
399 static struct mpl_msg buffered_message_set[MPL_BUFFERED_MESSAGE_SET_SIZE];
400 static struct mpl_seed seed_set[MPL_SEED_SET_SIZE];
401 static struct mpl_domain domain_set[MPL_DOMAIN_SET_SIZE];
402 static uint16_t last_seq;
403 static seed_id_t local_seed_id;
404 #if MPL_SUB_TO_ALL_FORWARDERS
405 static uip_ip6addr_t all_forwarders;
406 #endif
407 static struct ctimer lifetime_timer;
408 /*---------------------------------------------------------------------------*/
409 /* Temporary Stores */
410 /*---------------------------------------------------------------------------*/
411 static struct mpl_hbho *lochbhmptr; /* HBH Header Pointer */
412 static struct mpl_seed *locssptr; /* Seed Set Pointer */
413 static struct mpl_msg *locmmptr; /* MPL Message Pointer */
414 static struct mpl_domain *locdsptr; /* Domain set pointer */
415 static struct seed_info *locsiptr; /* Seed Info Pointer */
416 /*---------------------------------------------------------------------------*/
417 /* uIPv6 Pointers */
418 /*---------------------------------------------------------------------------*/
419 #define UIP_EXT_BUF ((struct uip_ext_hdr *)UIP_IP_PAYLOAD(0))
420 #define UIP_EXT_BUF_NEXT ((uint8_t *)(UIP_IP_PAYLOAD(HBHO_TOTAL_LEN)))
421 #define UIP_EXT_OPT_FIRST ((struct mpl_hbho *)(UIP_IP_PAYLOAD(0) + 2))
422 extern uint16_t uip_slen;
423 /*---------------------------------------------------------------------------*/
424 /* Local Macros */
425 /*---------------------------------------------------------------------------*/
426 /**
427  * \brief Start the trickle timer for a control message
428  * t: Pointer to set that should be reset
429  */
430 #define mpl_control_trickle_timer_start(t) { (t)->e = 0; trickle_timer_set(&(t)->tt, control_message_expiration, (t)); }
431 /**
432  * \brief Start the trickle timer for a data message
433  * t: Pointer to set that should be reset
434  */
435 #define mpl_data_trickle_timer_start(t) { (t)->e = 0; trickle_timer_set(&(t)->tt, data_message_expiration, (t)); }
436 /**
437  * \brief Call inconsistency on the provided timer
438  * t: Pointer to set that should be reset
439  */
440 #define mpl_trickle_timer_inconsistency(t) { (t)->e = 0; trickle_timer_inconsistency(&(t)->tt); }
441 /**
442  * \brief Reset the trickle timer and expiration count for the set
443  * t: Pointer to set that should be reset
444  */
445 #define mpl_trickle_timer_reset(t) { (t)->e = 0; trickle_timer_reset_event(&(t)->tt); }
446 /**
447  * \brief Set a single bit within a bit vector that spans multiple bytes
448  * v: The bit vector
449  * b: The 0-indexed bit to set
450  */
451 #define BIT_VECTOR_SET_BIT(v, b) (v[b / 8] |= (0x80 >> b % 8))
452 /**
453  * \brief Get the value of a bit in a bit vector
454  * v: The bit vector
455  * b: The 0-indexed bit to get
456  */
457 #define BIT_VECTOR_GET_BIT(v, b) ((v[b / 8] & (0x80 >> b % 8)) == (0x80 >> b % 8))
458 /**
459  * \brief Modify an ipv6 address to give it link local scope
460  * a: uip_ip6addr_t address to modify
461  */
462 #define UIP_ADDR_MAKE_LINK_LOCAL(a) (((uip_ip6addr_t *)a)->u8[1] = UIP_MCAST6_SCOPE_LINK_LOCAL)
463 /*---------------------------------------------------------------------------*/
464 /* Local function prototypes */
465 /*---------------------------------------------------------------------------*/
466 static void icmp_in(void);
467 UIP_ICMP6_HANDLER(mpl_icmp_handler, ICMP6_MPL, 0, icmp_in);
468 
469 static struct mpl_msg *
470 buffer_allocate(void)
471 {
472  for(locmmptr = &buffered_message_set[MPL_BUFFERED_MESSAGE_SET_SIZE - 1]; locmmptr >= buffered_message_set; locmmptr--) {
473  if(!MSG_SET_IS_USED(locmmptr)) {
474  memset(locmmptr, 0, sizeof(struct mpl_msg));
475  return locmmptr;
476  }
477  }
478  return NULL;
479 }
480 static void
481 buffer_free(struct mpl_msg *msg)
482 {
483  if(trickle_timer_is_running(&msg->tt)) {
484  trickle_timer_stop(&msg->tt);
485  }
486  MSG_SET_CLEAR_USED(msg);
487 }
488 static struct mpl_msg *
490 {
491  static struct mpl_seed *ssptr; /* Can't use locssptr since it's used by calling function */
492  static struct mpl_seed *largest;
493  static struct mpl_msg *reclaim;
494 
495  /* Reclaim the message with min_seq in the largest seed set */
496  largest = NULL;
497  reclaim = NULL;
498  for(ssptr = &seed_set[MPL_SEED_SET_SIZE]; ssptr >= seed_set; ssptr--) {
499  if(SEED_SET_IS_USED(ssptr) && (largest == NULL || ssptr->count > largest->count)) {
500  largest = ssptr;
501  }
502  }
503  /**
504  * To reclaim this, we need to increment the min seq number to
505  * the next largest sequence number in the set.
506  * This won't necessarily be min_seq + 1 because MPL does not require or
507  * ensure that sequence number are sequential, it just denotes the
508  * order messages are sent.
509  * We've already worked out what this new value is.
510  */
511  if(largest != NULL) {
512  reclaim = list_pop(largest->min_seq);
513  largest->min_seqno = list_item_next(reclaim) == NULL ? reclaim->seq : ((struct mpl_msg *)list_item_next(reclaim))->seq;
514  largest->count--;
515  trickle_timer_stop(&reclaim->tt);
516  mpl_trickle_timer_reset(reclaim->seed->domain);
517  memset(reclaim, 0, sizeof(struct mpl_msg));
518  }
519  return reclaim;
520 }
521 static struct mpl_domain *
522 domain_set_allocate(uip_ip6addr_t *address)
523 {
524  uip_ip6addr_t data_addr;
525  uip_ip6addr_t ctrl_addr;
526  /* Determine the two addresses for this domain */
527  if(uip_mcast6_get_address_scope(address) == UIP_MCAST6_SCOPE_LINK_LOCAL) {
528  LOG_DBG("Domain Set Allocate has a local scoped address\n");
529  memcpy(&data_addr, address, sizeof(uip_ip6addr_t));
530  memcpy(&ctrl_addr, address, sizeof(uip_ip6addr_t));
531  do {
532  data_addr.u8[1]++;
533  if(uip_ds6_maddr_lookup(&data_addr)) {
534  LOG_DBG("Found higher scoped address in table\n");
535  break;
536  }
537  } while(data_addr.u8[1] <= 5);
538  if(data_addr.u8[1] > 5) {
539  LOG_ERR("Failed to find MPL domain data address in table\n");
540  return NULL;
541  }
542  } else {
543  memcpy(&data_addr, address, sizeof(uip_ip6addr_t));
544  memcpy(&ctrl_addr, address, sizeof(uip_ip6addr_t));
545  UIP_ADDR_MAKE_LINK_LOCAL(&ctrl_addr);
546  }
547  /* Now try the allocation */
548  for(locdsptr = &domain_set[MPL_DOMAIN_SET_SIZE - 1]; locdsptr >= domain_set; locdsptr--) {
549  if(!DOMAIN_SET_IS_USED(locdsptr)) {
550  if(!uip_ds6_maddr_lookup(&ctrl_addr) && !uip_ds6_maddr_add(&ctrl_addr)) {
551  LOG_ERR("Failed to subscribe to link local address for domain ");
552  LOG_ERR_6ADDR(address);
553  LOG_ERR_("\n");
554  return NULL;
555  }
556  memset(locdsptr, 0, sizeof(struct mpl_domain));
557  memcpy(&locdsptr->data_addr, &data_addr, sizeof(uip_ip6addr_t));
558  memcpy(&locdsptr->ctrl_addr, &ctrl_addr, sizeof(uip_ip6addr_t));
559  if(!trickle_timer_config(&locdsptr->tt,
560  MPL_CONTROL_MESSAGE_IMIN,
561  MPL_CONTROL_MESSAGE_IMAX,
562  MPL_CONTROL_MESSAGE_K)) {
563  LOG_ERR("Unable to configure trickle timer for domain. Dropping,...\n");
564  DOMAIN_SET_CLEAR_USED(locdsptr);
565  return NULL;
566  }
567  return locdsptr;
568  }
569  }
570  return NULL;
571 }
572 /* Lookup the seed id in the seed set */
573 static struct mpl_seed *
574 seed_set_lookup(seed_id_t *seed_id, struct mpl_domain *domain)
575 {
576  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
577  if(SEED_SET_IS_USED(locssptr) && seed_id_cmp(seed_id, &locssptr->seed_id) && locssptr->domain == domain) {
578  return locssptr;
579  }
580  }
581  return NULL;
582 }
583 static struct mpl_seed *
584 seed_set_allocate(void)
585 {
586  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
587  if(!SEED_SET_IS_USED(locssptr)) {
588  locssptr->count = 0;
589  LIST_STRUCT_INIT(locssptr, min_seq);
590  return locssptr;
591  }
592  }
593  return NULL;
594 }
595 static void
596 seed_set_free(struct mpl_seed *s)
597 {
598  while((locmmptr = list_pop(s->min_seq)) != NULL) {
599  buffer_free(locmmptr);
600  }
602 }
603 static struct mpl_domain *
604 domain_set_lookup(uip_ip6addr_t *domain)
605 {
606  for(locdsptr = &domain_set[MPL_DOMAIN_SET_SIZE - 1]; locdsptr >= domain_set; locdsptr--) {
607  if(DOMAIN_SET_IS_USED(locdsptr)) {
608  if(uip_ip6addr_cmp(domain, &locdsptr->data_addr)
609  || uip_ip6addr_cmp(domain, &locdsptr->ctrl_addr)) {
610  return locdsptr;
611  }
612  }
613  }
614  return NULL;
615 }
616 static void
617 domain_set_free(struct mpl_domain *domain)
618 {
620  /* Must include freeing seeds otherwise we leak memory */
621  for(locssptr = &seed_set[MPL_SEED_SET_SIZE]; locssptr >= seed_set; locssptr--) {
622  if(SEED_SET_IS_USED(locssptr) && locssptr->domain == domain) {
623  seed_set_free(locssptr);
624  }
625  }
626  addr = uip_ds6_maddr_lookup(&domain->data_addr);
627  if(addr != NULL) {
628  uip_ds6_maddr_rm(addr);
629  }
630  addr = uip_ds6_maddr_lookup(&domain->ctrl_addr);
631  if(addr != NULL) {
632  uip_ds6_maddr_rm(addr);
633  }
634  if(trickle_timer_is_running(&domain->tt)) {
635  trickle_timer_stop(&domain->tt);
636  }
637  DOMAIN_SET_CLEAR_USED(domain);
638 }
639 static void
640 seed_id_net_to_host(seed_id_t *dst, void *src, uint8_t s)
641 {
642  /**
643  * Convert a seed id in network order header format and length S to
644  * internal representation.
645  */
646  static uint8_t i;
647  static uint8_t *ptr;
648  ptr = src;
649  switch(s) {
650  case 0:
651  /* 128 bit seed ID from IPV6 Address */
652  dst->s = 0;
653  for(i = 0; i < 16; i++) {
654  dst->id[i] = ptr[15 - i];
655  }
656  return;
657  case 1:
658  /* 16 bit seed ID */
659  dst->s = 1;
660  for(i = 2; i < 15; i++) {
661  /* Clear the first 13 bytes in the id */
662  dst->id[i] = 0;
663  }
664  dst->id[0] = ptr[1];
665  dst->id[1] = ptr[0];
666  return;
667  case 2:
668  /* 64 bit Seed ID */
669  dst->s = 2;
670  for(i = 0; i < 8; i++) {
671  /* Reverse the byte order */
672  dst->id[i] = ptr[7 - i];
673  }
674  for(i = 8; i < 16; i++) {
675  /* Set the remainder to zero */
676  dst->id[i] = 0;
677  }
678  return;
679  case 3:
680  /* 128 bit seed ID */
681  dst->s = 3;
682  for(i = 0; i < 16; i++) {
683  dst->id[i] = ptr[15 - i];
684  }
685  return;
686  default:
687  /* Invalid seed size */
688  return;
689  }
690 }
691 static void
692 seed_id_host_to_net(void *dst, seed_id_t *src)
693 {
694  /**
695  * Convert a seed id from our internal representation to network
696  * order and representation based on length s.
697  */
698  static uint8_t i;
699  static uint8_t *ptr;
700  ptr = dst;
701  switch(src->s) {
702  case 0:
703  case 3:
704  /* Both use 128 bit seed IDs and do exactly the same thing */
705  for(i = 0; i < 16; i++) {
706  /* Byte order must be swapped */
707  ptr[i] = src->id[15 - i];
708  }
709  return;
710  case 1:
711  /* 16 bit seed id */
712  ptr[0] = src->id[1];
713  ptr[1] = src->id[0];
714  return;
715  case 2:
716  /* 64 bit Seed ID */
717  for(i = 0; i < 8; i++) {
718  ptr[i] = src->id[7 - i];
719  }
720  return;
721  default:
722  /* Invalid seed size */
723  return;
724  }
725 }
726 static void
727 update_seed_id(void)
728 {
729  /* Load my seed ID into memory */
730 #if MPL_SEED_ID_TYPE == 0
731  /* Copy seed ID from out link local ip address */
732  static uip_ds6_addr_t *my_ip6_addr;
733  my_ip6_addr = uip_ds6_get_global(ADDR_PREFERRED);
734  if(my_ip6_addr != NULL) {
735  seed_id_net_to_host(&local_seed_id, &my_ip6_addr->ipaddr, 0);
736  } else {
737  local_seed_id.s = MPL_SEED_ID_UNKNOWN;
738  LOG_DBG("Seed id not yet known.\n");
739  return;
740  }
741 #elif MPL_SEED_ID_TYPE == 1
742  /* 16 bit seed id */
743  SEED_ID_S1(&local_seed_id, MPL_SEED_ID_L);
744 #elif MPL_SEED_ID_TYPE == 2
745  /* 64 bit seed id */
746  SEED_ID_S2(&local_seed_id, MPL_SEED_ID_L);
747 #elif MPL_SEED_ID_TYPE == 3
748  /* 128 bit seed id */
749  SEED_ID_S3(&local_seed_id, MPL_SEED_ID_L, MPL_SEED_ID_H);
750 #endif
751 
752  LOG_DBG("My seed id is ");
753  LOG_DBG_SEED(local_seed_id);
754  LOG_DBG_(" with S=%u\n", local_seed_id.s);
755 }
756 void
757 icmp_out(struct mpl_domain *dom)
758 {
759  uint8_t vector[32];
760  uint8_t vec_size;
761  uint8_t vec_len;
762  uint8_t cur_seq;
763  uint16_t payload_len;
765  size_t seed_info_len;
766 
767  LOG_INFO("MPL Control Message Out\n");
768 
769  UIP_IP_BUF->vtc = 0x60;
770  UIP_IP_BUF->tcflow = 0;
771  UIP_IP_BUF->flow = 0;
772  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
774 
775  locsiptr = (struct seed_info *)UIP_ICMP_PAYLOAD;
776  payload_len = 0;
777 
778  /* Set the source address to link local for now. If we need to, we can try changing it to global later */
779  uip_ip6addr_copy(&UIP_IP_BUF->destipaddr, &dom->ctrl_addr);
780  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
781 
782  /* Iterate over seed set to create payload */
783  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
784  if(SEED_SET_IS_USED(locssptr) && locssptr->domain == dom) {
785  locsiptr->min_seqno = locssptr->min_seqno;
786  SEED_INFO_CLR_LEN(locsiptr);
787  SEED_INFO_CLR_S(locsiptr);
788 
789  /* Try setting our source address to global */
790  addr = uip_ds6_get_global(ADDR_PREFERRED);
791  if(addr) {
792  uip_ip6addr_copy(&UIP_IP_BUF->srcipaddr, &addr->ipaddr);
793  } else {
794  /* Failed setting a global ip address, fallback to link local */
795  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
796  if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
797  LOG_ERR("icmp out: Cannot set src ip\n");
798  uipbuf_clear();
799  return;
800  }
801  }
802 
803  /* Set the Seed ID */
804  switch(locssptr->seed_id.s) {
805  case 0:
806  if(uip_ip6addr_cmp((uip_ip6addr_t *)&locssptr->seed_id.id, &UIP_IP_BUF->srcipaddr)) {
807  /* We can use an S=0 Seed ID */
808  SEED_INFO_SET_LEN(locsiptr, 0);
809  break;
810  } /* Else fall down into the S = 3 case */
811  case 3:
812  seed_id_host_to_net(&((struct seed_info_s3 *)locsiptr)->seed_id, &locssptr->seed_id);
813  SEED_INFO_SET_S(locsiptr, 3);
814  break;
815  case 1:
816  seed_id_host_to_net(&((struct seed_info_s1 *)locsiptr)->seed_id, &locssptr->seed_id);
817  SEED_INFO_SET_S(locsiptr, 1);
818  break;
819  case 2:
820  seed_id_host_to_net(&((struct seed_info_s2 *)locsiptr)->seed_id, &locssptr->seed_id);
821  SEED_INFO_SET_S(locsiptr, 2);
822  break;
823  }
824 
825  /* Populate the seed info message vector */
826  memset(vector, 0, sizeof(vector));
827  vec_len = 0;
828  cur_seq = 0;
829  LOG_INFO("\nBuffer for seed: ");
830  LOG_INFO_SEED(locssptr->seed_id);
831  LOG_INFO_("\n");
832  for(locmmptr = list_head(locssptr->min_seq); locmmptr != NULL; locmmptr = list_item_next(locmmptr)) {
833  LOG_INFO("%d -- %x\n", locmmptr->seq, locmmptr->data[locmmptr->size - 1]);
834  cur_seq = SEQ_VAL_ADD(locssptr->min_seqno, vec_len);
835  if(locmmptr->seq == SEQ_VAL_ADD(locssptr->min_seqno, vec_len)) {
836  BIT_VECTOR_SET_BIT(vector, vec_len);
837  vec_len++;
838  } else {
839  /* Insert enough zeros to get to the next message */
840  vec_len += locmmptr->seq - cur_seq;
841  BIT_VECTOR_SET_BIT(vector, vec_len);
842  vec_len++;
843  }
844  }
845 
846  /* Convert vector length from bits to bytes */
847  vec_size = (vec_len - 1) / 8 + 1;
848 
849  SEED_INFO_SET_LEN(locsiptr, vec_size);
850 
851  LOG_DBG("--- Control Message Entry ---\n");
852  LOG_DBG("Seed ID: ");
853  LOG_DBG_SEED(locssptr->seed_id);
854  LOG_DBG_("\n");
855  LOG_DBG("S=%u\n", locssptr->seed_id.s);
856  LOG_DBG("Min Sequence Number: %u\n", locssptr->min_seqno);
857  LOG_DBG("Size of message set: %u\n", vec_len);
858  LOG_DBG("Vector is %u bytes\n", vec_size);
859 
860  /* Copy vector into payload and point ptr to next location */
861  switch(SEED_INFO_GET_S(locsiptr)) {
862  case 0:
863  seed_info_len = sizeof(struct seed_info);
864  break;
865  case 1:
866  seed_info_len = sizeof(struct seed_info_s1);
867  break;
868  case 2:
869  seed_info_len = sizeof(struct seed_info_s2);
870  break;
871  case 3:
872  seed_info_len = sizeof(struct seed_info_s3);
873  break;
874  }
875  memcpy(((void *)locsiptr) + seed_info_len, vector, vec_size);
876  locsiptr = ((void *)locsiptr) + seed_info_len + vec_size;
877  payload_len += seed_info_len + vec_size;
878  }
879  /* Now go to next seed in set */
880  }
881  LOG_DBG("--- End of Messages --\n");
882 
883  /* Finish off construction of ICMP Packet */
884  uipbuf_set_len_field(UIP_IP_BUF, UIP_ICMPH_LEN + payload_len);
885  UIP_ICMP_BUF->type = ICMP6_MPL;
886  UIP_ICMP_BUF->icode = 0;
887  uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
888  UIP_ICMP_BUF->icmpchksum = 0;
889  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
890 
891  LOG_DBG("ICMP Out from ");
892  LOG_DBG_6ADDR(&UIP_IP_BUF->srcipaddr);
893  LOG_DBG_(" to ");
894  LOG_DBG_6ADDR(&UIP_IP_BUF->destipaddr);
895  LOG_DBG_("\n");
896 
897  LOG_DBG("MPL Contol Message Out - %u bytes\n", payload_len);
898 
900  uipbuf_clear();
901  MPL_STATS_ADD(icmp_out);
902  return;
903 }
904 static void
905 data_message_expiration(void *ptr, uint8_t suppress)
906 {
907  /* Callback for data message trickle timers */
908  locmmptr = ((struct mpl_msg *)ptr);
909  if(locmmptr->e > MPL_DATA_MESSAGE_TIMER_EXPIRATIONS) {
910  /* Terminate the trickle timer here if we've already expired enough times */
911  trickle_timer_stop(&locmmptr->tt);
912  return;
913  }
914  if(suppress == TRICKLE_TIMER_TX_OK) { /* Only transmit if not suppressed */
915  LOG_DBG("Data message TX\n");
916  LOG_DBG("Seed ID=");
917  LOG_DBG_SEED(locmmptr->seed->seed_id);
918  LOG_DBG_(", S=%u, Seq=%u\n", locmmptr->seed->seed_id.s, locmmptr->seq);
919  /* Setup the IP Header */
920  UIP_IP_BUF->vtc = 0x60;
921  UIP_IP_BUF->tcflow = 0;
922  UIP_IP_BUF->flow = 0;
923  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
924  /*UIP_IP_BUF->ttl = MPL_IP_HOP_LIMIT; */
925  uip_ip6addr_copy(&UIP_IP_BUF->destipaddr, &locmmptr->seed->domain->data_addr);
926  uip_len = UIP_IPH_LEN;
927  /* Setup the HBHO Header */
928  UIP_EXT_BUF->next = UIP_PROTO_UDP;
929  lochbhmptr = UIP_EXT_OPT_FIRST;
930  lochbhmptr->type = HBHO_OPT_TYPE_MPL;
931  lochbhmptr->flags = 0x00;
932  switch(locmmptr->seed->seed_id.s) {
933  case 0:
934  UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
935  lochbhmptr->len = MPL_OPT_LEN_S0;
936  HBH_CLR_S(lochbhmptr);
937  HBH_SET_S(lochbhmptr, 0);
938  uip_len += HBHO_BASE_LEN + HBHO_S0_LEN;
939  uip_ext_len += HBHO_BASE_LEN + HBHO_S0_LEN;
940  lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
941  lochbhmptr->padn.opt_len = 0x00;
942  break;
943  case 1:
944  UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
945  lochbhmptr->len = MPL_OPT_LEN_S1;
946  HBH_CLR_S(lochbhmptr);
947  HBH_SET_S(lochbhmptr, 1);
948  seed_id_host_to_net(&((struct mpl_hbho_s1 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
949  uip_len += HBHO_BASE_LEN + HBHO_S1_LEN;
950  uip_ext_len += HBHO_BASE_LEN + HBHO_S1_LEN;
951  break;
952  case 2:
953  UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
954  lochbhmptr->len = MPL_OPT_LEN_S2;
955  HBH_CLR_S(lochbhmptr);
956  HBH_SET_S(lochbhmptr, 2);
957  seed_id_host_to_net(&((struct mpl_hbho_s2 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
958  uip_len += HBHO_BASE_LEN + HBHO_S2_LEN;
959  uip_ext_len += HBHO_BASE_LEN + HBHO_S2_LEN;
960  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
961  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
962  break;
963  case 3:
964  UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
965  lochbhmptr->len = MPL_OPT_LEN_S3;
966  HBH_CLR_S(lochbhmptr);
967  HBH_SET_S(lochbhmptr, 3);
968  seed_id_host_to_net(&((struct mpl_hbho_s3 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
969  uip_len += HBHO_BASE_LEN + HBHO_S3_LEN;
970  uip_ext_len += HBHO_BASE_LEN + HBHO_S3_LEN;
971  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
972  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
973  break;
974  }
975  lochbhmptr->seq = locmmptr->seq;
976  if(list_item_next(locmmptr) == NULL) {
977  HBH_SET_M(lochbhmptr);
978  }
979  /* Now insert payload */
980  memcpy(((void *)UIP_EXT_BUF) + 8 + UIP_EXT_BUF->len * 8, &locmmptr->data, locmmptr->size);
981  uip_len += locmmptr->size;
982  uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
983  uip_ip6addr_copy(&UIP_IP_BUF->srcipaddr, &locmmptr->srcipaddr);
984  tcpip_output(NULL);
985  uipbuf_clear();
986  UIP_MCAST6_STATS_ADD(mcast_out);
987  }
988 
989  locmmptr->e++;
990 }
991 static void
992 control_message_expiration(void *ptr, uint8_t suppress)
993 {
994  /* Control message timer callback */
995  locdsptr = ((struct mpl_domain *)ptr);
996  if(locdsptr->e > MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS) {
997  /* Disable the trickle timer for now */
998  trickle_timer_stop(&locdsptr->tt);
999  return;
1000  }
1001  if(suppress == TRICKLE_TIMER_TX_OK) {
1002  /* Send an MPL Control Message */
1003  icmp_out(locdsptr);
1004  }
1005  locdsptr->e++;
1006 }
1007 static void
1008 mpl_maddr_check(void)
1009 {
1010  /* Check for new multicast addresses that aren't in our domain set */
1011  uip_ds6_maddr_t *elem;
1012  for(elem = &uip_ds6_if.maddr_list[UIP_DS6_MADDR_NB - 1];
1013  elem >= uip_ds6_if.maddr_list;
1014  elem--) {
1015  if(elem->isused && uip_mcast6_get_address_scope(&elem->ipaddr) > UIP_MCAST6_SCOPE_LINK_LOCAL) {
1016  locdsptr = domain_set_lookup(&elem->ipaddr);
1017  if(!locdsptr) {
1018  locdsptr = domain_set_allocate(&elem->ipaddr);
1019  if(!locdsptr) {
1020  LOG_ERR("Failed to allocate domain set in mpl_maddr_check()\n");
1021  }
1022  }
1023  }
1024  }
1025  /* Check for domain set addresses that aren't in our maddr table */
1026  for(locdsptr = &domain_set[MPL_DOMAIN_SET_SIZE - 1]; locdsptr >= domain_set; locdsptr--) {
1027  if(DOMAIN_SET_IS_USED(locdsptr) && !uip_ds6_maddr_lookup(&locdsptr->data_addr)) {
1028  domain_set_free(locdsptr);
1029  }
1030  }
1031 }
1032 static void
1033 lifetime_timer_expiration(void *ptr)
1034 {
1035  /* Called once per minute to decrement seed lifetime counters */
1036  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; seed_set <= locssptr; locssptr--) {
1037  if(SEED_SET_IS_USED(locssptr) && locssptr->lifetime == 0) {
1038  /* Check no timers are running */
1039  locmmptr = list_head(locssptr->min_seq);
1040  while(locmmptr != NULL) {
1041  if(trickle_timer_is_running(&locmmptr->tt)) {
1042  /* We must keep this seed */
1043  break;
1044  }
1045  locmmptr = list_item_next(locmmptr);
1046  }
1047  if(locmmptr == NULL) {
1048  /* We can now free this seed set */
1049  LOG_INFO("Seed ");
1050  LOG_INFO_SEED(locssptr->seed_id);
1051  LOG_INFO_(" expired. Freeing...\n");
1052  seed_set_free(locssptr);
1053  }
1054  }
1055  if(locssptr->lifetime > 0) {
1056  locssptr->lifetime--;
1057  }
1058  }
1059  mpl_maddr_check();
1060  ctimer_reset(&lifetime_timer);
1061 }
1062 static void
1063 icmp_in(void)
1064 {
1065  static seed_id_t seed_id;
1066  static uint8_t r;
1067  static uint8_t *vector;
1068  static uint8_t vector_len;
1069  static uint8_t r_missing;
1070  static uint8_t l_missing;
1071 
1072  LOG_INFO("MPL ICMP Control Message In\n");
1073 
1074 #if UIP_CONF_IPV6_CHECKS
1075  if(!uip_is_addr_mcast_non_routable(&UIP_IP_BUF->destipaddr)) {
1076  LOG_ERR("ICMPv6 In, bad dest ");
1077  LOG_ERR_6ADDR(&UIP_IP_BUF->destipaddr);
1078  LOG_ERR_("\n");
1079  MPL_STATS_ADD(icmp_bad);
1080  goto discard;
1081  }
1082 
1083  if(UIP_ICMP_BUF->type != ICMP6_MPL) {
1084  LOG_ERR("ICMPv6 In, bad ICMP type\n");
1085  MPL_STATS_ADD(icmp_bad);
1086  goto discard;
1087  }
1088 
1089  if(UIP_ICMP_BUF->icode != 0) {
1090  LOG_ERR("ICMPv6 In, bad ICMP type\n");
1091  MPL_STATS_ADD(icmp_bad);
1092  goto discard;
1093  }
1094 
1095  if(UIP_IP_BUF->ttl != MPL_IP_HOP_LIMIT) {
1096  LOG_ERR("ICMPv6 In, bad TTL\n");
1097  MPL_STATS_ADD(icmp_bad);
1098  goto discard;
1099  }
1100 #endif
1101 
1102  LOG_INFO("MPL ICMP Control Message from ");
1103  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
1104  LOG_INFO_(" len %u, ext %u\n", uip_len, uip_ext_len);
1105 
1106  MPL_STATS_ADD(icmp_in);
1107 
1108  /* Find the domain that this has come from */
1109  locdsptr = domain_set_lookup(&UIP_IP_BUF->destipaddr);
1110 
1111  if(!locdsptr) {
1112  LOG_INFO("New MPL Domain ");
1113  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
1114  LOG_INFO_("\n");
1115  locdsptr = domain_set_allocate(&UIP_IP_BUF->destipaddr);
1116  if(!locdsptr) {
1117  LOG_ERR("Couldn't allocate new domain. Dropping.\n");
1118  UIP_MCAST6_STATS_ADD(icmp_bad);
1119  goto discard;
1120  }
1122  }
1123  l_missing = 0;
1124  r_missing = 0;
1125 
1126  /* Iterate over our seed set and check all are present in the remote seed sed */
1127  locsiptr = (struct seed_info *)UIP_ICMP_PAYLOAD;
1128  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
1129  if(SEED_SET_IS_USED(locssptr) && locssptr->domain == locdsptr) {
1130  LOG_DBG("Checking remote for seed ");
1131  LOG_DBG_SEED(locssptr->seed_id);
1132  LOG_DBG_("\n");
1133  while(locsiptr <
1134  (struct seed_info *)((void *)UIP_ICMP_PAYLOAD + uip_len - uip_l3_icmp_hdr_len)) {
1135  switch(SEED_INFO_GET_S(locsiptr)) {
1136  case 0:
1137  seed_id_net_to_host(&seed_id, &UIP_IP_BUF->srcipaddr, 0);
1138  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info) + SEED_INFO_GET_LEN(locsiptr);
1139  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1140  goto seed_present;
1141  }
1142  break;
1143  case 1:
1144  seed_id_net_to_host(&seed_id, &((struct seed_info_s1 *)locsiptr)->seed_id, 1);
1145  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s1) + SEED_INFO_GET_LEN(locsiptr);
1146  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1147  goto seed_present;
1148  }
1149  break;
1150  case 2:
1151  seed_id_net_to_host(&seed_id, &((struct seed_info_s2 *)locsiptr)->seed_id, 2);
1152  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s2) + SEED_INFO_GET_LEN(locsiptr);
1153  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1154  goto seed_present;
1155  }
1156  break;
1157  case 3:
1158  seed_id_net_to_host(&seed_id, &((struct seed_info_s3 *)locsiptr)->seed_id, 3);
1159  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s3) + SEED_INFO_GET_LEN(locsiptr);
1160  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1161  goto seed_present;
1162  }
1163  break;
1164  }
1165  }
1166  /* If we made it this far, the seed is missing from the remote. Reset all message timers */
1167  LOG_DBG("Remote is missing seed ");
1168  LOG_DBG_SEED(locssptr->seed_id);
1169  LOG_DBG_("\n");
1170  r_missing = 1;
1171  if(list_head(locssptr->min_seq) != NULL) {
1172  for(locmmptr = list_head(locssptr->min_seq); locmmptr != NULL; locmmptr = list_item_next(locmmptr)) {
1173  LOG_DBG("Resetting timer for messages\n");
1174  if(!trickle_timer_is_running(&locmmptr->tt)) {
1175  LOG_DBG("Starting timer for messages\n");
1176  mpl_data_trickle_timer_start(locmmptr);
1177  }
1179  }
1180  }
1181  /* Otherwise we jump here and continute */
1182 seed_present:
1183  continue;
1184  }
1185  }
1186 
1187  /* Iterate over remote seed info and they're present locally. Additionally check messages match */
1188  locsiptr = (struct seed_info *)UIP_ICMP_PAYLOAD;
1189  while(locsiptr <
1190  (struct seed_info *)((void *)UIP_ICMP_PAYLOAD + uip_len - uip_l3_icmp_hdr_len)) {
1191  /* Extract the seed id */
1192  if(SEED_INFO_GET_S(locsiptr) > 0) {
1193  seed_id_net_to_host(&seed_id, &((struct seed_info_s1 *)locsiptr)->seed_id, SEED_INFO_GET_S(locsiptr));
1194  } else {
1195  /* Always set as S3 because it will never be us */
1196  seed_id_net_to_host(&seed_id, &UIP_IP_BUF->srcipaddr, 3);
1197  }
1198 
1199  LOG_DBG("Control Message for Seed Id: ");
1200  LOG_DBG_SEED(seed_id);
1201  LOG_DBG_("Min Seq Number: %u, %u bytes\n", locsiptr->min_seqno, SEED_INFO_GET_LEN(locsiptr));
1202 
1203  /* Do we have this seed? */
1204  locssptr = seed_set_lookup(&seed_id, locdsptr);
1205  if(!locssptr) {
1206  LOG_DBG("Unknown seed in seed info\n");
1207  /* We don't know this seed */
1208  l_missing = 1;
1209  goto next;
1210  }
1211 
1212  /* Work out where remote bit vector starts */
1213  vector_len = SEED_INFO_GET_LEN(locsiptr) * 8;
1214  switch(SEED_INFO_GET_S(locsiptr)) {
1215  case 0:
1216  vector = ((void *)locsiptr) + sizeof(struct seed_info);
1217  break;
1218  case 1:
1219  vector = ((void *)locsiptr) + sizeof(struct seed_info_s1);
1220  break;
1221  case 2:
1222  vector = ((void *)locsiptr) + sizeof(struct seed_info_s2);
1223  break;
1224  case 3:
1225  vector = ((void *)locsiptr) + sizeof(struct seed_info_s3);
1226  break;
1227  }
1228 
1229  /* Potential quick resolution here */
1230  locmmptr = list_head(locssptr->min_seq);
1231  if(locmmptr == NULL) {
1232  /* We have nothing! */
1233  if(vector[0] > 0) {
1234  /* They have something! */
1235  l_missing = 1;
1236  }
1237  goto next;
1238  }
1239  /**
1240  * Work out what offset the local or remote message set need so that the
1241  * sequence numbers match up
1242  */
1243  r = 0;
1244  if(locmmptr->seq != locsiptr->min_seqno) {
1245  if(SEQ_VAL_IS_GT(locmmptr->seq, locsiptr->min_seqno)) {
1246  while(locmmptr->seq != SEQ_VAL_ADD(locsiptr->min_seqno, r) && r <= vector_len) {
1247  r++;
1248  }
1249  } else {
1250  while(locmmptr != NULL && locmmptr->seq != locsiptr->min_seqno) {
1251  locmmptr = list_item_next(locmmptr);
1252  }
1253  }
1254 
1255  /* There is no overlap in message sets */
1256  if(r > vector_len || locmmptr == NULL) {
1257  LOG_WARN("Seed sets of local and remote have no overlap.\n");
1258  /* Work out who is behind who */
1259  locmmptr = list_head(locssptr->min_seq);
1260  while(list_item_next(locmmptr) != NULL) {
1261  locmmptr = list_item_next(locmmptr);
1262  }
1263  r = vector_len;
1264  while(!BIT_VECTOR_GET_BIT(vector, r)) {
1265  r--;
1266  }
1267  if(SEQ_VAL_IS_GT(locmmptr->seq, SEQ_VAL_ADD(locsiptr->min_seqno, r))) {
1268  /* Our max sequence number is greater than their max sequence number */
1269  LOG_DBG("Our max sequence number is greater than their max sequence number\n");
1270  r_missing = 1;
1271  /* Additionally all data message timers in set if r is behind us */
1272  if(list_head(locssptr->min_seq) != NULL) {
1273  for(locmmptr = list_head(locssptr->min_seq); locmmptr != NULL; locmmptr = list_item_next(locmmptr)) {
1274  if(!trickle_timer_is_running(&locmmptr->tt)) {
1275  mpl_data_trickle_timer_start(locmmptr);
1276  }
1278  }
1279  }
1280  } else {
1281  l_missing = 1;
1282  }
1283  goto next;
1284  }
1285  }
1286 
1287  /**
1288  * If we've made it this far, our sets overlap and we can work out specific
1289  * messages that may be missing from each set.
1290  */
1291  do {
1292  /* This won't occur on first iteration */
1293  /* Resyncronise our pointers to local and remote messages after previous iteration */
1294  while(locmmptr->seq != SEQ_VAL_ADD(locsiptr->min_seqno, r)) {
1295  /**
1296  * If we enter this loop it means there is a gap in local sequence numbers.
1297  * Check that same gap exists in the remote set.
1298  */
1299  if(BIT_VECTOR_GET_BIT(vector, r)) {
1300  /* We are missing a message. Reset timer */
1301  LOG_DBG("We are missing seq=%u\n", SEQ_VAL_ADD(locsiptr->min_seqno, r));
1302  l_missing = 1;
1303  }
1304  r++;
1305  }
1306  /* At this point the local pointer and remote pointer will be in sync */
1307 
1308  /* Check whether the remote is missing the current message */
1309  if(!BIT_VECTOR_GET_BIT(vector, r)) {
1310  /* Local message is missing from remote set. Reset control and data timers */
1311  LOG_DBG("Remote is missing seq=%u\n", locmmptr->seq);
1312  r_missing = 1;
1313  if(!trickle_timer_is_running(&locmmptr->tt)) {
1314  mpl_data_trickle_timer_start(locmmptr);
1315  }
1317  }
1318 
1319  /* Now increment our pointers */
1320  r++;
1321  locmmptr = list_item_next(locmmptr);
1322  /* These are then resyncronised at the top of the loop */
1323  } while(locmmptr != NULL && r <= vector_len);
1324 
1325  /* If we have stopped short of either message set then we may have inconsistencies */
1326  if(locmmptr != NULL || r < vector_len) {
1327  /**
1328  * We have reached the end of local set, the remainder of the remote set should
1329  * be zero else local is missing a message.
1330  */
1331  while(r < vector_len) {
1332  if(BIT_VECTOR_GET_BIT(vector, r)) {
1333  /* We are missing a message */
1334  LOG_DBG("We are missing seq=%u which is greater than our max seq number\n", SEQ_VAL_ADD(locsiptr->min_seqno, r));
1335  l_missing = 1;
1336  }
1337  r++;
1338  }
1339  } else if(r >= vector_len && locmmptr != NULL) {
1340  /* We have reached the end of the remote set.
1341  * Any remaining messages are missing and should be reset.
1342  */
1343  while(locmmptr != NULL) {
1344  LOG_DBG("Remote is missing all above seq=%u\n", locmmptr->seq);
1345  if(!trickle_timer_is_running(&locmmptr->tt)) {
1346  mpl_data_trickle_timer_start(locmmptr);
1347  }
1349  r_missing = 1;
1350  locmmptr = list_item_next(locmmptr);
1351  }
1352  }
1353  /* Now point to next seed info */
1354 next:
1355  switch(SEED_INFO_GET_S(locsiptr)) {
1356  case 0:
1357  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info) + SEED_INFO_GET_LEN(locsiptr);
1358  break;
1359  case 1:
1360  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s1) + SEED_INFO_GET_LEN(locsiptr);
1361  break;
1362  case 2:
1363  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s2) + SEED_INFO_GET_LEN(locsiptr);
1364  break;
1365  case 3:
1366  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s3) + SEED_INFO_GET_LEN(locsiptr);
1367  break;
1368  }
1369  }
1370 
1371  /* Now sort out control message timers */
1372  if(l_missing && !trickle_timer_is_running(&locdsptr->tt)) {
1374  }
1375  if(l_missing || r_missing) {
1376  LOG_INFO("Inconsistency detected l=%u, r=%u\n", l_missing, r_missing);
1377  if(trickle_timer_is_running(&locdsptr->tt)) {
1379  }
1380  } else {
1381  LOG_INFO("Domain is consistent \n");
1382  trickle_timer_consistency(&locdsptr->tt);
1383  }
1384 
1385 discard:
1386  uip_len = 0;
1387  uipbuf_clear();
1388  return;
1389 }
1390 static uint8_t
1391 accept(uint8_t in)
1392 {
1393  static seed_id_t seed_id;
1394  static uint16_t seq_val;
1395  static uint8_t S;
1396  static struct mpl_msg *mmiterptr;
1397  static struct uip_ext_hdr *hptr;
1398 
1399  LOG_INFO("Multicast I/O\n");
1400 
1401 #if UIP_CONF_IPV6_CHECKS
1402  if(uip_is_addr_mcast_non_routable(&UIP_IP_BUF->destipaddr)) {
1403  LOG_ERR("Mcast I/O, bad destination\n");
1404  UIP_MCAST6_STATS_ADD(mcast_bad);
1405  return UIP_MCAST6_DROP;
1406  }
1407  /*
1408  * Abort transmission if the v6 src is unspecified. This may happen if the
1409  * seed tries to TX while it's still performing DAD or waiting for a prefix
1410  */
1411  if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
1412  LOG_ERR("Mcast I/O, bad source\n");
1413  UIP_MCAST6_STATS_ADD(mcast_bad);
1414  return UIP_MCAST6_DROP;
1415  }
1416 #endif
1417 
1418  if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr) && in == MPL_DGRAM_IN) {
1419  LOG_WARN("Received message from ourselves.\n");
1420  return UIP_MCAST6_DROP;
1421  }
1422 
1423  /* Check the Next Header field: Must be HBHO */
1424  if(UIP_IP_BUF->proto != UIP_PROTO_HBHO) {
1425  LOG_ERR("Mcast I/O, bad proto\n");
1426  LOG_DBG("Next Proto was %u\n", UIP_IP_BUF->proto);
1427  UIP_MCAST6_STATS_ADD(mcast_bad);
1428  return UIP_MCAST6_DROP;
1429  } else {
1430  /* Check the Option Type */
1431  if(UIP_EXT_OPT_FIRST->type != HBHO_OPT_TYPE_MPL) {
1432  LOG_ERR("Mcast I/O, bad HBHO type\n");
1433  UIP_MCAST6_STATS_ADD(mcast_bad);
1434  return UIP_MCAST6_DROP;
1435  }
1436  }
1437  lochbhmptr = UIP_EXT_OPT_FIRST;
1438 
1439  LOG_DBG("HBHO T=%u, L=%u, M=%u, V=%u, S=%u, SEQ=0x%x\n",
1440  lochbhmptr->type, lochbhmptr->len, HBH_GET_M(lochbhmptr),
1441  HBH_GET_V(lochbhmptr), HBH_GET_S(lochbhmptr),
1442  lochbhmptr->seq);
1443 
1444 #if UIP_MCAST6_STATS
1445  if(in == MPL_DGRAM_IN) {
1446  UIP_MCAST6_STATS_ADD(mcast_in_all);
1447  }
1448 #endif
1449  /* Do a check on the V bit */
1450  if(HBH_GET_V(lochbhmptr)) {
1451  /* The V bit MUST be zero otherwise we drop the message */
1452  LOG_ERR("Invalid V bit - dropping...\n");
1453  return UIP_MCAST6_DROP;
1454  }
1455  /* Is this for a known seed and domain? */
1456  S = HBH_GET_S(lochbhmptr);
1457  LOG_DBG("Incoming message S value = %u\n", S);
1458 
1459  if(S == 0) {
1460  /* Seed ID is the IPV6 Source Address */
1461  seed_id_net_to_host(&seed_id, &UIP_IP_BUF->srcipaddr, S);
1462  } else {
1463  /**
1464  * Seed ID is embedded in the header where padding would otherwise be.
1465  * Since we're only interested in the address the specific s1/s2/s3
1466  * type doesn't matter.
1467  */
1468  seed_id_net_to_host(&seed_id, &((struct mpl_hbho_s1 *)lochbhmptr)->seed_id, S);
1469  }
1470 
1471  LOG_DBG("MPL Domain is ");
1472  LOG_DBG_6ADDR(&UIP_IP_BUF->destipaddr);
1473  LOG_DBG_("\n");
1474 
1475  /* First check the MPL Domain */
1476  locdsptr = domain_set_lookup(&UIP_IP_BUF->destipaddr);
1477 
1478  if(!locdsptr) {
1479  locdsptr = domain_set_allocate(&UIP_IP_BUF->destipaddr);
1480  LOG_INFO("New MPL Domain ");
1481  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
1482  LOG_INFO_("\n");
1483  if(!locdsptr) {
1484  LOG_ERR("Couldn't add to MPL Domain Set. Dropping.\n");
1485  UIP_MCAST6_STATS_ADD(mcast_dropped);
1486  return UIP_MCAST6_DROP;
1487  }
1488 
1489  /* Setup new MPL Domain */
1490  if(!trickle_timer_config(&locdsptr->tt,
1491  MPL_CONTROL_MESSAGE_IMIN,
1492  MPL_CONTROL_MESSAGE_IMAX,
1493  MPL_CONTROL_MESSAGE_K)) {
1494  LOG_ERR("Unable to configure trickle timer for domain. Dropping,...\n");
1495  domain_set_free(locdsptr);
1496  return UIP_MCAST6_DROP;
1497  }
1498  }
1499 
1500  /* Now lookup this seed */
1501  locssptr = seed_set_lookup(&seed_id, locdsptr);
1502 
1503  seq_val = lochbhmptr->seq;
1504 
1505  if(locssptr) {
1506  if(SEQ_VAL_IS_LT(seq_val, locssptr->min_seqno)) {
1507  /* Too old, drop */
1508  LOG_INFO("Too old\n");
1509  UIP_MCAST6_STATS_ADD(mcast_dropped);
1510  return UIP_MCAST6_DROP;
1511  }
1512  if(list_head(locssptr->min_seq) != NULL) {
1513  for(locmmptr = list_head(locssptr->min_seq); locmmptr != NULL; locmmptr = list_item_next(locmmptr)) {
1514  if(SEQ_VAL_IS_EQ(seq_val, locmmptr->seq)) {
1515  /* Seen before , drop */
1516  LOG_INFO("Seen before\n");
1517  if(HBH_GET_M(lochbhmptr) && list_item_next(locmmptr) != NULL) {
1519  } else {
1520  trickle_timer_consistency(&locmmptr->tt);
1521  }
1522  UIP_MCAST6_STATS_ADD(mcast_dropped);
1523  return UIP_MCAST6_DROP;
1524  }
1525  }
1526  }
1527  }
1528  /* We have not seen this message before */
1529 
1530  /* Allocate a seed set if we have to */
1531  if(!locssptr) {
1532  locssptr = seed_set_allocate();
1533  LOG_INFO("New seed\n");
1534  if(!locssptr) {
1535  /* Couldn't allocate seed set, drop */
1536  LOG_ERR("Failed to allocate seed set\n");
1537  UIP_MCAST6_STATS_ADD(mcast_dropped);
1538  return UIP_MCAST6_DROP;
1539  }
1540  memset(locssptr, 0, sizeof(struct mpl_seed));
1541  LIST_STRUCT_INIT(locssptr, min_seq);
1542  seed_id_cpy(&locssptr->seed_id, &seed_id);
1543  locssptr->domain = locdsptr;
1544  }
1545 
1546  /* Allocate a buffer */
1547  locmmptr = buffer_allocate();
1548  if(!locmmptr) {
1549  LOG_INFO("Buffer allocation failed. Reclaiming...\n");
1550  locmmptr = buffer_reclaim();
1551  if(!locmmptr) {
1552  LOG_ERR("Buffer reclaim failed. Dropping...\n");
1553  UIP_MCAST6_STATS_ADD(mcast_dropped);
1554  return UIP_MCAST6_DROP;
1555  }
1556  }
1557 
1558  /* We have a domain set, a seed set, and we have a buffer. Accept this message */
1559  LOG_INFO("Message from seed ");
1560  LOG_INFO_SEED(locssptr->seed_id);
1561  LOG_INFO_("\n");
1562 
1563  /* Set the source IP of the message */
1564  uip_ip6addr_copy(&locmmptr->srcipaddr, &UIP_IP_BUF->srcipaddr);
1565 
1566 #if UIP_MCAST6_STATS
1567  if(in == MPL_DGRAM_IN) {
1568  UIP_MCAST6_STATS_ADD(mcast_in_unique);
1569  }
1570 #endif
1571 
1572  /* Find the start of the payload */
1573  hptr = (struct uip_ext_hdr *)UIP_EXT_BUF;
1574  while(hptr->next != UIP_PROTO_UDP) {
1575  hptr = ((void *)hptr) + hptr->len * 8 + 8;
1576  }
1577  hptr = ((void *)hptr) + hptr->len * 8 + 8;
1578  locmmptr->size = uip_len - UIP_IPH_LEN - uip_ext_len;
1579  memcpy(&locmmptr->data, hptr, locmmptr->size);
1580  locmmptr->seq = seq_val;
1581  locmmptr->seed = locssptr;
1582  if(!trickle_timer_config(&locmmptr->tt,
1583  MPL_DATA_MESSAGE_IMIN,
1584  MPL_DATA_MESSAGE_IMAX,
1585  MPL_DATA_MESSAGE_K)) {
1586  LOG_ERR("Failed to configure timer for message. Dropping...\n");
1587  buffer_free(locmmptr);
1588  return UIP_MCAST6_DROP;
1589  }
1590 
1591  /* Place the message into the buffered message linked list */
1592  if(list_head(locssptr->min_seq) == NULL) {
1593  list_push(locssptr->min_seq, locmmptr);
1594  locssptr->min_seqno = locmmptr->seq;
1595  } else {
1596  for(mmiterptr = list_head(locssptr->min_seq); mmiterptr != NULL; mmiterptr = list_item_next(mmiterptr)) {
1597  if(list_item_next(mmiterptr) == NULL
1598  || (SEQ_VAL_IS_GT(locmmptr->seq, mmiterptr->seq) && SEQ_VAL_IS_LT(locmmptr->seq, ((struct mpl_msg *)list_item_next(mmiterptr))->seq))) {
1599  list_insert(locssptr->min_seq, mmiterptr, locmmptr);
1600  break;
1601  }
1602  }
1603  }
1604  locssptr->count++;
1605 
1606 #if MPL_PROACTIVE_FORWARDING
1607  /* Start Forwarding the message */
1608  mpl_data_trickle_timer_start(locmmptr);
1609 #endif
1610 
1611  LOG_INFO("Min Seq Number=%u, %u values\n", locssptr->min_seqno, locssptr->count);
1612  locssptr->lifetime = MPL_SEED_SET_ENTRY_LIFETIME;
1613 
1614  /* Start the control message timer if needed */
1615 #if MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS > 0
1616  if(!trickle_timer_is_running(&locdsptr->tt)) {
1618  } else {
1619  mpl_trickle_timer_reset(locdsptr);
1620  }
1621 #endif
1622 
1623  /**
1624  * Check for inconsistency
1625  * MPL Defines an inconsistent packet as "receiving
1626  * an MPL Data Message that has the same MPL Domain Address, seed-id
1627  * value, and the M flag set, but has a sequence value less than that
1628  * of the MPL Data Message managed by the Trickle timer."
1629  * We have already satisfied the domain address and seed-id conditions,
1630  * now check the rest.
1631  */
1632 #if MPL_PROACTIVE_FORWARDING
1633  if(HBH_GET_M(lochbhmptr) == 1 && list_item_next(locmmptr) != NULL) {
1634  LOG_DBG("MPL Domain is inconsistent\n");
1636  } else {
1637  LOG_DBG("MPL Domain is consistent\n");
1638  trickle_timer_consistency(&locmmptr->tt);
1639  }
1640 #endif
1641 
1642  /* Deliver if necessary */
1643  return UIP_MCAST6_ACCEPT;
1644 }
1645 static void
1646 out(void)
1647 {
1648  /* Check we know our seed ID */
1649  if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1650  update_seed_id();
1651  if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1652  LOG_ERR("Our seed ID is not yet known.\n");
1653  goto drop;
1654  }
1655  }
1656 
1657  /* Check we have enough space for the options header */
1658  if(uip_len + HBHO_TOTAL_LEN > UIP_BUFSIZE) {
1659  LOG_ERR("Multicast Out can not add HBHO. Packet too long\n");
1660  goto drop;
1661  }
1662 
1663  /* Slide 'right' by HBHO_TOTAL_LEN bytes */
1664  memmove(UIP_EXT_BUF_NEXT, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
1665  memset(UIP_EXT_BUF, 0, HBHO_TOTAL_LEN);
1666 
1667  /* Insert the option header into the packet and set it's length */
1668  /* This depends entirely on our seed ID size */
1669  UIP_EXT_BUF->next = UIP_IP_BUF->proto;
1670 #if MPL_SEED_ID_TYPE == 0
1671  UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
1672 #elif MPL_SEED_ID_TYPE == 1
1673  UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
1674 #elif MPL_SEED_ID_TYPE == 2
1675  UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
1676 #elif MPL_SEED_ID_TYPE == 3
1677  UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
1678 #endif
1679 
1680  /* Get a reference to the HBHO and set the type */
1681  lochbhmptr = UIP_EXT_OPT_FIRST;
1682  lochbhmptr->type = HBHO_OPT_TYPE_MPL;
1683  lochbhmptr->flags = 0x00;
1684  HBH_CLR_S(lochbhmptr);
1685  HBH_SET_S(lochbhmptr, MPL_SEED_ID_TYPE);
1686  HBH_CLR_V(lochbhmptr);
1687 #if MPL_SEED_ID_TYPE == 0
1688  lochbhmptr->len = MPL_OPT_LEN_S0;
1689  /* In this case the Seed ID is our IPV6 address */
1690  lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1691  lochbhmptr->padn.opt_type = 0x00;
1692 #elif MPL_SEED_ID_TYPE == 1
1693  lochbhmptr->len = MPL_OPT_LEN_S1;
1694  seed_id_host_to_net(&((struct mpl_hbho_s1 *)lochbhmptr)->seed_id, &local_seed_id);
1695 #elif MPL_SEED_ID_TYPE == 2
1696  lochbhmptr->len = MPL_OPT_LEN_S2;
1697  seed_id_host_to_net(&((struct mpl_hbho_s2 *)lochbhmptr)->seed_id, &local_seed_id);
1698  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1699  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
1700 #elif MPL_SEED_ID_TYPE == 3
1701  lochbhmptr->len = MPL_OPT_LEN_S3;
1702  seed_id_host_to_net(&((struct mpl_hbho_s3 *)lochbhmptr)->seed_id, &local_seed_id);
1703  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1704  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
1705 #endif
1706 
1707  /* Set the sequence ID */
1708  last_seq = SEQ_VAL_ADD(last_seq, 1);
1709  lochbhmptr->seq = last_seq;
1710  HBH_SET_M(lochbhmptr);
1711 
1712  uip_ext_len += HBHO_TOTAL_LEN;
1713  uip_len += HBHO_TOTAL_LEN;
1714 
1715  /* Update the proto and length field in the v6 header */
1716  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
1717  UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
1718  UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
1719 
1720  LOG_INFO("Multicast Out\n");
1721  LOG_DBG("HBHO: Next Header=0x%x, Header Len (exc. 1st 8 bytes)=%u\n",
1722  UIP_EXT_BUF->next, UIP_EXT_BUF->len);
1723  LOG_DBG("MPL Option Type 0x%x: Len=%u, S=%u, M=%u, V=%u, Seq=0x%x\n",
1724  lochbhmptr->type, lochbhmptr->len, HBH_GET_S(lochbhmptr),
1725  HBH_GET_M(lochbhmptr), HBH_GET_V(lochbhmptr), lochbhmptr->seq);
1726 
1727  /*
1728  * We need to remember this message and advertise it in subsequent ICMP
1729  * messages. Otherwise, our neighs will think we are inconsistent and will
1730  * bounce it back to us.
1731  *
1732  * Queue this message but don't set its MUST_SEND flag. We reset the trickle
1733  * timer and we send it immediately. We then set uip_len = 0 to stop the core
1734  * from re-sending it.
1735  */
1736  if(accept(MPL_DGRAM_OUT)) {
1737  tcpip_output(NULL);
1738  UIP_MCAST6_STATS_ADD(mcast_out);
1739  }
1740 
1741 drop:
1742  uip_slen = 0;
1743  uipbuf_clear();
1744 }
1745 static uint8_t
1746 in(void)
1747 {
1748  if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) {
1749  LOG_INFO("Not in our domain. No further processing\n");
1750  return UIP_MCAST6_DROP;
1751  }
1752  /*
1753  * We call accept() which will sort out caching and forwarding. Depending
1754  * on accept()'s return value, we then need to signal the core
1755  * whether to deliver this to higher layers
1756  */
1757  if(accept(MPL_DGRAM_IN) == UIP_MCAST6_DROP) {
1758  LOG_INFO("Packet dropped\n");
1759  return UIP_MCAST6_DROP;
1760  } else {
1761  LOG_INFO("Ours. Deliver to upper layers\n");
1762  UIP_MCAST6_STATS_ADD(mcast_in_ours);
1763  return UIP_MCAST6_ACCEPT;
1764  }
1765 }
1766 static void
1767 init(void)
1768 {
1769  LOG_INFO("Multicast Protocol for Low Power and Lossy Networks - RFC7731\n");
1770 
1771  /* Clear out all sets */
1772  memset(domain_set, 0, sizeof(struct mpl_domain) * MPL_DOMAIN_SET_SIZE);
1773  memset(seed_set, 0, sizeof(struct mpl_seed) * MPL_SEED_SET_SIZE);
1774  memset(buffered_message_set, 0, sizeof(struct mpl_msg) * MPL_BUFFERED_MESSAGE_SET_SIZE);
1775 
1776  /* Register the ICMPv6 input handler */
1777  uip_icmp6_register_input_handler(&mpl_icmp_handler);
1778 
1779  update_seed_id();
1780 
1781  /* Init MPL Stats */
1782  MPL_STATS_INIT();
1783 
1784 #if MPL_SUB_TO_ALL_FORWARDERS
1785  /* Subscribe to the All MPL Forwarders Address by default */
1786  ALL_MPL_FORWARDERS(&all_forwarders, UIP_MCAST6_SCOPE_REALM_LOCAL);
1787  if(!uip_ds6_maddr_add(&all_forwarders)) {
1788  LOG_ERR("Failed to subscribe to All Forwarders MPL Address\n");
1789  }
1790 #endif
1791  mpl_maddr_check();
1792 
1793  /* Setup Minute lifetime timer */
1794  ctimer_set(&lifetime_timer, CLOCK_SECOND * 60, lifetime_timer_expiration, NULL);
1795 }
1796 /*---------------------------------------------------------------------------*/
1797 /**
1798  * \brief The MPL engine driver
1799  */
1801  "MPL",
1802  init,
1803  out,
1804  in
1805 };
1806 /*---------------------------------------------------------------------------*/
1807 /** @} */
#define MPL_IP_HOP_LIMIT
Hop limit for ICMP messages.
Definition: mpl.h:64
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition: uip.h:71
#define mpl_trickle_timer_inconsistency(t)
Call inconsistency on the provided timer t: Pointer to set that should be reset.
Definition: mpl.c:440
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
Header file for ICMPv6 message and error handing (RFC 4443)
#define MSG_SET_IS_USED(h)
Get the state of the used flag in the buffered message set entry h: pointer to the message set entry...
Definition: mpl.c:166
#define MPL_SEED_SET_SIZE
Seed Set Size MPL Forwarders maintain a Seed Set to keep track of the MPL messages that a particular ...
Definition: mpl.h:201
#define mpl_trickle_timer_reset(t)
Reset the trickle timer and expiration count for the set t: Pointer to set that should be reset...
Definition: mpl.c:445
#define MPL_BUFFERED_MESSAGE_SET_SIZE
Buffered Message Set Size MPL Forwarders maintain a buffer of data messages that are periodically for...
Definition: mpl.h:214
#define ICMP6_MPL
MPL.
Definition: uip-icmp6.h:67
#define MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS
Control Message Timer Expirations An MPL Forwarder forwards MPL messages for a particular domain usin...
Definition: mpl.h:267
#define SEED_INFO_CLR_S(h)
Clear the S bits within the length/S field in the seed info header h: pointer to the seed info struct...
Definition: mpl.c:361
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition: list.c:164
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
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
A trickle timer.
Trickle timer library header file.
#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
void trickle_timer_consistency(struct trickle_timer *tt)
To be called by the protocol when it hears a consistent transmission.
const struct uip_mcast6_driver mpl_driver
The MPL engine driver.
Definition: mpl.c:1800
#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
#define SEED_INFO_GET_S(h)
Get the S bits in the length/S field in the seed info header h: pointer to the seed info struct...
Definition: mpl.c:356
#define trickle_timer_stop(tt)
Stop a running trickle timer.
#define HBH_SET_M(h)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
Definition: mpl.c:304
static void icmp_in(void)
Definition: mpl.c:1063
void list_insert(list_t list, void *previtem, void *newitem)
Insert an item after a specified item on the list.
Definition: list.c:300
#define MPL_SEED_SET_ENTRY_LIFETIME
Seed Set Entry Lifetime MPL Seed set entries remain in the seed set for a set period of time after th...
Definition: mpl.h:243
static struct mpl_msg * buffer_reclaim(void)
Definition: mpl.c:489
#define SEED_INFO_SET_LEN(h, l)
Set the length bits in the seed info struct.
Definition: mpl.c:383
#define DOMAIN_SET_IS_USED(h)
Get the state of the used flag in the buffered message set entry h: pointer to the message set entry...
Definition: mpl.c:234
uint8_t trickle_timer_config(struct trickle_timer *tt, clock_time_t i_min, uint8_t i_max, uint8_t k)
Configure a trickle timer.
#define UIP_ADDR_MAKE_LINK_LOCAL(a)
Modify an ipv6 address to give it link local scope a: uip_ip6addr_t address to modify.
Definition: mpl.c:462
#define SEQ_VAL_IS_LT(i1, i2)
s1 is said to be less than s2 if SEQ_VAL_IS_LT(s1, s2) == 1
Definition: mpl.c:181
#define HBH_SET_S(h, s)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
Definition: mpl.c:286
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
Definition: ctimer.c:125
static uint8_t accept(uint8_t in)
Definition: mpl.c:1391
Header file for the implementation of the MPL protocol.
#define trickle_timer_is_running(tt)
To be called in order to determine whether a trickle timer is running.
Header file for IPv6-related data structures.
#define BIT_VECTOR_GET_BIT(v, b)
Get the value of a bit in a bit vector v: The bit vector b: The 0-indexed bit to get.
Definition: mpl.c:457
#define MPL_SEED_ID_H
Seed ID High Bits If the Seed ID Length setting is 3, this setting defines the upper 64 bits for the ...
Definition: mpl.h:165
#define HBH_CLR_V(h)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
Definition: mpl.c:316
#define SEQ_VAL_IS_GT(i1, i2)
s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
Definition: mpl.c:191
Multicast stats extension for the MPL engine.
Definition: mpl.h:284
#define SEED_INFO_SET_S(h, s)
Set the S bits within the seed info struct.
Definition: mpl.c:367
This header file contains configuration directives for uIPv6 multicast support.
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
uint16_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:122
#define SEED_INFO_GET_LEN(h)
Get the length bits from the seed info struct.
Definition: mpl.c:372
#define BIT_VECTOR_SET_BIT(v, b)
Set a single bit within a bit vector that spans multiple bytes v: The bit vector b: The 0-indexed bit...
Definition: mpl.c:451
Header file for the callback timer
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 HBH_GET_S(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
Definition: mpl.c:280
#define SEED_SET_IS_USED(h)
Get the state of the used flag in the buffered message set entry h: pointer to the message set entry...
Definition: mpl.c:216
Linked list manipulation routines.
#define uip_is_addr_mcast_non_routable(a)
is address a non-routable multicast address.
Definition: uip.h:1978
#define SEQ_VAL_IS_EQ(i1, i2)
s1 is said to be equal s2 if SEQ_VAL_IS_EQ(s1, s2) == 1
Definition: mpl.c:176
#define mpl_data_trickle_timer_start(t)
Start the trickle timer for a data message t: Pointer to set that should be reset.
Definition: mpl.c:435
#define DOMAIN_SET_CLEAR_USED(h)
Clear the state of the used flag in the buffered message set entry h: pointer to the message set entr...
Definition: mpl.c:239
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
#define MSG_SET_CLEAR_USED(h)
Clear the state of the used flag in the buffered message set entry h: pointer to the message set entr...
Definition: mpl.c:171
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
Unicast address structure.
Definition: uip-ds6.h:205
static void seed_id_host_to_net(void *dst, seed_id_t *src)
Definition: mpl.c:692
#define mpl_control_trickle_timer_start(t)
Start the trickle timer for a control message t: Pointer to set that should be reset.
Definition: mpl.c:430
#define HBH_GET_M(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
Definition: mpl.c:298
#define SEED_ID_S2(dst, src)
Set the seed id to a 64 bit constant dst: seed_id_t to set to the constant src: 64 bit integer to set...
Definition: mpl.c:122
void(* out)(void)
Process an outgoing datagram with a multicast IPv6 destination address.
Definition: uip-mcast6.h:121
#define SEED_INFO_CLR_LEN(h)
Clear the length bits in the seed info struct.
Definition: mpl.c:377
#define MPL_DOMAIN_SET_SIZE
Domain Set Size MPL Forwarders maintain a Domain Set which maps MPL domains to trickle timers...
Definition: mpl.h:189
Header file for the uIP TCP/IP stack.
void(* init)(void)
Initialize the multicast engine.
Definition: uip-mcast6.h:106
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
#define MPL_SEED_ID_TYPE
Seed ID Length The MPL Protocol requires that each seed is identified by an ID that is unique to the ...
Definition: mpl.h:134
uint16_t uip_icmp6chksum(void)
Calculate the ICMP checksum of the packet in uip_buf.
Definition: uip6.c:363
void * list_pop(list_t list)
Remove the first object on a list.
Definition: list.c:215
#define SEED_ID_S1(dst, src)
Set the seed id to a 16 bit constant dst: seed_id_t to set to the constant src: 16 bit integer to set...
Definition: mpl.c:116
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
Definition: list.h:111
#define seed_id_cpy(a, b)
Copy one seed_id_t into another.
Definition: mpl.c:141
#define SEED_SET_CLEAR_USED(h)
Clear the state of the used flag in the buffered message set entry h: pointer to the message set entr...
Definition: mpl.c:221
#define MPL_SEED_ID_L
Seed ID Alias Points to MPL_CONF_SEED_ID_L.
Definition: mpl.h:154
#define HBH_GET_V(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
Definition: mpl.c:310
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
A multicast address.
Definition: uip-ds6.h:225
Header file for the logging system
#define HBH_CLR_S(h)
Clear the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
Definition: mpl.c:292
#define SEED_ID_S3(dst, l, h)
Set the seed id to a 128 bit constant dst: seed_id_t to set to the constant l: Lower 64 bits of the s...
Definition: mpl.c:129
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
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:322
static void seed_id_net_to_host(seed_id_t *dst, void *src, uint8_t s)
Definition: mpl.c:640
#define uip_mcast6_get_address_scope(a)
Get a multicast address&#39; scope.
Definition: uip-mcast6.h:146
#define MPL_DATA_MESSAGE_TIMER_EXPIRATIONS
Data Message Timer Expirations MPL data message trickle timers are stopped after they expire a set nu...
Definition: mpl.h:254
#define SEQ_VAL_ADD(s, n)
Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000)
Definition: mpl.c:201