44#include "contiki-lib.h"
45#include "contiki-net.h"
51#include "dev/watchdog.h"
58#define LOG_MODULE "MPL"
59#define LOG_LEVEL LOG_LEVEL_NONE
65#if MPL_SEED_ID_TYPE < 0 || MPL_SEED_ID_TYPE > 3
66#error Invalid value for MPL_SEED_ID_TYPE
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
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
74#if MPL_SEED_ID_TYPE == 1 && MPL_SEED_ID_L > 0xFFFF
75#error MPL Seed ID too large for Seed ID type setting
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
84typedef struct seed_id_s {
88#define MPL_SEED_ID_UNKNOWN 0xFF
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]); \
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__)
116#define SEED_ID_S1(dst, src) { (*(uint16_t *)&(dst)->id) = (src); (dst)->s = 1; }
122#define SEED_ID_S2(dst, src) { (*(uint64_t *)&(dst)->id) = (src); (dst)->s = 2; }
129#define SEED_ID_S3(dst, l, h) { (*(uint64_t *)&(dst)->id) = (l); (*(uint64_t *)&(dst)->id[8]) = (h); (dst)->s = 3; }
135#define seed_id_cmp(a, b) (memcmp((a)->id, (b)->id, sizeof(uint8_t) * 16) == 0)
141#define seed_id_cpy(a, b) (memcpy((a), (b), sizeof(seed_id_t)))
146#define seed_id_clr(a) (memset((a), 0, sizeof(seed_id_t)))
153 struct mpl_msg *next;
154 struct mpl_seed *seed;
156 uip_ip6addr_t srcipaddr;
166#define MSG_SET_IS_USED(h) ((h)->seed != NULL)
171#define MSG_SET_CLEAR_USED(h) ((h)->seed = NULL)
176#define SEQ_VAL_IS_EQ(i1, i2) ((i1) == (i2))
181#define SEQ_VAL_IS_LT(i1, i2) \
184 ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) < 0x100)) || \
185 (((i1) > (i2)) && ((int16_t)((i1) - (i2)) > 0x100))) \
191#define SEQ_VAL_IS_GT(i1, i2) \
194 ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) > 0x100)) || \
195 (((i1) > (i2)) && ((int16_t)((i1) - (i2)) < 0x100))) \
201#define SEQ_VAL_ADD(s, n) (((s) + (n)) % 0x100)
210 struct mpl_domain *domain;
216#define SEED_SET_IS_USED(h) (((h)->domain != NULL))
221#define SEED_SET_CLEAR_USED(h) ((h)->domain = NULL)
225 uip_ip6addr_t data_addr;
226 uip_ip6addr_t ctrl_addr;
234#define DOMAIN_SET_IS_USED(h) (uip_is_addr_mcast(&(h)->data_addr))
239#define DOMAIN_SET_CLEAR_USED(h) (memset(&(h)->data_addr, 0, sizeof(uip_ip6addr_t)))
251 struct uip_ext_hdr_opt_padn padn;
266 struct uip_ext_hdr_opt_padn padn;
274 struct uip_ext_hdr_opt_padn padn;
280#define HBH_GET_S(h) (((h)->flags & 0xC0) >> 6)
286#define HBH_SET_S(h, s) ((h)->flags |= ((s & 0x03) << 6))
292#define HBH_CLR_S(h) ((h)->flags &= ~0xC0)
298#define HBH_GET_M(h) (((h)->flags & 0x20) == 0x20)
304#define HBH_SET_M(h) ((h)->flags |= 0x20)
310#define HBH_GET_V(h) (((h)->flags & 0x10) == 0x10)
316#define HBH_CLR_V(h) ((h)->flags &= ~0x10)
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
356#define SEED_INFO_GET_S(h) ((h)->bm_len_S & 0x03)
361#define SEED_INFO_CLR_S(h) ((h)->bm_len_S &= ~0x03)
367#define SEED_INFO_SET_S(h, s) ((h)->bm_len_S |= (s & 0x03))
372#define SEED_INFO_GET_LEN(h) ((h)->bm_len_S >> 2)
377#define SEED_INFO_CLR_LEN(h) ((h)->bm_len_S &= 0x03)
383#define SEED_INFO_SET_LEN(h, l) ((h)->bm_len_S |= (l << 2))
390#define MPL_STATS_ADD(x) stats.x++
391#define MPL_STATS_INIT() do { memset(&stats, 0, sizeof(stats)); } while(0)
393#define MPL_STATS_ADD(x)
394#define MPL_STATS_INIT()
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;
407static struct ctimer lifetime_timer;
411static struct mpl_hbho *lochbhmptr;
412static struct mpl_seed *locssptr;
413static struct mpl_msg *locmmptr;
414static struct mpl_domain *locdsptr;
415static struct seed_info *locsiptr;
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;
430#define mpl_control_trickle_timer_start(t) { (t)->e = 0; trickle_timer_set(&(t)->tt, control_message_expiration, (t)); }
435#define mpl_data_trickle_timer_start(t) { (t)->e = 0; trickle_timer_set(&(t)->tt, data_message_expiration, (t)); }
440#define mpl_trickle_timer_inconsistency(t) { (t)->e = 0; trickle_timer_inconsistency(&(t)->tt); }
445#define mpl_trickle_timer_reset(t) { (t)->e = 0; trickle_timer_reset_event(&(t)->tt); }
451#define BIT_VECTOR_SET_BIT(v, b) (v[b / 8] |= (0x80 >> b % 8))
457#define BIT_VECTOR_GET_BIT(v, b) ((v[b / 8] & (0x80 >> b % 8)) == (0x80 >> b % 8))
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)
469static struct mpl_msg *
474 memset(locmmptr, 0,
sizeof(
struct mpl_msg));
481buffer_free(
struct mpl_msg *msg)
488static struct mpl_msg *
491 static struct mpl_seed *ssptr;
492 static struct mpl_seed *largest;
493 static struct mpl_msg *reclaim;
499 if(
SEED_SET_IS_USED(ssptr) && (largest == NULL || ssptr->count > largest->count)) {
511 if(largest != NULL) {
512 reclaim =
list_pop(largest->min_seq);
517 memset(reclaim, 0,
sizeof(
struct mpl_msg));
521static struct mpl_domain *
522domain_set_allocate(uip_ip6addr_t *address)
524 uip_ip6addr_t data_addr;
525 uip_ip6addr_t ctrl_addr;
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));
533 if(uip_ds6_maddr_lookup(&data_addr)) {
534 LOG_DBG(
"Found higher scoped address in table\n");
539 LOG_ERR(
"Failed to find MPL domain data address in table\n");
543 memcpy(&data_addr, address,
sizeof(uip_ip6addr_t));
544 memcpy(&ctrl_addr, address,
sizeof(uip_ip6addr_t));
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);
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));
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");
573static struct mpl_seed *
574seed_set_lookup(seed_id_t *seed_id,
struct mpl_domain *domain)
576 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
583static struct mpl_seed *
584seed_set_allocate(
void)
586 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
596seed_set_free(
struct mpl_seed *s)
598 while((locmmptr =
list_pop(s->min_seq)) != NULL) {
599 buffer_free(locmmptr);
603static struct mpl_domain *
604domain_set_lookup(uip_ip6addr_t *domain)
608 if(uip_ip6addr_cmp(domain, &locdsptr->data_addr)
609 || uip_ip6addr_cmp(domain, &locdsptr->ctrl_addr)) {
617domain_set_free(
struct mpl_domain *domain)
623 seed_set_free(locssptr);
626 addr = uip_ds6_maddr_lookup(&domain->data_addr);
628 uip_ds6_maddr_rm(
addr);
630 addr = uip_ds6_maddr_lookup(&domain->ctrl_addr);
632 uip_ds6_maddr_rm(
addr);
653 for(i = 0; i < 16; i++) {
654 dst->id[i] = ptr[15 - i];
660 for(i = 2; i < 15; i++) {
670 for(i = 0; i < 8; i++) {
672 dst->id[i] = ptr[7 - i];
674 for(i = 8; i < 16; i++) {
682 for(i = 0; i < 16; i++) {
683 dst->id[i] = ptr[15 - i];
705 for(i = 0; i < 16; i++) {
707 ptr[i] = src->id[15 - i];
717 for(i = 0; i < 8; i++) {
718 ptr[i] = src->id[7 - i];
730#if MPL_SEED_ID_TYPE == 0
733 my_ip6_addr = uip_ds6_get_global(ADDR_PREFERRED);
734 if(my_ip6_addr != NULL) {
737 local_seed_id.s = MPL_SEED_ID_UNKNOWN;
738 LOG_DBG(
"Seed id not yet known.\n");
741#elif MPL_SEED_ID_TYPE == 1
744#elif MPL_SEED_ID_TYPE == 2
747#elif MPL_SEED_ID_TYPE == 3
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);
757icmp_out(
struct mpl_domain *dom)
763 uint16_t payload_len;
765 size_t seed_info_len;
767 LOG_INFO(
"MPL Control Message Out\n");
775 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
779 uip_ip6addr_copy(&
UIP_IP_BUF->destipaddr, &dom->ctrl_addr);
783 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
785 locsiptr->min_seqno = locssptr->min_seqno;
790 addr = uip_ds6_get_global(ADDR_PREFERRED);
797 LOG_ERR(
"icmp out: Cannot set src ip\n");
804 switch(locssptr->seed_id.s) {
806 if(uip_ip6addr_cmp((uip_ip6addr_t *)&locssptr->seed_id.id, &
UIP_IP_BUF->srcipaddr)) {
826 memset(vector, 0,
sizeof(vector));
829 LOG_INFO(
"\nBuffer for seed: ");
830 LOG_INFO_SEED(locssptr->seed_id);
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)) {
840 vec_len += locmmptr->seq - cur_seq;
847 vec_size = (vec_len - 1) / 8 + 1;
851 LOG_DBG(
"--- Control Message Entry ---\n");
852 LOG_DBG(
"Seed ID: ");
853 LOG_DBG_SEED(locssptr->seed_id);
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);
863 seed_info_len =
sizeof(
struct seed_info);
866 seed_info_len =
sizeof(
struct seed_info_s1);
869 seed_info_len =
sizeof(
struct seed_info_s2);
872 seed_info_len =
sizeof(
struct seed_info_s3);
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;
881 LOG_DBG(
"--- End of Messages --\n");
884 uipbuf_set_len_field(
UIP_IP_BUF, UIP_ICMPH_LEN + payload_len);
887 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
891 LOG_DBG(
"ICMP Out from ");
897 LOG_DBG(
"MPL Contol Message Out - %u bytes\n", payload_len);
901 MPL_STATS_ADD(icmp_out);
905data_message_expiration(
void *ptr, uint8_t suppress)
908 locmmptr = ((
struct mpl_msg *)ptr);
914 if(suppress == TRICKLE_TIMER_TX_OK) {
915 LOG_DBG(
"Data message TX\n");
917 LOG_DBG_SEED(locmmptr->seed->seed_id);
918 LOG_DBG_(
", S=%u, Seq=%u\n", locmmptr->seed->seed_id.s, locmmptr->seq);
925 uip_ip6addr_copy(&
UIP_IP_BUF->destipaddr, &locmmptr->seed->domain->data_addr);
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) {
934 UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
935 lochbhmptr->len = MPL_OPT_LEN_S0;
938 uip_len += HBHO_BASE_LEN + HBHO_S0_LEN;
940 lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
941 lochbhmptr->padn.opt_len = 0x00;
944 UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
945 lochbhmptr->len = MPL_OPT_LEN_S1;
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;
953 UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
954 lochbhmptr->len = MPL_OPT_LEN_S2;
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;
960 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
961 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
964 UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
965 lochbhmptr->len = MPL_OPT_LEN_S3;
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;
971 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
972 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
975 lochbhmptr->seq = locmmptr->seq;
980 memcpy(((
void *)UIP_EXT_BUF) + 8 + UIP_EXT_BUF->len * 8, &locmmptr->data, locmmptr->size);
983 uip_ip6addr_copy(&
UIP_IP_BUF->srcipaddr, &locmmptr->srcipaddr);
986 UIP_MCAST6_STATS_ADD(mcast_out);
992control_message_expiration(
void *ptr, uint8_t suppress)
995 locdsptr = ((
struct mpl_domain *)ptr);
1001 if(suppress == TRICKLE_TIMER_TX_OK) {
1008mpl_maddr_check(
void)
1012 for(elem = &
uip_ds6_if.maddr_list[UIP_DS6_MADDR_NB - 1];
1016 locdsptr = domain_set_lookup(&elem->ipaddr);
1018 locdsptr = domain_set_allocate(&elem->ipaddr);
1020 LOG_ERR(
"Failed to allocate domain set in mpl_maddr_check()\n");
1026 for(locdsptr = &domain_set[
MPL_DOMAIN_SET_SIZE - 1]; locdsptr >= domain_set; locdsptr--) {
1028 domain_set_free(locdsptr);
1033lifetime_timer_expiration(
void *ptr)
1036 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; seed_set <= locssptr; locssptr--) {
1039 locmmptr =
list_head(locssptr->min_seq);
1040 while(locmmptr != NULL) {
1047 if(locmmptr == NULL) {
1050 LOG_INFO_SEED(locssptr->seed_id);
1051 LOG_INFO_(
" expired. Freeing...\n");
1052 seed_set_free(locssptr);
1055 if(locssptr->lifetime > 0) {
1056 locssptr->lifetime--;
1065 static seed_id_t seed_id;
1067 static uint8_t *vector;
1068 static uint8_t vector_len;
1069 static uint8_t r_missing;
1070 static uint8_t l_missing;
1072 LOG_INFO(
"MPL ICMP Control Message In\n");
1074#if UIP_CONF_IPV6_CHECKS
1076 LOG_ERR(
"ICMPv6 In, bad dest ");
1079 MPL_STATS_ADD(icmp_bad);
1084 LOG_ERR(
"ICMPv6 In, bad ICMP type\n");
1085 MPL_STATS_ADD(icmp_bad);
1090 LOG_ERR(
"ICMPv6 In, bad ICMP type\n");
1091 MPL_STATS_ADD(icmp_bad);
1096 LOG_ERR(
"ICMPv6 In, bad TTL\n");
1097 MPL_STATS_ADD(icmp_bad);
1102 LOG_INFO(
"MPL ICMP Control Message from ");
1109 locdsptr = domain_set_lookup(&
UIP_IP_BUF->destipaddr);
1112 LOG_INFO(
"New MPL Domain ");
1115 locdsptr = domain_set_allocate(&
UIP_IP_BUF->destipaddr);
1117 LOG_ERR(
"Couldn't allocate new domain. Dropping.\n");
1118 UIP_MCAST6_STATS_ADD(icmp_bad);
1127 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
1128 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
1130 LOG_DBG(
"Checking remote for seed ");
1131 LOG_DBG_SEED(locssptr->seed_id);
1134 (
struct seed_info *)((
void *)UIP_ICMP_PAYLOAD +
uip_len - uip_l3_icmp_hdr_len)) {
1138 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info) +
SEED_INFO_GET_LEN(locsiptr);
1145 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1) +
SEED_INFO_GET_LEN(locsiptr);
1152 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2) +
SEED_INFO_GET_LEN(locsiptr);
1159 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3) +
SEED_INFO_GET_LEN(locsiptr);
1167 LOG_DBG(
"Remote is missing seed ");
1168 LOG_DBG_SEED(locssptr->seed_id);
1171 if(
list_head(locssptr->min_seq) != NULL) {
1173 LOG_DBG(
"Resetting timer for messages\n");
1175 LOG_DBG(
"Starting timer for messages\n");
1188 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
1190 (
struct seed_info *)((
void *)UIP_ICMP_PAYLOAD +
uip_len - uip_l3_icmp_hdr_len)) {
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));
1204 locssptr = seed_set_lookup(&seed_id, locdsptr);
1206 LOG_DBG(
"Unknown seed in seed info\n");
1216 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info);
1219 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1);
1222 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2);
1225 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3);
1230 locmmptr =
list_head(locssptr->min_seq);
1231 if(locmmptr == NULL) {
1244 if(locmmptr->seq != locsiptr->min_seqno) {
1246 while(locmmptr->seq !=
SEQ_VAL_ADD(locsiptr->min_seqno, r) && r <= vector_len) {
1250 while(locmmptr != NULL && locmmptr->seq != locsiptr->min_seqno) {
1256 if(r > vector_len || locmmptr == NULL) {
1257 LOG_WARN(
"Seed sets of local and remote have no overlap.\n");
1259 locmmptr =
list_head(locssptr->min_seq);
1269 LOG_DBG(
"Our max sequence number is greater than their max sequence number\n");
1272 if(
list_head(locssptr->min_seq) != NULL) {
1294 while(locmmptr->seq !=
SEQ_VAL_ADD(locsiptr->min_seqno, r)) {
1301 LOG_DBG(
"We are missing seq=%u\n",
SEQ_VAL_ADD(locsiptr->min_seqno, r));
1311 LOG_DBG(
"Remote is missing seq=%u\n", locmmptr->seq);
1323 }
while(locmmptr != NULL && r <= vector_len);
1326 if(locmmptr != NULL || r < vector_len) {
1331 while(r < vector_len) {
1334 LOG_DBG(
"We are missing seq=%u which is greater than our max seq number\n",
SEQ_VAL_ADD(locsiptr->min_seqno, r));
1339 }
else if(r >= vector_len && locmmptr != NULL) {
1343 while(locmmptr != NULL) {
1344 LOG_DBG(
"Remote is missing all above seq=%u\n", locmmptr->seq);
1357 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info) +
SEED_INFO_GET_LEN(locsiptr);
1360 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1) +
SEED_INFO_GET_LEN(locsiptr);
1363 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2) +
SEED_INFO_GET_LEN(locsiptr);
1366 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3) +
SEED_INFO_GET_LEN(locsiptr);
1375 if(l_missing || r_missing) {
1376 LOG_INFO(
"Inconsistency detected l=%u, r=%u\n", l_missing, r_missing);
1381 LOG_INFO(
"Domain is consistent \n");
1393 static seed_id_t seed_id;
1394 static uint16_t seq_val;
1396 static struct mpl_msg *mmiterptr;
1397 static struct uip_ext_hdr *hptr;
1399 LOG_INFO(
"Multicast I/O\n");
1401#if UIP_CONF_IPV6_CHECKS
1403 LOG_ERR(
"Mcast I/O, bad destination\n");
1404 UIP_MCAST6_STATS_ADD(mcast_bad);
1405 return UIP_MCAST6_DROP;
1412 LOG_ERR(
"Mcast I/O, bad source\n");
1413 UIP_MCAST6_STATS_ADD(mcast_bad);
1414 return UIP_MCAST6_DROP;
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;
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;
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;
1437 lochbhmptr = UIP_EXT_OPT_FIRST;
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),
1445 if(in == MPL_DGRAM_IN) {
1446 UIP_MCAST6_STATS_ADD(mcast_in_all);
1452 LOG_ERR(
"Invalid V bit - dropping...\n");
1453 return UIP_MCAST6_DROP;
1457 LOG_DBG(
"Incoming message S value = %u\n", S);
1471 LOG_DBG(
"MPL Domain is ");
1476 locdsptr = domain_set_lookup(&
UIP_IP_BUF->destipaddr);
1479 locdsptr = domain_set_allocate(&
UIP_IP_BUF->destipaddr);
1480 LOG_INFO(
"New MPL Domain ");
1484 LOG_ERR(
"Couldn't add to MPL Domain Set. Dropping.\n");
1485 UIP_MCAST6_STATS_ADD(mcast_dropped);
1486 return UIP_MCAST6_DROP;
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;
1501 locssptr = seed_set_lookup(&seed_id, locdsptr);
1503 seq_val = lochbhmptr->seq;
1508 LOG_INFO(
"Too old\n");
1509 UIP_MCAST6_STATS_ADD(mcast_dropped);
1510 return UIP_MCAST6_DROP;
1512 if(
list_head(locssptr->min_seq) != NULL) {
1516 LOG_INFO(
"Seen before\n");
1522 UIP_MCAST6_STATS_ADD(mcast_dropped);
1523 return UIP_MCAST6_DROP;
1532 locssptr = seed_set_allocate();
1533 LOG_INFO(
"New seed\n");
1536 LOG_ERR(
"Failed to allocate seed set\n");
1537 UIP_MCAST6_STATS_ADD(mcast_dropped);
1538 return UIP_MCAST6_DROP;
1540 memset(locssptr, 0,
sizeof(
struct mpl_seed));
1543 locssptr->domain = locdsptr;
1547 locmmptr = buffer_allocate();
1549 LOG_INFO(
"Buffer allocation failed. Reclaiming...\n");
1552 LOG_ERR(
"Buffer reclaim failed. Dropping...\n");
1553 UIP_MCAST6_STATS_ADD(mcast_dropped);
1554 return UIP_MCAST6_DROP;
1559 LOG_INFO(
"Message from seed ");
1560 LOG_INFO_SEED(locssptr->seed_id);
1564 uip_ip6addr_copy(&locmmptr->srcipaddr, &
UIP_IP_BUF->srcipaddr);
1567 if(in == MPL_DGRAM_IN) {
1568 UIP_MCAST6_STATS_ADD(mcast_in_unique);
1573 hptr = (
struct uip_ext_hdr *)UIP_EXT_BUF;
1574 while(hptr->next != UIP_PROTO_UDP) {
1575 hptr = ((
void *)hptr) + hptr->len * 8 + 8;
1577 hptr = ((
void *)hptr) + hptr->len * 8 + 8;
1579 memcpy(&locmmptr->data, hptr, locmmptr->size);
1580 locmmptr->seq = seq_val;
1581 locmmptr->seed = locssptr;
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;
1592 if(
list_head(locssptr->min_seq) == NULL) {
1594 locssptr->min_seqno = locmmptr->seq;
1599 list_insert(locssptr->min_seq, mmiterptr, locmmptr);
1606#if MPL_PROACTIVE_FORWARDING
1611 LOG_INFO(
"Min Seq Number=%u, %u values\n", locssptr->min_seqno, locssptr->count);
1615#if MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS > 0
1632#if MPL_PROACTIVE_FORWARDING
1634 LOG_DBG(
"MPL Domain is inconsistent\n");
1637 LOG_DBG(
"MPL Domain is consistent\n");
1643 return UIP_MCAST6_ACCEPT;
1649 if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1651 if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1652 LOG_ERR(
"Our seed ID is not yet known.\n");
1659 LOG_ERR(
"Multicast Out can not add HBHO. Packet too long\n");
1664 memmove(UIP_EXT_BUF_NEXT, UIP_EXT_BUF,
uip_len - UIP_IPH_LEN);
1665 memset(UIP_EXT_BUF, 0, HBHO_TOTAL_LEN);
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;
1681 lochbhmptr = UIP_EXT_OPT_FIRST;
1682 lochbhmptr->type = HBHO_OPT_TYPE_MPL;
1683 lochbhmptr->flags = 0x00;
1687#if MPL_SEED_ID_TYPE == 0
1688 lochbhmptr->len = MPL_OPT_LEN_S0;
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;
1695#elif MPL_SEED_ID_TYPE == 2
1696 lochbhmptr->len = MPL_OPT_LEN_S2;
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;
1703 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1704 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
1709 lochbhmptr->seq = last_seq;
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),
1736 if(
accept(MPL_DGRAM_OUT)) {
1738 UIP_MCAST6_STATS_ADD(mcast_out);
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;
1757 if(
accept(MPL_DGRAM_IN) == UIP_MCAST6_DROP) {
1758 LOG_INFO(
"Packet dropped\n");
1759 return UIP_MCAST6_DROP;
1761 LOG_INFO(
"Ours. Deliver to upper layers\n");
1762 UIP_MCAST6_STATS_ADD(mcast_in_ours);
1763 return UIP_MCAST6_ACCEPT;
1769 LOG_INFO(
"Multicast Protocol for Low Power and Lossy Networks - RFC7731\n");
1784#if MPL_SUB_TO_ALL_FORWARDERS
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");
Header file for the callback timer.
static volatile uint64_t count
Num.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
void * list_pop(list_t list)
Remove the first object on a list.
void * list_item_next(const void *item)
Get the next item following this item.
void list_push(list_t list, void *item)
Add an item to the start of the list.
void * list_head(const_list_t list)
Get a pointer to the first element of a list.
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
void list_insert(list_t list, void *previtem, void *newitem)
Insert an item after a specified item on the list.
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
#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.
static void seed_id_host_to_net(void *dst, seed_id_t *src)
const struct uip_mcast6_driver mpl_driver
The MPL engine driver.
#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.
#define SEED_INFO_CLR_LEN(h)
Clear the length bits in the seed info struct.
#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...
#define MPL_SEED_ID_L
Seed ID Alias Points to MPL_CONF_SEED_ID_L.
#define HBH_GET_M(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
static void seed_id_net_to_host(seed_id_t *dst, void *src, uint8_t s)
#define HBH_GET_V(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
#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.
#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...
#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.
#define seed_id_cpy(a, b)
Copy one seed_id_t into another.
#define SEQ_VAL_ADD(s, n)
Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000)
#define HBH_SET_S(h, s)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header.
#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 ...
static struct mpl_msg * buffer_reclaim(void)
#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...
#define SEED_INFO_GET_LEN(h)
Get the length bits from the seed info struct.
static uint8_t accept(uint8_t in)
#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...
#define mpl_control_trickle_timer_start(t)
Start the trickle timer for a control message t: Pointer to set that should be reset.
#define SEQ_VAL_IS_LT(i1, i2)
s1 is said to be less than s2 if SEQ_VAL_IS_LT(s1, s2) == 1
static void icmp_in(void)
#define MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS
Control Message Timer Expirations An MPL Forwarder forwards MPL messages for a particular domain usin...
#define mpl_trickle_timer_inconsistency(t)
Call inconsistency on the provided timer t: Pointer to set that should be reset.
#define MPL_IP_HOP_LIMIT
Hop limit for ICMP messages.
#define SEQ_VAL_IS_EQ(i1, i2)
s1 is said to be equal s2 if SEQ_VAL_IS_EQ(s1, s2) == 1
#define MPL_SEED_SET_SIZE
Seed Set Size MPL Forwarders maintain a Seed Set to keep track of the MPL messages that a particular ...
#define HBH_CLR_S(h)
Clear the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header.
#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.
#define SEED_INFO_SET_LEN(h, l)
Set the length bits in the seed info struct.
#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 ...
#define MPL_DATA_MESSAGE_TIMER_EXPIRATIONS
Data Message Timer Expirations MPL data message trickle timers are stopped after they expire a set nu...
#define mpl_trickle_timer_reset(t)
Reset the trickle timer and expiration count for the set t: Pointer to set that should be reset.
#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...
#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...
#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...
#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...
#define SEED_INFO_SET_S(h, s)
Set the S bits within the seed info struct.
#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...
#define UIP_ADDR_MAKE_LINK_LOCAL(a)
Modify an ipv6 address to give it link local scope a: uip_ip6addr_t address to modify.
#define SEQ_VAL_IS_GT(i1, i2)
s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
#define HBH_CLR_V(h)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header.
#define HBH_GET_S(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
#define mpl_data_trickle_timer_start(t)
Start the trickle timer for a data message t: Pointer to set that should be reset.
#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...
#define HBH_SET_M(h)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header.
#define MPL_DOMAIN_SET_SIZE
Domain Set Size MPL Forwarders maintain a Domain Set which maps MPL domains to trickle timers.
#define MPL_BUFFERED_MESSAGE_SET_SIZE
Buffered Message Set Size MPL Forwarders maintain a buffer of data messages that are periodically for...
uint8_t tcpip_output(const uip_lladdr_t *a)
Output packet to layer 2 The eventual parameter is the MAC address of the destination.
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
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.
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
#define UIP_ICMP_BUF
Direct access to ICMP, UDP, and TCP headers and payload, with implicit ext header offset (global uip_...
#define uip_is_addr_mcast_non_routable(a)
is address a non-routable multicast address.
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
Register a handler which can handle a specific ICMPv6 message type.
uip_ds6_netif_t uip_ds6_if
The single interface.
#define UIP_PROTO_HBHO
extension headers types
#define UIP_IP_BUF
Direct access to IPv6 header.
uint16_t uip_ext_len
The length of the extension headers.
uint16_t uip_len
The length of the packet in the uip_buf buffer.
#define UIP_BUFSIZE
The size of the uIP packet buffer.
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.
Unicast address structure.
The data structure used to represent a multicast engine.
void(* out)(void)
Process an outgoing datagram with a multicast IPv6 destination address.
uint8_t(* in)(void)
Process an incoming multicast datagram and determine whether it should be delivered up the stack or n...
void(* init)(void)
Initialize the multicast engine.
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.
Header file for the uIP TCP/IP stack.