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);
924 uip_ip6addr_copy(&
UIP_IP_BUF->destipaddr, &locmmptr->seed->domain->data_addr);
927 UIP_EXT_BUF->next = UIP_PROTO_UDP;
928 lochbhmptr = UIP_EXT_OPT_FIRST;
929 lochbhmptr->type = HBHO_OPT_TYPE_MPL;
930 lochbhmptr->flags = 0x00;
931 switch(locmmptr->seed->seed_id.s) {
933 UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
934 lochbhmptr->len = MPL_OPT_LEN_S0;
937 uip_len += HBHO_BASE_LEN + HBHO_S0_LEN;
939 lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
940 lochbhmptr->padn.opt_len = 0x00;
943 UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
944 lochbhmptr->len = MPL_OPT_LEN_S1;
947 seed_id_host_to_net(&((
struct mpl_hbho_s1 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
948 uip_len += HBHO_BASE_LEN + HBHO_S1_LEN;
952 UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
953 lochbhmptr->len = MPL_OPT_LEN_S2;
956 seed_id_host_to_net(&((
struct mpl_hbho_s2 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
957 uip_len += HBHO_BASE_LEN + HBHO_S2_LEN;
959 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
960 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
963 UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
964 lochbhmptr->len = MPL_OPT_LEN_S3;
967 seed_id_host_to_net(&((
struct mpl_hbho_s3 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
968 uip_len += HBHO_BASE_LEN + HBHO_S3_LEN;
970 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
971 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
974 lochbhmptr->seq = locmmptr->seq;
979 memcpy(((
void *)UIP_EXT_BUF) + 8 + UIP_EXT_BUF->len * 8, &locmmptr->data, locmmptr->size);
982 uip_ip6addr_copy(&
UIP_IP_BUF->srcipaddr, &locmmptr->srcipaddr);
985 UIP_MCAST6_STATS_ADD(mcast_out);
991control_message_expiration(
void *ptr, uint8_t suppress)
994 locdsptr = ((
struct mpl_domain *)ptr);
1000 if(suppress == TRICKLE_TIMER_TX_OK) {
1007mpl_maddr_check(
void)
1011 for(elem = &
uip_ds6_if.maddr_list[UIP_DS6_MADDR_NB - 1];
1015 locdsptr = domain_set_lookup(&elem->ipaddr);
1017 locdsptr = domain_set_allocate(&elem->ipaddr);
1019 LOG_ERR(
"Failed to allocate domain set in mpl_maddr_check()\n");
1025 for(locdsptr = &domain_set[
MPL_DOMAIN_SET_SIZE - 1]; locdsptr >= domain_set; locdsptr--) {
1027 domain_set_free(locdsptr);
1032lifetime_timer_expiration(
void *ptr)
1035 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; seed_set <= locssptr; locssptr--) {
1038 locmmptr =
list_head(locssptr->min_seq);
1039 while(locmmptr != NULL) {
1046 if(locmmptr == NULL) {
1049 LOG_INFO_SEED(locssptr->seed_id);
1050 LOG_INFO_(
" expired. Freeing...\n");
1051 seed_set_free(locssptr);
1054 if(locssptr->lifetime > 0) {
1055 locssptr->lifetime--;
1064 static seed_id_t seed_id;
1066 static uint8_t *vector;
1067 static uint8_t vector_len;
1068 static uint8_t r_missing;
1069 static uint8_t l_missing;
1071 LOG_INFO(
"MPL ICMP Control Message In\n");
1073#if UIP_CONF_IPV6_CHECKS
1075 LOG_ERR(
"ICMPv6 In, bad dest ");
1078 MPL_STATS_ADD(icmp_bad);
1083 LOG_ERR(
"ICMPv6 In, bad ICMP type\n");
1084 MPL_STATS_ADD(icmp_bad);
1089 LOG_ERR(
"ICMPv6 In, bad ICMP type\n");
1090 MPL_STATS_ADD(icmp_bad);
1095 LOG_ERR(
"ICMPv6 In, bad TTL\n");
1096 MPL_STATS_ADD(icmp_bad);
1101 LOG_INFO(
"MPL ICMP Control Message from ");
1108 locdsptr = domain_set_lookup(&
UIP_IP_BUF->destipaddr);
1111 LOG_INFO(
"New MPL Domain ");
1114 locdsptr = domain_set_allocate(&
UIP_IP_BUF->destipaddr);
1116 LOG_ERR(
"Couldn't allocate new domain. Dropping.\n");
1117 UIP_MCAST6_STATS_ADD(icmp_bad);
1126 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
1127 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
1129 LOG_DBG(
"Checking remote for seed ");
1130 LOG_DBG_SEED(locssptr->seed_id);
1133 (
struct seed_info *)((
void *)UIP_ICMP_PAYLOAD +
uip_len - uip_l3_icmp_hdr_len)) {
1137 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info) +
SEED_INFO_GET_LEN(locsiptr);
1144 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1) +
SEED_INFO_GET_LEN(locsiptr);
1151 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2) +
SEED_INFO_GET_LEN(locsiptr);
1158 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3) +
SEED_INFO_GET_LEN(locsiptr);
1166 LOG_DBG(
"Remote is missing seed ");
1167 LOG_DBG_SEED(locssptr->seed_id);
1170 if(
list_head(locssptr->min_seq) != NULL) {
1172 LOG_DBG(
"Resetting timer for messages\n");
1174 LOG_DBG(
"Starting timer for messages\n");
1187 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
1189 (
struct seed_info *)((
void *)UIP_ICMP_PAYLOAD +
uip_len - uip_l3_icmp_hdr_len)) {
1198 LOG_DBG(
"Control Message for Seed Id: ");
1199 LOG_DBG_SEED(seed_id);
1200 LOG_DBG_(
"Min Seq Number: %u, %u bytes\n", locsiptr->min_seqno,
SEED_INFO_GET_LEN(locsiptr));
1203 locssptr = seed_set_lookup(&seed_id, locdsptr);
1205 LOG_DBG(
"Unknown seed in seed info\n");
1215 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info);
1218 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1);
1221 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2);
1224 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3);
1229 locmmptr =
list_head(locssptr->min_seq);
1230 if(locmmptr == NULL) {
1243 if(locmmptr->seq != locsiptr->min_seqno) {
1245 while(locmmptr->seq !=
SEQ_VAL_ADD(locsiptr->min_seqno, r) && r <= vector_len) {
1249 while(locmmptr != NULL && locmmptr->seq != locsiptr->min_seqno) {
1255 if(r > vector_len || locmmptr == NULL) {
1256 LOG_WARN(
"Seed sets of local and remote have no overlap.\n");
1258 locmmptr =
list_head(locssptr->min_seq);
1268 LOG_DBG(
"Our max sequence number is greater than their max sequence number\n");
1271 if(
list_head(locssptr->min_seq) != NULL) {
1293 while(locmmptr->seq !=
SEQ_VAL_ADD(locsiptr->min_seqno, r)) {
1300 LOG_DBG(
"We are missing seq=%u\n",
SEQ_VAL_ADD(locsiptr->min_seqno, r));
1310 LOG_DBG(
"Remote is missing seq=%u\n", locmmptr->seq);
1322 }
while(locmmptr != NULL && r <= vector_len);
1325 if(locmmptr != NULL || r < vector_len) {
1330 while(r < vector_len) {
1333 LOG_DBG(
"We are missing seq=%u which is greater than our max seq number\n",
SEQ_VAL_ADD(locsiptr->min_seqno, r));
1338 }
else if(r >= vector_len && locmmptr != NULL) {
1342 while(locmmptr != NULL) {
1343 LOG_DBG(
"Remote is missing all above seq=%u\n", locmmptr->seq);
1356 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info) +
SEED_INFO_GET_LEN(locsiptr);
1359 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1) +
SEED_INFO_GET_LEN(locsiptr);
1362 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2) +
SEED_INFO_GET_LEN(locsiptr);
1365 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3) +
SEED_INFO_GET_LEN(locsiptr);
1374 if(l_missing || r_missing) {
1375 LOG_INFO(
"Inconsistency detected l=%u, r=%u\n", l_missing, r_missing);
1380 LOG_INFO(
"Domain is consistent \n");
1392 static seed_id_t seed_id;
1393 static uint16_t seq_val;
1395 static struct mpl_msg *mmiterptr;
1396 static struct uip_ext_hdr *hptr;
1398 LOG_INFO(
"Multicast I/O\n");
1400#if UIP_CONF_IPV6_CHECKS
1402 LOG_ERR(
"Mcast I/O, bad destination\n");
1403 UIP_MCAST6_STATS_ADD(mcast_bad);
1404 return UIP_MCAST6_DROP;
1411 LOG_ERR(
"Mcast I/O, bad source\n");
1412 UIP_MCAST6_STATS_ADD(mcast_bad);
1413 return UIP_MCAST6_DROP;
1417 if(uip_ds6_is_my_addr(&
UIP_IP_BUF->srcipaddr) && in == MPL_DGRAM_IN) {
1418 LOG_WARN(
"Received message from ourselves.\n");
1419 return UIP_MCAST6_DROP;
1424 LOG_ERR(
"Mcast I/O, bad proto\n");
1425 LOG_DBG(
"Next Proto was %u\n",
UIP_IP_BUF->proto);
1426 UIP_MCAST6_STATS_ADD(mcast_bad);
1427 return UIP_MCAST6_DROP;
1430 if(UIP_EXT_OPT_FIRST->type != HBHO_OPT_TYPE_MPL) {
1431 LOG_ERR(
"Mcast I/O, bad HBHO type\n");
1432 UIP_MCAST6_STATS_ADD(mcast_bad);
1433 return UIP_MCAST6_DROP;
1436 lochbhmptr = UIP_EXT_OPT_FIRST;
1438 LOG_DBG(
"HBHO T=%u, L=%u, M=%u, V=%u, S=%u, SEQ=0x%x\n",
1439 lochbhmptr->type, lochbhmptr->len,
HBH_GET_M(lochbhmptr),
1444 if(in == MPL_DGRAM_IN) {
1445 UIP_MCAST6_STATS_ADD(mcast_in_all);
1451 LOG_ERR(
"Invalid V bit - dropping...\n");
1452 return UIP_MCAST6_DROP;
1456 LOG_DBG(
"Incoming message S value = %u\n", S);
1470 LOG_DBG(
"MPL Domain is ");
1475 locdsptr = domain_set_lookup(&
UIP_IP_BUF->destipaddr);
1478 locdsptr = domain_set_allocate(&
UIP_IP_BUF->destipaddr);
1479 LOG_INFO(
"New MPL Domain ");
1483 LOG_ERR(
"Couldn't add to MPL Domain Set. Dropping.\n");
1484 UIP_MCAST6_STATS_ADD(mcast_dropped);
1485 return UIP_MCAST6_DROP;
1490 MPL_CONTROL_MESSAGE_IMIN,
1491 MPL_CONTROL_MESSAGE_IMAX,
1492 MPL_CONTROL_MESSAGE_K)) {
1493 LOG_ERR(
"Unable to configure trickle timer for domain. Dropping,...\n");
1494 domain_set_free(locdsptr);
1495 return UIP_MCAST6_DROP;
1500 locssptr = seed_set_lookup(&seed_id, locdsptr);
1502 seq_val = lochbhmptr->seq;
1507 LOG_INFO(
"Too old\n");
1508 UIP_MCAST6_STATS_ADD(mcast_dropped);
1509 return UIP_MCAST6_DROP;
1511 if(
list_head(locssptr->min_seq) != NULL) {
1515 LOG_INFO(
"Seen before\n");
1521 UIP_MCAST6_STATS_ADD(mcast_dropped);
1522 return UIP_MCAST6_DROP;
1531 locssptr = seed_set_allocate();
1532 LOG_INFO(
"New seed\n");
1535 LOG_ERR(
"Failed to allocate seed set\n");
1536 UIP_MCAST6_STATS_ADD(mcast_dropped);
1537 return UIP_MCAST6_DROP;
1539 memset(locssptr, 0,
sizeof(
struct mpl_seed));
1542 locssptr->domain = locdsptr;
1546 locmmptr = buffer_allocate();
1548 LOG_INFO(
"Buffer allocation failed. Reclaiming...\n");
1551 LOG_ERR(
"Buffer reclaim failed. Dropping...\n");
1552 UIP_MCAST6_STATS_ADD(mcast_dropped);
1553 return UIP_MCAST6_DROP;
1558 LOG_INFO(
"Message from seed ");
1559 LOG_INFO_SEED(locssptr->seed_id);
1563 uip_ip6addr_copy(&locmmptr->srcipaddr, &
UIP_IP_BUF->srcipaddr);
1566 if(in == MPL_DGRAM_IN) {
1567 UIP_MCAST6_STATS_ADD(mcast_in_unique);
1572 hptr = (
struct uip_ext_hdr *)UIP_EXT_BUF;
1573 while(hptr->next != UIP_PROTO_UDP) {
1574 hptr = ((
void *)hptr) + hptr->len * 8 + 8;
1576 hptr = ((
void *)hptr) + hptr->len * 8 + 8;
1578 memcpy(&locmmptr->data, hptr, locmmptr->size);
1579 locmmptr->seq = seq_val;
1580 locmmptr->seed = locssptr;
1582 MPL_DATA_MESSAGE_IMIN,
1583 MPL_DATA_MESSAGE_IMAX,
1584 MPL_DATA_MESSAGE_K)) {
1585 LOG_ERR(
"Failed to configure timer for message. Dropping...\n");
1586 buffer_free(locmmptr);
1587 return UIP_MCAST6_DROP;
1591 if(
list_head(locssptr->min_seq) == NULL) {
1593 locssptr->min_seqno = locmmptr->seq;
1598 list_insert(locssptr->min_seq, mmiterptr, locmmptr);
1605#if MPL_PROACTIVE_FORWARDING
1610 LOG_INFO(
"Min Seq Number=%u, %u values\n", locssptr->min_seqno, locssptr->count);
1614#if MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS > 0
1631#if MPL_PROACTIVE_FORWARDING
1633 LOG_DBG(
"MPL Domain is inconsistent\n");
1636 LOG_DBG(
"MPL Domain is consistent\n");
1642 return UIP_MCAST6_ACCEPT;
1648 if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1650 if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1651 LOG_ERR(
"Our seed ID is not yet known.\n");
1658 LOG_ERR(
"Multicast Out can not add HBHO. Packet too long\n");
1663 memmove(UIP_EXT_BUF_NEXT, UIP_EXT_BUF,
uip_len - UIP_IPH_LEN);
1664 memset(UIP_EXT_BUF, 0, HBHO_TOTAL_LEN);
1669#if MPL_SEED_ID_TYPE == 0
1670 UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
1671#elif MPL_SEED_ID_TYPE == 1
1672 UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
1673#elif MPL_SEED_ID_TYPE == 2
1674 UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
1675#elif MPL_SEED_ID_TYPE == 3
1676 UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
1680 lochbhmptr = UIP_EXT_OPT_FIRST;
1681 lochbhmptr->type = HBHO_OPT_TYPE_MPL;
1682 lochbhmptr->flags = 0x00;
1686#if MPL_SEED_ID_TYPE == 0
1687 lochbhmptr->len = MPL_OPT_LEN_S0;
1689 lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1690 lochbhmptr->padn.opt_type = 0x00;
1691#elif MPL_SEED_ID_TYPE == 1
1692 lochbhmptr->len = MPL_OPT_LEN_S1;
1694#elif MPL_SEED_ID_TYPE == 2
1695 lochbhmptr->len = MPL_OPT_LEN_S2;
1697 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1698 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
1699#elif MPL_SEED_ID_TYPE == 3
1700 lochbhmptr->len = MPL_OPT_LEN_S3;
1702 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1703 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
1708 lochbhmptr->seq = last_seq;
1719 LOG_INFO(
"Multicast Out\n");
1720 LOG_DBG(
"HBHO: Next Header=0x%x, Header Len (exc. 1st 8 bytes)=%u\n",
1721 UIP_EXT_BUF->next, UIP_EXT_BUF->len);
1722 LOG_DBG(
"MPL Option Type 0x%x: Len=%u, S=%u, M=%u, V=%u, Seq=0x%x\n",
1723 lochbhmptr->type, lochbhmptr->len,
HBH_GET_S(lochbhmptr),
1735 if(
accept(MPL_DGRAM_OUT)) {
1737 UIP_MCAST6_STATS_ADD(mcast_out);
1747 if(!uip_ds6_is_my_maddr(&
UIP_IP_BUF->destipaddr)) {
1748 LOG_INFO(
"Not in our domain. No further processing\n");
1749 return UIP_MCAST6_DROP;
1756 if(
accept(MPL_DGRAM_IN) == UIP_MCAST6_DROP) {
1757 LOG_INFO(
"Packet dropped\n");
1758 return UIP_MCAST6_DROP;
1760 LOG_INFO(
"Ours. Deliver to upper layers\n");
1761 UIP_MCAST6_STATS_ADD(mcast_in_ours);
1762 return UIP_MCAST6_ACCEPT;
1768 LOG_INFO(
"Multicast Protocol for Low Power and Lossy Networks - RFC7731\n");
1783#if MPL_SUB_TO_ALL_FORWARDERS
1785 ALL_MPL_FORWARDERS(&all_forwarders, UIP_MCAST6_SCOPE_REALM_LOCAL);
1786 if(!uip_ds6_maddr_add(&all_forwarders)) {
1787 LOG_ERR(
"Failed to subscribe to All Forwarders MPL Address\n");
Header file for the callback timer.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
static void * list_item_next(const void *item)
Get the next item following this item.
void * list_pop(list_t list)
Remove the first object on a list.
void list_push(list_t list, void *item)
Add an item to the start of the 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.
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
#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.