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(locssptr->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  uint16_t payload_len;
764  size_t seed_info_len;
765 
766  LOG_INFO("MPL Control Message Out\n");
767 
768  UIP_IP_BUF->vtc = 0x60;
769  UIP_IP_BUF->tcflow = 0;
770  UIP_IP_BUF->flow = 0;
771  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
773 
774  locsiptr = (struct seed_info *)UIP_ICMP_PAYLOAD;
775  payload_len = 0;
776 
777  /* Set the source address to link local for now. If we need to, we can try changing it to global later */
778  uip_ip6addr_copy(&UIP_IP_BUF->destipaddr, &dom->ctrl_addr);
779  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
780 
781  /* Iterate over seed set to create payload */
782  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
783  if(SEED_SET_IS_USED(locssptr) && locssptr->domain == dom) {
784  locsiptr->min_seqno = locssptr->min_seqno;
785  SEED_INFO_CLR_LEN(locsiptr);
786  SEED_INFO_CLR_S(locsiptr);
787 
788  /* Try setting our source address to global */
789  addr = uip_ds6_get_global(ADDR_PREFERRED);
790  if(addr) {
791  uip_ip6addr_copy(&UIP_IP_BUF->srcipaddr, &addr->ipaddr);
792  } else {
793  /* Failed setting a global ip address, fallback to link local */
794  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
795  if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
796  LOG_ERR("icmp out: Cannot set src ip\n");
797  uipbuf_clear();
798  return;
799  }
800  }
801 
802  /* Set the Seed ID */
803  switch(locssptr->seed_id.s) {
804  case 0:
805  if(uip_ip6addr_cmp((uip_ip6addr_t *)&locssptr->seed_id.id, &UIP_IP_BUF->srcipaddr)) {
806  /* We can use an S=0 Seed ID */
807  SEED_INFO_SET_LEN(locsiptr, 0);
808  break;
809  } /* Else fall down into the S = 3 case */
810  case 3:
811  seed_id_host_to_net(&((struct seed_info_s3 *)locsiptr)->seed_id, &locssptr->seed_id);
812  SEED_INFO_SET_S(locsiptr, 3);
813  break;
814  case 1:
815  seed_id_host_to_net(&((struct seed_info_s1 *)locsiptr)->seed_id, &locssptr->seed_id);
816  SEED_INFO_SET_S(locsiptr, 1);
817  break;
818  case 2:
819  seed_id_host_to_net(&((struct seed_info_s2 *)locsiptr)->seed_id, &locssptr->seed_id);
820  SEED_INFO_SET_S(locsiptr, 2);
821  break;
822  }
823 
824  /* Populate the seed info message vector */
825  memset(vector, 0, sizeof(vector));
826  vec_len = 0;
827  locmmptr = list_head(locssptr->min_seq);
828  while(locmmptr != NULL) {
829  if(locmmptr->seq == SEQ_VAL_ADD(locssptr->min_seqno, vec_len)) {
830  BIT_VECTOR_SET_BIT(vector, vec_len);
831  locmmptr = list_item_next(locmmptr);
832  }
833  vec_len++;
834  }
835 
836  /* Convert vector length from bits to bytes */
837  vec_size = (vec_len - 1) / 8 + 1;
838 
839  SEED_INFO_SET_LEN(locsiptr, vec_size);
840 
841  LOG_DBG("--- Control Message Entry ---\n");
842  LOG_DBG("Seed ID: ");
843  LOG_DBG_SEED(locssptr->seed_id);
844  LOG_DBG_("\n");
845  LOG_DBG("S=%u\n", locssptr->seed_id.s);
846  LOG_DBG("Min Sequence Number: %u\n", locssptr->min_seqno);
847  LOG_DBG("Size of message set: %u\n", vec_len);
848  LOG_DBG("Vector is %u bytes\n", vec_size);
849 
850  /* Copy vector into payload and point ptr to next location */
851  switch(SEED_INFO_GET_S(locsiptr)) {
852  case 0:
853  seed_info_len = sizeof(struct seed_info);
854  break;
855  case 1:
856  seed_info_len = sizeof(struct seed_info_s1);
857  break;
858  case 2:
859  seed_info_len = sizeof(struct seed_info_s2);
860  break;
861  case 3:
862  seed_info_len = sizeof(struct seed_info_s3);
863  break;
864  }
865  memcpy(((void *)locsiptr) + seed_info_len, vector, vec_size);
866  locsiptr = ((void *)locsiptr) + seed_info_len + vec_size;
867  payload_len += seed_info_len + vec_size;
868  }
869  /* Now go to next seed in set */
870  }
871  LOG_DBG("--- End of Messages --\n");
872 
873  /* Finish off construction of ICMP Packet */
874  uipbuf_set_len_field(UIP_IP_BUF, UIP_ICMPH_LEN + payload_len);
875  UIP_ICMP_BUF->type = ICMP6_MPL;
876  UIP_ICMP_BUF->icode = 0;
877  uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
878  UIP_ICMP_BUF->icmpchksum = 0;
879  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
880 
881  LOG_DBG("ICMP Out from ");
882  LOG_DBG_6ADDR(&UIP_IP_BUF->srcipaddr);
883  LOG_DBG_(" to ");
884  LOG_DBG_6ADDR(&UIP_IP_BUF->destipaddr);
885  LOG_DBG_("\n");
886 
887  LOG_DBG("MPL Contol Message Out - %u bytes\n", payload_len);
888 
890  uipbuf_clear();
891  MPL_STATS_ADD(icmp_out);
892  return;
893 }
894 static void
895 data_message_expiration(void *ptr, uint8_t suppress)
896 {
897  /* Callback for data message trickle timers */
898  locmmptr = ((struct mpl_msg *)ptr);
899  if(locmmptr->e > MPL_DATA_MESSAGE_TIMER_EXPIRATIONS) {
900  /* Terminate the trickle timer here if we've already expired enough times */
901  trickle_timer_stop(&locmmptr->tt);
902  return;
903  }
904  if(suppress == TRICKLE_TIMER_TX_OK) { /* Only transmit if not suppressed */
905  LOG_DBG("Data message TX\n");
906  LOG_DBG("Seed ID=");
907  LOG_DBG_SEED(locmmptr->seed->seed_id);
908  LOG_DBG_(", S=%u, Seq=%u\n", locmmptr->seed->seed_id.s, locmmptr->seq);
909  /* Setup the IP Header */
910  UIP_IP_BUF->vtc = 0x60;
911  UIP_IP_BUF->tcflow = 0;
912  UIP_IP_BUF->flow = 0;
913  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
914  /*UIP_IP_BUF->ttl = MPL_IP_HOP_LIMIT; */
915  uip_ip6addr_copy(&UIP_IP_BUF->destipaddr, &locmmptr->seed->domain->data_addr);
916  uip_len = UIP_IPH_LEN;
917  /* Setup the HBHO Header */
918  UIP_EXT_BUF->next = UIP_PROTO_UDP;
919  lochbhmptr = UIP_EXT_OPT_FIRST;
920  lochbhmptr->type = HBHO_OPT_TYPE_MPL;
921  lochbhmptr->flags = 0x00;
922  switch(locmmptr->seed->seed_id.s) {
923  case 0:
924  UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
925  lochbhmptr->len = MPL_OPT_LEN_S0;
926  HBH_CLR_S(lochbhmptr);
927  HBH_SET_S(lochbhmptr, 0);
928  uip_len += HBHO_BASE_LEN + HBHO_S0_LEN;
929  uip_ext_len += HBHO_BASE_LEN + HBHO_S0_LEN;
930  lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
931  lochbhmptr->padn.opt_len = 0x00;
932  break;
933  case 1:
934  UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
935  lochbhmptr->len = MPL_OPT_LEN_S1;
936  HBH_CLR_S(lochbhmptr);
937  HBH_SET_S(lochbhmptr, 1);
938  seed_id_host_to_net(&((struct mpl_hbho_s1 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
939  uip_len += HBHO_BASE_LEN + HBHO_S1_LEN;
940  uip_ext_len += HBHO_BASE_LEN + HBHO_S1_LEN;
941  break;
942  case 2:
943  UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
944  lochbhmptr->len = MPL_OPT_LEN_S2;
945  HBH_CLR_S(lochbhmptr);
946  HBH_SET_S(lochbhmptr, 2);
947  seed_id_host_to_net(&((struct mpl_hbho_s2 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
948  uip_len += HBHO_BASE_LEN + HBHO_S2_LEN;
949  uip_ext_len += HBHO_BASE_LEN + HBHO_S2_LEN;
950  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
951  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
952  break;
953  case 3:
954  UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
955  lochbhmptr->len = MPL_OPT_LEN_S3;
956  HBH_CLR_S(lochbhmptr);
957  HBH_SET_S(lochbhmptr, 3);
958  seed_id_host_to_net(&((struct mpl_hbho_s3 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
959  uip_len += HBHO_BASE_LEN + HBHO_S3_LEN;
960  uip_ext_len += HBHO_BASE_LEN + HBHO_S3_LEN;
961  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
962  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
963  break;
964  }
965  lochbhmptr->seq = locmmptr->seq;
966  if(list_item_next(locmmptr) == NULL) {
967  HBH_SET_M(lochbhmptr);
968  }
969  /* Now insert payload */
970  memcpy(((void *)UIP_EXT_BUF) + 8 + UIP_EXT_BUF->len * 8, &locmmptr->data, locmmptr->size);
971  uip_len += locmmptr->size;
972  uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
973  uip_ip6addr_copy(&UIP_IP_BUF->srcipaddr, &locmmptr->srcipaddr);
974  tcpip_output(NULL);
975  uipbuf_clear();
976  UIP_MCAST6_STATS_ADD(mcast_out);
977  }
978 
979  locmmptr->e++;
980 }
981 static void
982 control_message_expiration(void *ptr, uint8_t suppress)
983 {
984  /* Control message timer callback */
985  locdsptr = ((struct mpl_domain *)ptr);
986  if(locdsptr->e > MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS) {
987  /* Disable the trickle timer for now */
988  trickle_timer_stop(&locdsptr->tt);
989  return;
990  }
991  if(suppress == TRICKLE_TIMER_TX_OK) {
992  /* Send an MPL Control Message */
993  icmp_out(locdsptr);
994  }
995  locdsptr->e++;
996 }
997 static void
998 mpl_maddr_check(void)
999 {
1000  /* Check for new multicast addresses that aren't in our domain set */
1001  uip_ds6_maddr_t *elem;
1002  for(elem = &uip_ds6_if.maddr_list[UIP_DS6_MADDR_NB - 1];
1003  elem >= uip_ds6_if.maddr_list;
1004  elem--) {
1005  if(elem->isused && uip_mcast6_get_address_scope(&elem->ipaddr) > UIP_MCAST6_SCOPE_LINK_LOCAL) {
1006  locdsptr = domain_set_lookup(&elem->ipaddr);
1007  if(!locdsptr) {
1008  locdsptr = domain_set_allocate(&elem->ipaddr);
1009  if(!locdsptr) {
1010  LOG_ERR("Failed to allocate domain set in mpl_maddr_check()\n");
1011  }
1012  }
1013  }
1014  }
1015  /* Check for domain set addresses that aren't in our maddr table */
1016  for(locdsptr = &domain_set[MPL_DOMAIN_SET_SIZE - 1]; locdsptr >= domain_set; locdsptr--) {
1017  if(DOMAIN_SET_IS_USED(locdsptr) && !uip_ds6_maddr_lookup(&locdsptr->data_addr)) {
1018  domain_set_free(locdsptr);
1019  }
1020  }
1021 }
1022 static void
1023 lifetime_timer_expiration(void *ptr)
1024 {
1025  /* Called once per minute to decrement seed lifetime counters */
1026  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; seed_set <= locssptr; locssptr--) {
1027  if(SEED_SET_IS_USED(locssptr) && locssptr->lifetime == 0) {
1028  /* Check no timers are running */
1029  locmmptr = list_head(locssptr->min_seq);
1030  while(locmmptr != NULL) {
1031  if(trickle_timer_is_running(&locmmptr->tt)) {
1032  /* We must keep this seed */
1033  break;
1034  }
1035  locmmptr = list_item_next(locmmptr);
1036  }
1037  if(locmmptr == NULL) {
1038  /* We can now free this seed set */
1039  LOG_INFO("Seed ");
1040  LOG_INFO_SEED(locssptr->seed_id);
1041  LOG_INFO_(" expired. Freeing...\n");
1042  seed_set_free(locssptr);
1043  }
1044  }
1045  if(locssptr->lifetime > 0) {
1046  locssptr->lifetime--;
1047  }
1048  }
1049  mpl_maddr_check();
1050  ctimer_reset(&lifetime_timer);
1051 }
1052 static void
1053 icmp_in(void)
1054 {
1055  static seed_id_t seed_id;
1056  static uint8_t r;
1057  static uint8_t *vector;
1058  static uint8_t vector_len;
1059  static uint8_t r_missing;
1060  static uint8_t l_missing;
1061 
1062  LOG_INFO("MPL ICMP Control Message In\n");
1063 
1064 #if UIP_CONF_IPV6_CHECKS
1065  if(!uip_is_addr_mcast_non_routable(&UIP_IP_BUF->destipaddr)) {
1066  LOG_ERR("ICMPv6 In, bad dest ");
1067  LOG_ERR_6ADDR(&UIP_IP_BUF->destipaddr);
1068  LOG_ERR_("\n");
1069  MPL_STATS_ADD(icmp_bad);
1070  goto discard;
1071  }
1072 
1073  if(UIP_ICMP_BUF->type != ICMP6_MPL) {
1074  LOG_ERR("ICMPv6 In, bad ICMP type\n");
1075  MPL_STATS_ADD(icmp_bad);
1076  goto discard;
1077  }
1078 
1079  if(UIP_ICMP_BUF->icode != 0) {
1080  LOG_ERR("ICMPv6 In, bad ICMP type\n");
1081  MPL_STATS_ADD(icmp_bad);
1082  goto discard;
1083  }
1084 
1085  if(UIP_IP_BUF->ttl != MPL_IP_HOP_LIMIT) {
1086  LOG_ERR("ICMPv6 In, bad TTL\n");
1087  MPL_STATS_ADD(icmp_bad);
1088  goto discard;
1089  }
1090 #endif
1091 
1092  LOG_INFO("MPL ICMP Control Message from ");
1093  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
1094  LOG_INFO_(" len %u, ext %u\n", uip_len, uip_ext_len);
1095 
1096  MPL_STATS_ADD(icmp_in);
1097 
1098  /* Find the domain that this has come from */
1099  locdsptr = domain_set_lookup(&UIP_IP_BUF->destipaddr);
1100 
1101  if(!locdsptr) {
1102  LOG_INFO("New MPL Domain ");
1103  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
1104  LOG_INFO_("\n");
1105  locdsptr = domain_set_allocate(&UIP_IP_BUF->destipaddr);
1106  if(!locdsptr) {
1107  LOG_ERR("Couldn't allocate new domain. Dropping.\n");
1108  UIP_MCAST6_STATS_ADD(icmp_bad);
1109  goto discard;
1110  }
1112  }
1113  l_missing = 0;
1114  r_missing = 0;
1115 
1116  /* Iterate over our seed set and check all are present in the remote seed sed */
1117  locsiptr = (struct seed_info *)UIP_ICMP_PAYLOAD;
1118  for(locssptr = &seed_set[MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
1119  if(SEED_SET_IS_USED(locssptr) && locssptr->domain == locdsptr) {
1120  LOG_DBG("Checking remote for seed ");
1121  LOG_DBG_SEED(locssptr->seed_id);
1122  LOG_DBG_("\n");
1123  while(locsiptr <
1124  (struct seed_info *)((void *)UIP_ICMP_PAYLOAD + uip_len - uip_l3_icmp_hdr_len)) {
1125  switch(SEED_INFO_GET_S(locsiptr)) {
1126  case 0:
1127  seed_id_net_to_host(&seed_id, &UIP_IP_BUF->srcipaddr, 0);
1128  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info) + SEED_INFO_GET_LEN(locsiptr);
1129  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1130  goto seed_present;
1131  }
1132  break;
1133  case 1:
1134  seed_id_net_to_host(&seed_id, &((struct seed_info_s1 *)locsiptr)->seed_id, 1);
1135  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s1) + SEED_INFO_GET_LEN(locsiptr);
1136  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1137  goto seed_present;
1138  }
1139  break;
1140  case 2:
1141  seed_id_net_to_host(&seed_id, &((struct seed_info_s2 *)locsiptr)->seed_id, 2);
1142  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s2) + SEED_INFO_GET_LEN(locsiptr);
1143  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1144  goto seed_present;
1145  }
1146  break;
1147  case 3:
1148  seed_id_net_to_host(&seed_id, &((struct seed_info_s3 *)locsiptr)->seed_id, 3);
1149  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s3) + SEED_INFO_GET_LEN(locsiptr);
1150  if(seed_id_cmp(&seed_id, &locssptr->seed_id)) {
1151  goto seed_present;
1152  }
1153  break;
1154  }
1155  }
1156  /* If we made it this far, the seed is missing from the remote. Reset all message timers */
1157  LOG_DBG("Remote is missing seed ");
1158  LOG_DBG_SEED(locssptr->seed_id);
1159  LOG_DBG_("\n");
1160  r_missing = 1;
1161  if(list_head(locssptr->min_seq) != NULL) {
1162  for(locmmptr = list_head(locssptr->min_seq); locmmptr != NULL; locmmptr = list_item_next(locmmptr)) {
1163  LOG_DBG("Resetting timer for messages\n");
1164  if(!trickle_timer_is_running(&locmmptr->tt)) {
1165  LOG_DBG("Starting timer for messages\n");
1166  mpl_data_trickle_timer_start(locmmptr);
1167  }
1169  }
1170  }
1171  /* Otherwise we jump here and continute */
1172 seed_present:
1173  continue;
1174  }
1175  }
1176 
1177  /* Iterate over remote seed info and they're present locally. Additionally check messages match */
1178  locsiptr = (struct seed_info *)UIP_ICMP_PAYLOAD;
1179  while(locsiptr <
1180  (struct seed_info *)((void *)UIP_ICMP_PAYLOAD + uip_len - uip_l3_icmp_hdr_len)) {
1181  /* Extract the seed id */
1182  if(SEED_INFO_GET_S(locsiptr) > 0) {
1183  seed_id_net_to_host(&seed_id, &((struct seed_info_s1 *)locsiptr)->seed_id, SEED_INFO_GET_S(locsiptr));
1184  } else {
1185  /* Always set as S3 because it will never be us */
1186  seed_id_net_to_host(&seed_id, &UIP_IP_BUF->srcipaddr, 3);
1187  }
1188 
1189  LOG_DBG("Control Message for Seed Id: ");
1190  LOG_DBG_SEED(seed_id);
1191  LOG_DBG_("Min Seq Number: %u, %u bytes\n", locsiptr->min_seqno, SEED_INFO_GET_LEN(locsiptr));
1192 
1193  /* Do we have this seed? */
1194  locssptr = seed_set_lookup(&seed_id, locdsptr);
1195  if(!locssptr) {
1196  LOG_DBG("Unknown seed in seed info\n");
1197  /* We don't know this seed */
1198  l_missing = 1;
1199  goto next;
1200  }
1201 
1202  /* Work out where remote bit vector starts */
1203  vector_len = SEED_INFO_GET_LEN(locsiptr) * 8;
1204  switch(SEED_INFO_GET_S(locsiptr)) {
1205  case 0:
1206  vector = ((void *)locsiptr) + sizeof(struct seed_info);
1207  break;
1208  case 1:
1209  vector = ((void *)locsiptr) + sizeof(struct seed_info_s1);
1210  break;
1211  case 2:
1212  vector = ((void *)locsiptr) + sizeof(struct seed_info_s2);
1213  break;
1214  case 3:
1215  vector = ((void *)locsiptr) + sizeof(struct seed_info_s3);
1216  break;
1217  }
1218 
1219  /* Potential quick resolution here */
1220  locmmptr = list_head(locssptr->min_seq);
1221  if(locmmptr == NULL) {
1222  /* We have nothing! */
1223  if(vector[0] > 0) {
1224  /* They have something! */
1225  l_missing = 1;
1226  }
1227  goto next;
1228  }
1229  /**
1230  * Work out what offset the local or remote message set need so that the
1231  * sequence numbers match up
1232  */
1233  r = 0;
1234  if(locmmptr->seq != locsiptr->min_seqno) {
1235  if(SEQ_VAL_IS_GT(locmmptr->seq, locsiptr->min_seqno)) {
1236  while(locmmptr->seq != SEQ_VAL_ADD(locsiptr->min_seqno, r) && r <= vector_len) {
1237  r++;
1238  }
1239  } else {
1240  while(locmmptr != NULL && locmmptr->seq != locsiptr->min_seqno) {
1241  locmmptr = list_item_next(locmmptr);
1242  }
1243  }
1244 
1245  /* There is no overlap in message sets */
1246  if(r > vector_len || locmmptr == NULL) {
1247  LOG_WARN("Seed sets of local and remote have no overlap.\n");
1248  /* Work out who is behind who */
1249  locmmptr = list_head(locssptr->min_seq);
1250  while(list_item_next(locmmptr) != NULL) {
1251  locmmptr = list_item_next(locmmptr);
1252  }
1253  r = vector_len;
1254  while(!BIT_VECTOR_GET_BIT(vector, r)) {
1255  r--;
1256  }
1257  if(SEQ_VAL_IS_GT(locmmptr->seq, SEQ_VAL_ADD(locsiptr->min_seqno, r))) {
1258  /* Our max sequence number is greater than their max sequence number */
1259  LOG_DBG("Our max sequence number is greater than their max sequence number\n");
1260  r_missing = 1;
1261  /* Additionally all data message timers in set if r is behind us */
1262  if(list_head(locssptr->min_seq) != NULL) {
1263  for(locmmptr = list_head(locssptr->min_seq); locmmptr != NULL; locmmptr = list_item_next(locmmptr)) {
1264  if(!trickle_timer_is_running(&locmmptr->tt)) {
1265  mpl_data_trickle_timer_start(locmmptr);
1266  }
1268  }
1269  }
1270  } else {
1271  l_missing = 1;
1272  }
1273  goto next;
1274  }
1275  }
1276 
1277  /**
1278  * If we've made it this far, our sets overlap and we can work out specific
1279  * messages that may be missing from each set.
1280  */
1281  do {
1282  /* This won't occur on first iteration */
1283  /* Resyncronise our pointers to local and remote messages after previous iteration */
1284  while(locmmptr->seq != SEQ_VAL_ADD(locsiptr->min_seqno, r)) {
1285  /**
1286  * If we enter this loop it means there is a gap in local sequence numbers.
1287  * Check that same gap exists in the remote set.
1288  */
1289  if(BIT_VECTOR_GET_BIT(vector, r)) {
1290  /* We are missing a message. Reset timer */
1291  LOG_DBG("We are missing seq=%u\n", SEQ_VAL_ADD(locsiptr->min_seqno, r));
1292  l_missing = 1;
1293  }
1294  r++;
1295  }
1296  /* At this point the local pointer and remote pointer will be in sync */
1297 
1298  /* Check whether the remote is missing the current message */
1299  if(!BIT_VECTOR_GET_BIT(vector, r)) {
1300  /* Local message is missing from remote set. Reset control and data timers */
1301  LOG_DBG("Remote is missing seq=%u\n", locmmptr->seq);
1302  r_missing = 1;
1303  if(!trickle_timer_is_running(&locmmptr->tt)) {
1304  mpl_data_trickle_timer_start(locmmptr);
1305  }
1307  }
1308 
1309  /* Now increment our pointers */
1310  r++;
1311  locmmptr = list_item_next(locmmptr);
1312  /* These are then resyncronised at the top of the loop */
1313  } while(locmmptr != NULL && r <= vector_len);
1314 
1315  /* If we have stopped short of either message set then we may have inconsistencies */
1316  if(locmmptr != NULL || r < vector_len) {
1317  /**
1318  * We have reached the end of local set, the remainder of the remote set should
1319  * be zero else local is missing a message.
1320  */
1321  while(r < vector_len) {
1322  if(BIT_VECTOR_GET_BIT(vector, r)) {
1323  /* We are missing a message */
1324  LOG_DBG("We are missing seq=%u which is greater than our max seq number\n", SEQ_VAL_ADD(locsiptr->min_seqno, r));
1325  l_missing = 1;
1326  }
1327  r++;
1328  }
1329  } else if(r >= vector_len && locmmptr != NULL) {
1330  /* We have reached the end of the remote set.
1331  * Any remaining messages are missing and should be reset.
1332  */
1333  while(locmmptr != NULL) {
1334  LOG_DBG("Remote is missing all above seq=%u\n", locmmptr->seq);
1335  if(!trickle_timer_is_running(&locmmptr->tt)) {
1336  mpl_data_trickle_timer_start(locmmptr);
1337  }
1339  r_missing = 1;
1340  locmmptr = list_item_next(locmmptr);
1341  }
1342  }
1343  /* Now point to next seed info */
1344 next:
1345  switch(SEED_INFO_GET_S(locsiptr)) {
1346  case 0:
1347  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info) + SEED_INFO_GET_LEN(locsiptr);
1348  break;
1349  case 1:
1350  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s1) + SEED_INFO_GET_LEN(locsiptr);
1351  break;
1352  case 2:
1353  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s2) + SEED_INFO_GET_LEN(locsiptr);
1354  break;
1355  case 3:
1356  locsiptr = ((void *)locsiptr) + sizeof(struct seed_info_s3) + SEED_INFO_GET_LEN(locsiptr);
1357  break;
1358  }
1359  }
1360 
1361  /* Now sort out control message timers */
1362  if(l_missing && !trickle_timer_is_running(&locdsptr->tt)) {
1364  }
1365  if(l_missing || r_missing) {
1366  LOG_INFO("Inconsistency detected l=%u, r=%u\n", l_missing, r_missing);
1367  if(trickle_timer_is_running(&locdsptr->tt)) {
1369  }
1370  } else {
1371  LOG_INFO("Domain is consistent \n");
1372  trickle_timer_consistency(&locdsptr->tt);
1373  }
1374 
1375 discard:
1376  uip_len = 0;
1377  uipbuf_clear();
1378  return;
1379 }
1380 static uint8_t
1381 accept(uint8_t in)
1382 {
1383  static seed_id_t seed_id;
1384  static uint16_t seq_val;
1385  static uint8_t S;
1386  static struct mpl_msg *mmiterptr;
1387  static struct uip_ext_hdr *hptr;
1388 
1389  LOG_INFO("Multicast I/O\n");
1390 
1391 #if UIP_CONF_IPV6_CHECKS
1392  if(uip_is_addr_mcast_non_routable(&UIP_IP_BUF->destipaddr)) {
1393  LOG_ERR("Mcast I/O, bad destination\n");
1394  UIP_MCAST6_STATS_ADD(mcast_bad);
1395  return UIP_MCAST6_DROP;
1396  }
1397  /*
1398  * Abort transmission if the v6 src is unspecified. This may happen if the
1399  * seed tries to TX while it's still performing DAD or waiting for a prefix
1400  */
1401  if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
1402  LOG_ERR("Mcast I/O, bad source\n");
1403  UIP_MCAST6_STATS_ADD(mcast_bad);
1404  return UIP_MCAST6_DROP;
1405  }
1406 #endif
1407 
1408  if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr) && in == MPL_DGRAM_IN) {
1409  LOG_WARN("Received message from ourselves.\n");
1410  return UIP_MCAST6_DROP;
1411  }
1412 
1413  /* Check the Next Header field: Must be HBHO */
1414  if(UIP_IP_BUF->proto != UIP_PROTO_HBHO) {
1415  LOG_ERR("Mcast I/O, bad proto\n");
1416  LOG_DBG("Next Proto was %u\n", UIP_IP_BUF->proto);
1417  UIP_MCAST6_STATS_ADD(mcast_bad);
1418  return UIP_MCAST6_DROP;
1419  } else {
1420  /* Check the Option Type */
1421  if(UIP_EXT_OPT_FIRST->type != HBHO_OPT_TYPE_MPL) {
1422  LOG_ERR("Mcast I/O, bad HBHO type\n");
1423  UIP_MCAST6_STATS_ADD(mcast_bad);
1424  return UIP_MCAST6_DROP;
1425  }
1426  }
1427  lochbhmptr = UIP_EXT_OPT_FIRST;
1428 
1429  LOG_DBG("HBHO T=%u, L=%u, M=%u, V=%u, S=%u, SEQ=0x%x\n",
1430  lochbhmptr->type, lochbhmptr->len, HBH_GET_M(lochbhmptr),
1431  HBH_GET_V(lochbhmptr), HBH_GET_S(lochbhmptr),
1432  lochbhmptr->seq);
1433 
1434 #if UIP_MCAST6_STATS
1435  if(in == MPL_DGRAM_IN) {
1436  UIP_MCAST6_STATS_ADD(mcast_in_all);
1437  }
1438 #endif
1439  /* Do a check on the V bit */
1440  if(HBH_GET_V(lochbhmptr)) {
1441  /* The V bit MUST be zero otherwise we drop the message */
1442  LOG_ERR("Invalid V bit - dropping...\n");
1443  return UIP_MCAST6_DROP;
1444  }
1445  /* Is this for a known seed and domain? */
1446  S = HBH_GET_S(lochbhmptr);
1447  LOG_DBG("Incoming message S value = %u\n", S);
1448 
1449  if(S == 0) {
1450  /* Seed ID is the IPV6 Source Address */
1451  seed_id_net_to_host(&seed_id, &UIP_IP_BUF->srcipaddr, S);
1452  } else {
1453  /**
1454  * Seed ID is embedded in the header where padding would otherwise be.
1455  * Since we're only interested in the address the specific s1/s2/s3
1456  * type doesn't matter.
1457  */
1458  seed_id_net_to_host(&seed_id, &((struct mpl_hbho_s1 *)lochbhmptr)->seed_id, S);
1459  }
1460 
1461  LOG_DBG("MPL Domain is ");
1462  LOG_DBG_6ADDR(&UIP_IP_BUF->destipaddr);
1463  LOG_DBG_("\n");
1464 
1465  /* First check the MPL Domain */
1466  locdsptr = domain_set_lookup(&UIP_IP_BUF->destipaddr);
1467 
1468  if(!locdsptr) {
1469  locdsptr = domain_set_allocate(&UIP_IP_BUF->destipaddr);
1470  LOG_INFO("New MPL Domain ");
1471  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
1472  LOG_INFO_("\n");
1473  if(!locdsptr) {
1474  LOG_ERR("Couldn't add to MPL Domain Set. Dropping.\n");
1475  UIP_MCAST6_STATS_ADD(mcast_dropped);
1476  return UIP_MCAST6_DROP;
1477  }
1478 
1479  /* Setup new MPL Domain */
1480  if(!trickle_timer_config(&locdsptr->tt,
1481  MPL_CONTROL_MESSAGE_IMIN,
1482  MPL_CONTROL_MESSAGE_IMAX,
1483  MPL_CONTROL_MESSAGE_K)) {
1484  LOG_ERR("Unable to configure trickle timer for domain. Dropping,...\n");
1485  domain_set_free(locdsptr);
1486  return UIP_MCAST6_DROP;
1487  }
1488  }
1489 
1490  /* Now lookup this seed */
1491  locssptr = seed_set_lookup(&seed_id, locdsptr);
1492 
1493  seq_val = lochbhmptr->seq;
1494 
1495  if(locssptr) {
1496  if(SEQ_VAL_IS_LT(seq_val, locssptr->min_seqno)) {
1497  /* Too old, drop */
1498  LOG_INFO("Too old\n");
1499  UIP_MCAST6_STATS_ADD(mcast_dropped);
1500  return UIP_MCAST6_DROP;
1501  }
1502  if(list_head(locssptr->min_seq) != NULL) {
1503  for(locmmptr = list_head(locssptr->min_seq); locmmptr != NULL; locmmptr = list_item_next(locmmptr)) {
1504  if(SEQ_VAL_IS_EQ(seq_val, locmmptr->seq)) {
1505  /* Seen before , drop */
1506  LOG_INFO("Seen before\n");
1507  if(HBH_GET_M(lochbhmptr) && list_item_next(locmmptr) != NULL) {
1509  } else {
1510  trickle_timer_consistency(&locmmptr->tt);
1511  }
1512  UIP_MCAST6_STATS_ADD(mcast_dropped);
1513  return UIP_MCAST6_DROP;
1514  }
1515  }
1516  }
1517  }
1518  /* We have not seen this message before */
1519 
1520  /* Allocate a seed set if we have to */
1521  if(!locssptr) {
1522  locssptr = seed_set_allocate();
1523  LOG_INFO("New seed\n");
1524  if(!locssptr) {
1525  /* Couldn't allocate seed set, drop */
1526  LOG_ERR("Failed to allocate seed set\n");
1527  UIP_MCAST6_STATS_ADD(mcast_dropped);
1528  return UIP_MCAST6_DROP;
1529  }
1530  memset(locssptr, 0, sizeof(struct mpl_seed));
1531  LIST_STRUCT_INIT(locssptr, min_seq);
1532  seed_id_cpy(&locssptr->seed_id, &seed_id);
1533  locssptr->domain = locdsptr;
1534  }
1535 
1536  /* Allocate a buffer */
1537  locmmptr = buffer_allocate();
1538  if(!locmmptr) {
1539  LOG_INFO("Buffer allocation failed. Reclaiming...\n");
1540  locmmptr = buffer_reclaim();
1541  if(!locmmptr) {
1542  LOG_ERR("Buffer reclaim failed. Dropping...\n");
1543  UIP_MCAST6_STATS_ADD(mcast_dropped);
1544  return UIP_MCAST6_DROP;
1545  }
1546  }
1547 
1548  /* We have a domain set, a seed set, and we have a buffer. Accept this message */
1549  LOG_INFO("Message from seed ");
1550  LOG_INFO_SEED(locssptr->seed_id);
1551  LOG_INFO_("\n");
1552 
1553  /* Set the source IP of the message */
1554  uip_ip6addr_copy(&locmmptr->srcipaddr, &UIP_IP_BUF->srcipaddr);
1555 
1556 #if UIP_MCAST6_STATS
1557  if(in == MPL_DGRAM_IN) {
1558  UIP_MCAST6_STATS_ADD(mcast_in_unique);
1559  }
1560 #endif
1561 
1562  /* Find the start of the payload */
1563  hptr = (struct uip_ext_hdr *)UIP_EXT_BUF;
1564  while(hptr->next != UIP_PROTO_UDP) {
1565  hptr = ((void *)hptr) + hptr->len * 8 + 8;
1566  }
1567  hptr = ((void *)hptr) + hptr->len * 8 + 8;
1568  locmmptr->size = uip_len - UIP_IPH_LEN - uip_ext_len;
1569  memcpy(&locmmptr->data, hptr, locmmptr->size);
1570  locmmptr->seq = seq_val;
1571  locmmptr->seed = locssptr;
1572  if(!trickle_timer_config(&locmmptr->tt,
1573  MPL_DATA_MESSAGE_IMIN,
1574  MPL_DATA_MESSAGE_IMAX,
1575  MPL_DATA_MESSAGE_K)) {
1576  LOG_ERR("Failed to configure timer for message. Dropping...\n");
1577  buffer_free(locmmptr);
1578  return UIP_MCAST6_DROP;
1579  }
1580 
1581  /* Place the message into the buffered message linked list */
1582  if(list_head(locssptr->min_seq) == NULL) {
1583  list_push(locssptr->min_seq, locmmptr);
1584  locssptr->min_seqno = locmmptr->seq;
1585  } else {
1586  for(mmiterptr = list_head(locssptr->min_seq); mmiterptr != NULL; mmiterptr = list_item_next(mmiterptr)) {
1587  if(list_item_next(mmiterptr) == NULL
1588  || (SEQ_VAL_IS_GT(locmmptr->seq, mmiterptr->seq) && SEQ_VAL_IS_LT(locmmptr->seq, ((struct mpl_msg *)list_item_next(mmiterptr))->seq))) {
1589  list_insert(locssptr->min_seq, mmiterptr, locmmptr);
1590  break;
1591  }
1592  }
1593  }
1594  locssptr->count++;
1595 
1596 #if MPL_PROACTIVE_FORWARDING
1597  /* Start Forwarding the message */
1598  mpl_data_trickle_timer_start(locmmptr);
1599 #endif
1600 
1601  LOG_INFO("Min Seq Number=%u, %u values\n", locssptr->min_seqno, locssptr->count);
1602  locssptr->lifetime = MPL_SEED_SET_ENTRY_LIFETIME;
1603 
1604  /* Start the control message timer if needed */
1605 #if MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS > 0
1606  if(!trickle_timer_is_running(&locdsptr->tt)) {
1608  } else {
1609  mpl_trickle_timer_reset(locdsptr);
1610  }
1611 #endif
1612 
1613  /**
1614  * Check for inconsistency
1615  * MPL Defines an inconsistent packet as "receiving
1616  * an MPL Data Message that has the same MPL Domain Address, seed-id
1617  * value, and the M flag set, but has a sequence value less than that
1618  * of the MPL Data Message managed by the Trickle timer."
1619  * We have already satisfied the domain address and seed-id conditions,
1620  * now check the rest.
1621  */
1622 #if MPL_PROACTIVE_FORWARDING
1623  if(HBH_GET_M(lochbhmptr) == 1 && list_item_next(locmmptr) != NULL) {
1624  LOG_DBG("MPL Domain is inconsistent\n");
1626  } else {
1627  LOG_DBG("MPL Domain is consistent\n");
1628  trickle_timer_consistency(&locmmptr->tt);
1629  }
1630 #endif
1631 
1632  /* Deliver if necessary */
1633  return UIP_MCAST6_ACCEPT;
1634 }
1635 static void
1636 out(void)
1637 {
1638  /* Check we know our seed ID */
1639  if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1640  update_seed_id();
1641  if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1642  LOG_ERR("Our seed ID is not yet known.\n");
1643  goto drop;
1644  }
1645  }
1646 
1647  /* Check we have enough space for the options header */
1648  if(uip_len + HBHO_TOTAL_LEN > UIP_BUFSIZE) {
1649  LOG_ERR("Multicast Out can not add HBHO. Packet too long\n");
1650  goto drop;
1651  }
1652 
1653  /* Slide 'right' by HBHO_TOTAL_LEN bytes */
1654  memmove(UIP_EXT_BUF_NEXT, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
1655  memset(UIP_EXT_BUF, 0, HBHO_TOTAL_LEN);
1656 
1657  /* Insert the option header into the packet and set it's length */
1658  /* This depends entirely on our seed ID size */
1659  UIP_EXT_BUF->next = UIP_IP_BUF->proto;
1660 #if MPL_SEED_ID_TYPE == 0
1661  UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
1662 #elif MPL_SEED_ID_TYPE == 1
1663  UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
1664 #elif MPL_SEED_ID_TYPE == 2
1665  UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
1666 #elif MPL_SEED_ID_TYPE == 3
1667  UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
1668 #endif
1669 
1670  /* Get a reference to the HBHO and set the type */
1671  lochbhmptr = UIP_EXT_OPT_FIRST;
1672  lochbhmptr->type = HBHO_OPT_TYPE_MPL;
1673  lochbhmptr->flags = 0x00;
1674  HBH_CLR_S(lochbhmptr);
1675  HBH_SET_S(lochbhmptr, MPL_SEED_ID_TYPE);
1676  HBH_CLR_V(lochbhmptr);
1677 #if MPL_SEED_ID_TYPE == 0
1678  lochbhmptr->len = MPL_OPT_LEN_S0;
1679  /* In this case the Seed ID is our IPV6 address */
1680  lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1681  lochbhmptr->padn.opt_type = 0x00;
1682 #elif MPL_SEED_ID_TYPE == 1
1683  lochbhmptr->len = MPL_OPT_LEN_S1;
1684  seed_id_host_to_net(&((struct mpl_hbho_s1 *)lochbhmptr)->seed_id, &local_seed_id);
1685 #elif MPL_SEED_ID_TYPE == 2
1686  lochbhmptr->len = MPL_OPT_LEN_S2;
1687  seed_id_host_to_net(&((struct mpl_hbho_s2 *)lochbhmptr)->seed_id, &local_seed_id);
1688  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1689  ((struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
1690 #elif MPL_SEED_ID_TYPE == 3
1691  lochbhmptr->len = MPL_OPT_LEN_S3;
1692  seed_id_host_to_net(&((struct mpl_hbho_s3 *)lochbhmptr)->seed_id, &local_seed_id);
1693  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1694  ((struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
1695 #endif
1696 
1697  /* Set the sequence ID */
1698  last_seq = SEQ_VAL_ADD(last_seq, 1);
1699  lochbhmptr->seq = last_seq;
1700  HBH_SET_M(lochbhmptr);
1701 
1702  uip_ext_len += HBHO_TOTAL_LEN;
1703  uip_len += HBHO_TOTAL_LEN;
1704 
1705  /* Update the proto and length field in the v6 header */
1706  UIP_IP_BUF->proto = UIP_PROTO_HBHO;
1707  UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
1708  UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
1709 
1710  LOG_INFO("Multicast Out\n");
1711  LOG_DBG("HBHO: Next Header=0x%x, Header Len (exc. 1st 8 bytes)=%u\n",
1712  UIP_EXT_BUF->next, UIP_EXT_BUF->len);
1713  LOG_DBG("MPL Option Type 0x%x: Len=%u, S=%u, M=%u, V=%u, Seq=0x%x\n",
1714  lochbhmptr->type, lochbhmptr->len, HBH_GET_S(lochbhmptr),
1715  HBH_GET_M(lochbhmptr), HBH_GET_V(lochbhmptr), lochbhmptr->seq);
1716 
1717  /*
1718  * We need to remember this message and advertise it in subsequent ICMP
1719  * messages. Otherwise, our neighs will think we are inconsistent and will
1720  * bounce it back to us.
1721  *
1722  * Queue this message but don't set its MUST_SEND flag. We reset the trickle
1723  * timer and we send it immediately. We then set uip_len = 0 to stop the core
1724  * from re-sending it.
1725  */
1726  if(accept(MPL_DGRAM_OUT)) {
1727  tcpip_output(NULL);
1728  UIP_MCAST6_STATS_ADD(mcast_out);
1729  }
1730 
1731 drop:
1732  uip_slen = 0;
1733  uipbuf_clear();
1734 }
1735 static uint8_t
1736 in(void)
1737 {
1738  if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) {
1739  LOG_INFO("Not in our domain. No further processing\n");
1740  return UIP_MCAST6_DROP;
1741  }
1742  /*
1743  * We call accept() which will sort out caching and forwarding. Depending
1744  * on accept()'s return value, we then need to signal the core
1745  * whether to deliver this to higher layers
1746  */
1747  if(accept(MPL_DGRAM_IN) == UIP_MCAST6_DROP) {
1748  LOG_INFO("Packet dropped\n");
1749  return UIP_MCAST6_DROP;
1750  } else {
1751  LOG_INFO("Ours. Deliver to upper layers\n");
1752  UIP_MCAST6_STATS_ADD(mcast_in_ours);
1753  return UIP_MCAST6_ACCEPT;
1754  }
1755 }
1756 static void
1757 init(void)
1758 {
1759  LOG_INFO("Multicast Protocol for Low Power and Lossy Networks - RFC7731\n");
1760 
1761  /* Clear out all sets */
1762  memset(domain_set, 0, sizeof(struct mpl_domain) * MPL_DOMAIN_SET_SIZE);
1763  memset(seed_set, 0, sizeof(struct mpl_seed) * MPL_SEED_SET_SIZE);
1764  memset(buffered_message_set, 0, sizeof(struct mpl_msg) * MPL_BUFFERED_MESSAGE_SET_SIZE);
1765 
1766  /* Register the ICMPv6 input handler */
1767  uip_icmp6_register_input_handler(&mpl_icmp_handler);
1768 
1769  update_seed_id();
1770 
1771  /* Init MPL Stats */
1772  MPL_STATS_INIT();
1773 
1774 #if MPL_SUB_TO_ALL_FORWARDERS
1775  /* Subscribe to the All MPL Forwarders Address by default */
1776  ALL_MPL_FORWARDERS(&all_forwarders, UIP_MCAST6_SCOPE_REALM_LOCAL);
1777  if(!uip_ds6_maddr_add(&all_forwarders)) {
1778  LOG_ERR("Failed to subscribe to All Forwarders MPL Address\n");
1779  }
1780 #endif
1781  mpl_maddr_check();
1782 
1783  /* Setup Minute lifetime timer */
1784  ctimer_set(&lifetime_timer, CLOCK_SECOND * 60, lifetime_timer_expiration, NULL);
1785 }
1786 /*---------------------------------------------------------------------------*/
1787 /**
1788  * \brief The MPL engine driver
1789  */
1791  "MPL",
1792  init,
1793  out,
1794  in
1795 };
1796 /*---------------------------------------------------------------------------*/
1797 /** @} */
#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:630
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:1790
#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:1053
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:1381
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:204
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:224
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