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"
51#include "dev/watchdog.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 */
84typedef 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 */
152struct 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 */
204struct 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 */
224struct 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 */
246struct 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};
253struct 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};
260struct 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};
268struct 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 */
333struct seed_info {
334 uint8_t min_seqno;
335 uint8_t bm_len_S; /* First 6 bits bm-len, last 2 S */
336};
337struct 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};
342struct 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};
347struct 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
388static 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/*---------------------------------------------------------------------------*/
399static struct mpl_msg buffered_message_set[MPL_BUFFERED_MESSAGE_SET_SIZE];
400static struct mpl_seed seed_set[MPL_SEED_SET_SIZE];
401static struct mpl_domain domain_set[MPL_DOMAIN_SET_SIZE];
402static uint16_t last_seq;
403static seed_id_t local_seed_id;
404#if MPL_SUB_TO_ALL_FORWARDERS
405static uip_ip6addr_t all_forwarders;
406#endif
407static struct ctimer lifetime_timer;
408/*---------------------------------------------------------------------------*/
409/* Temporary Stores */
410/*---------------------------------------------------------------------------*/
411static struct mpl_hbho *lochbhmptr; /* HBH Header Pointer */
412static struct mpl_seed *locssptr; /* Seed Set Pointer */
413static struct mpl_msg *locmmptr; /* MPL Message Pointer */
414static struct mpl_domain *locdsptr; /* Domain set pointer */
415static 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))
422extern 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_ip6addr_t *)a)->u8[1] & 0xF0) | UIP_MCAST6_SCOPE_LINK_LOCAL)
463/*---------------------------------------------------------------------------*/
464/* Local function prototypes */
465/*---------------------------------------------------------------------------*/
466static void icmp_in(void);
467UIP_ICMP6_HANDLER(mpl_icmp_handler, ICMP6_MPL, 0, icmp_in);
468
469static struct mpl_msg *
470buffer_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}
480static void
481buffer_free(struct mpl_msg *msg)
482{
483 if(trickle_timer_is_running(&msg->tt)) {
484 trickle_timer_stop(&msg->tt);
485 }
487}
488static 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}
521static struct mpl_domain *
522domain_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(uip_mcast6_get_address_scope(&data_addr) <= UIP_MCAST6_SCOPE_SITE_LOCAL);
538 if(uip_mcast6_get_address_scope(&data_addr) > UIP_MCAST6_SCOPE_SITE_LOCAL) {
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 */
573static struct mpl_seed *
574seed_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}
583static struct mpl_seed *
584seed_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}
595static void
596seed_set_free(struct mpl_seed *s)
597{
598 while((locmmptr = list_pop(s->min_seq)) != NULL) {
599 buffer_free(locmmptr);
600 }
602}
603static struct mpl_domain *
604domain_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}
616static void
617domain_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}
639static void
640seed_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}
691static void
692seed_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}
726static void
727update_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}
756void
757icmp_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}
904static void
905data_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}
991static void
992control_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}
1007static void
1008mpl_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}
1032static void
1033lifetime_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}
1062static 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");
1177 }
1179 }
1180 }
1181 /* Otherwise we jump here and continute */
1182seed_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)) {
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)) {
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)) {
1347 }
1349 r_missing = 1;
1350 locmmptr = list_item_next(locmmptr);
1351 }
1352 }
1353 /* Now point to next seed info */
1354next:
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
1385discard:
1386 uip_len = 0;
1387 uipbuf_clear();
1388 return;
1389}
1390static uint8_t
1391accept(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 */
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}
1645static void
1646out(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
1741drop:
1742 uip_slen = 0;
1743 uipbuf_clear();
1744}
1745static uint8_t
1746in(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}
1766static void
1767init(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/** @} */
Header file for the callback timer.
static volatile uint64_t count
Num.
Definition: clock.c:50
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
Definition: ctimer.c:125
void * list_pop(list_t list)
Remove the first object on a list.
Definition: list.c:140
void * list_item_next(const void *item)
Get the next item following this item.
Definition: list.c:203
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition: list.c:108
void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition: list.c:63
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
Definition: list.h:111
void list_insert(list_t list, void *previtem, void *newitem)
Insert an item after a specified item on the list.
Definition: list.c:191
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
#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
static void seed_id_host_to_net(void *dst, seed_id_t *src)
Definition: mpl.c:692
const struct uip_mcast6_driver mpl_driver
The MPL engine driver.
Definition: mpl.c:1800
#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
#define SEED_INFO_CLR_LEN(h)
Clear the length bits in the seed info struct.
Definition: mpl.c:377
#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 MPL_SEED_ID_L
Seed ID Alias Points to MPL_CONF_SEED_ID_L.
Definition: mpl.h:154
#define HBH_GET_M(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
Definition: mpl.c:298
static void seed_id_net_to_host(seed_id_t *dst, void *src, uint8_t s)
Definition: mpl.c:640
#define HBH_GET_V(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
Definition: mpl.c:310
#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 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
#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 seed_id_cpy(a, b)
Copy one seed_id_t into another.
Definition: mpl.c:141
#define SEQ_VAL_ADD(s, n)
Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000)
Definition: mpl.c:201
#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
#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
static struct mpl_msg * buffer_reclaim(void)
Definition: mpl.c:489
#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
#define SEED_INFO_GET_LEN(h)
Get the length bits from the seed info struct.
Definition: mpl.c:372
static uint8_t accept(uint8_t in)
Definition: mpl.c:1391
#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
#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 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
static void icmp_in(void)
Definition: mpl.c:1063
#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 mpl_trickle_timer_inconsistency(t)
Call inconsistency on the provided timer t: Pointer to set that should be reset.
Definition: mpl.c:440
#define MPL_IP_HOP_LIMIT
Hop limit for ICMP messages.
Definition: mpl.h:64
#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_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 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_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 SEED_INFO_SET_LEN(h, l)
Set the length bits in the seed info struct.
Definition: mpl.c:383
#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
#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 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 seed_id_cmp(a, b)
Compare two contiki seed ids represented as seed_id_t types a: First value to compare b: Second value...
Definition: mpl.c:135
#define 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
#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 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
#define SEED_INFO_SET_S(h, s)
Set the S bits within the seed info struct.
Definition: mpl.c:367
#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
#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_GT(i1, i2)
s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
Definition: mpl.c:191
#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 HBH_GET_S(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
Definition: mpl.c:280
#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 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
#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
#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
#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
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
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
Definition: tcpip.c:631
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 trickle_timer_is_running(tt)
To be called in order to determine whether a trickle timer is running.
#define trickle_timer_stop(tt)
Stop a running trickle timer.
void trickle_timer_consistency(struct trickle_timer *tt)
To be called by the protocol when it hears a consistent transmission.
#define uip_mcast6_get_address_scope(a)
Get a multicast address' scope.
Definition: uip-mcast6.h:146
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Definition: uip.h:1734
#define UIP_ICMP_BUF
Direct access to ICMP, UDP, and TCP headers and payload, with implicit ext header offset (global uip_...
Definition: uip.h:77
#define uip_is_addr_mcast_non_routable(a)
is address a non-routable multicast address.
Definition: uip.h:1886
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
Definition: uip-ds6.c:538
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
Register a handler which can handle a specific ICMPv6 message type.
Definition: uip-icmp6.c:102
#define ICMP6_MPL
MPL.
Definition: uip-icmp6.h:67
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
#define UIP_PROTO_HBHO
extension headers types
Definition: uip.h:1672
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition: uip.h:71
uint16_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:122
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:93
Linked list manipulation routines.
Header file for the logging system.
Header file for the implementation of the MPL protocol.
Multicast stats extension for the MPL engine.
Definition: mpl.h:284
A trickle timer.
Unicast address structure.
Definition: uip-ds6.h:205
A multicast address.
Definition: uip-ds6.h:225
The data structure used to represent a multicast engine.
Definition: uip-mcast6.h:101
void(* out)(void)
Process an outgoing datagram with a multicast IPv6 destination address.
Definition: uip-mcast6.h:121
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
void(* init)(void)
Initialize the multicast engine.
Definition: uip-mcast6.h:106
Trickle timer library header file.
Header file for IPv6-related data structures.
Header file for ICMPv6 message and error handing (RFC 4443)
This header file contains configuration directives for uIPv6 multicast support.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
Header file for the uIP TCP/IP stack.