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 84 typedef 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 337 struct seed_info_s1 {
342 struct seed_info_s2 {
347 struct seed_info_s3 {
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() 402 static uint16_t last_seq;
403 static seed_id_t local_seed_id;
404 #if MPL_SUB_TO_ALL_FORWARDERS 405 static uip_ip6addr_t all_forwarders;
407 static struct ctimer lifetime_timer;
411 static struct mpl_hbho *lochbhmptr;
412 static struct mpl_seed *locssptr;
413 static struct mpl_msg *locmmptr;
414 static struct mpl_domain *locdsptr;
415 static 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)) 422 extern 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_MCAST6_SCOPE_LINK_LOCAL) 469 static struct mpl_msg *
470 buffer_allocate(
void)
474 memset(locmmptr, 0,
sizeof(
struct mpl_msg));
481 buffer_free(
struct mpl_msg *msg)
488 static 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));
521 static struct mpl_domain *
522 domain_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");
537 }
while(data_addr.u8[1] <= 5);
538 if(data_addr.u8[1] > 5) {
539 LOG_ERR(
"Failed to find MPL domain data address in table\n");
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");
573 static struct mpl_seed *
574 seed_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--) {
583 static struct mpl_seed *
584 seed_set_allocate(
void)
586 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
596 seed_set_free(
struct mpl_seed *s)
598 while((locmmptr =
list_pop(s->min_seq)) != NULL) {
599 buffer_free(locmmptr);
603 static struct mpl_domain *
604 domain_set_lookup(uip_ip6addr_t *domain)
608 if(uip_ip6addr_cmp(domain, &locdsptr->data_addr)
609 || uip_ip6addr_cmp(domain, &locdsptr->ctrl_addr)) {
617 domain_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);
757 icmp_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);
792 uip_ip6addr_copy(&
UIP_IP_BUF->srcipaddr, &addr->ipaddr);
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);
905 data_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);
992 control_message_expiration(
void *ptr, uint8_t suppress)
995 locdsptr = ((
struct mpl_domain *)ptr);
1001 if(suppress == TRICKLE_TIMER_TX_OK) {
1008 mpl_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);
1033 lifetime_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),
1444 #if UIP_MCAST6_STATS 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);
1566 #if UIP_MCAST6_STATS 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");
#define MPL_IP_HOP_LIMIT
Hop limit for ICMP messages.
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
#define UIP_IP_BUF
Direct access to IPv6 header.
#define mpl_trickle_timer_inconsistency(t)
Call inconsistency on the provided timer t: Pointer to set that should be reset.
uint8_t tcpip_output(const uip_lladdr_t *a)
Output packet to layer 2 The eventual parameter is the MAC address of the destination.
Header file for ICMPv6 message and error handing (RFC 4443)
#define MSG_SET_IS_USED(h)
Get the state of the used flag in the buffered message set entry h: pointer to the message set entry...
#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 mpl_trickle_timer_reset(t)
Reset the trickle timer and expiration count for the set t: Pointer to set that should be reset...
#define MPL_BUFFERED_MESSAGE_SET_SIZE
Buffered Message Set Size MPL Forwarders maintain a buffer of data messages that are periodically for...
#define MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS
Control Message Timer Expirations An MPL Forwarder forwards MPL messages for a particular domain usin...
#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...
uint16_t uip_len
The length of the packet in the uip_buf buffer.
void list_push(list_t list, void *item)
Add an item to the start of the list.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
The data structure used to represent a multicast engine.
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
Trickle timer library header file.
#define UIP_ICMP_BUF
Direct access to ICMP, UDP, and TCP headers and payload, with implicit ext header offset (global uip_...
void trickle_timer_consistency(struct trickle_timer *tt)
To be called by the protocol when it hears a consistent transmission.
const struct uip_mcast6_driver mpl_driver
The MPL engine driver.
#define UIP_PROTO_HBHO
extension headers types
#define UIP_BUFSIZE
The size of the uIP packet buffer.
#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 trickle_timer_stop(tt)
Stop a running trickle timer.
#define HBH_SET_M(h)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
static void icmp_in(void)
void list_insert(list_t list, void *previtem, void *newitem)
Insert an item after a specified item on the list.
#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...
static struct mpl_msg * buffer_reclaim(void)
#define SEED_INFO_SET_LEN(h, l)
Set the length bits in the seed info struct.
#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...
uint8_t trickle_timer_config(struct trickle_timer *tt, clock_time_t i_min, uint8_t i_max, uint8_t k)
Configure a trickle timer.
#define UIP_ADDR_MAKE_LINK_LOCAL(a)
Modify an ipv6 address to give it link local scope a: uip_ip6addr_t address to modify.
#define SEQ_VAL_IS_LT(i1, i2)
s1 is said to be less than s2 if SEQ_VAL_IS_LT(s1, s2) == 1
#define HBH_SET_S(h, s)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
static uint8_t accept(uint8_t in)
Header file for the implementation of the MPL protocol.
#define trickle_timer_is_running(tt)
To be called in order to determine whether a trickle timer is running.
Header file for IPv6-related data structures.
#define BIT_VECTOR_GET_BIT(v, b)
Get the value of a bit in a bit vector v: The bit vector b: The 0-indexed bit to get.
#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 ...
#define HBH_CLR_V(h)
Set the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
#define SEQ_VAL_IS_GT(i1, i2)
s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1
Multicast stats extension for the MPL engine.
#define SEED_INFO_SET_S(h, s)
Set the S bits within the seed info struct.
This header file contains configuration directives for uIPv6 multicast support.
#define CLOCK_SECOND
A second, measured in system clock time.
uint16_t uip_ext_len
The length of the extension headers.
#define SEED_INFO_GET_LEN(h)
Get the length bits from the seed info struct.
#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...
Header file for the callback timer
uint8_t(* in)(void)
Process an incoming multicast datagram and determine whether it should be delivered up the stack or n...
#define HBH_GET_S(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
#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...
Linked list manipulation routines.
#define uip_is_addr_mcast_non_routable(a)
is address a non-routable multicast address.
#define SEQ_VAL_IS_EQ(i1, i2)
s1 is said to be equal s2 if SEQ_VAL_IS_EQ(s1, s2) == 1
#define mpl_data_trickle_timer_start(t)
Start the trickle timer for a data message t: Pointer to set that should be reset.
#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...
void * list_head(list_t list)
Get a pointer to the first element of a list.
#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...
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Unicast address structure.
static void seed_id_host_to_net(void *dst, seed_id_t *src)
#define mpl_control_trickle_timer_start(t)
Start the trickle timer for a control message t: Pointer to set that should be reset.
#define HBH_GET_M(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
#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...
void(* out)(void)
Process an outgoing datagram with a multicast IPv6 destination address.
#define SEED_INFO_CLR_LEN(h)
Clear the length bits in the seed info struct.
#define MPL_DOMAIN_SET_SIZE
Domain Set Size MPL Forwarders maintain a Domain Set which maps MPL domains to trickle timers...
Header file for the uIP TCP/IP stack.
void(* init)(void)
Initialize the multicast engine.
uip_ds6_netif_t uip_ds6_if
The single interface.
#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 ...
uint16_t uip_icmp6chksum(void)
Calculate the ICMP checksum of the packet in uip_buf.
void * list_pop(list_t list)
Remove the first object on a list.
#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 LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
#define seed_id_cpy(a, b)
Copy one seed_id_t into another.
#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 MPL_SEED_ID_L
Seed ID Alias Points to MPL_CONF_SEED_ID_L.
#define HBH_GET_V(h)
Get the MPL Parametrization for a multicast HBHO header m: pointer to the HBHO header.
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
Register a handler which can handle a specific ICMPv6 message type.
Header file for the logging system
#define HBH_CLR_S(h)
Clear the MPL Parametrization bit for a multicast HBHO header m: pointer to the HBHO header...
#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...
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
#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...
void * list_item_next(void *item)
Get the next item following this item.
static void seed_id_net_to_host(seed_id_t *dst, void *src, uint8_t s)
#define uip_mcast6_get_address_scope(a)
Get a multicast address' scope.
#define MPL_DATA_MESSAGE_TIMER_EXPIRATIONS
Data Message Timer Expirations MPL data message trickle timers are stopped after they expire a set nu...
#define SEQ_VAL_ADD(s, n)
Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000)