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(locssptr->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)
762 uint16_t payload_len;
764 size_t seed_info_len;
766 LOG_INFO(
"MPL Control Message Out\n");
774 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
778 uip_ip6addr_copy(&
UIP_IP_BUF->destipaddr, &dom->ctrl_addr);
782 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
784 locsiptr->min_seqno = locssptr->min_seqno;
789 addr = uip_ds6_get_global(ADDR_PREFERRED);
791 uip_ip6addr_copy(&
UIP_IP_BUF->srcipaddr, &addr->ipaddr);
796 LOG_ERR(
"icmp out: Cannot set src ip\n");
803 switch(locssptr->seed_id.s) {
805 if(uip_ip6addr_cmp((uip_ip6addr_t *)&locssptr->seed_id.id, &
UIP_IP_BUF->srcipaddr)) {
825 memset(vector, 0,
sizeof(vector));
828 while(locmmptr != NULL) {
829 if(locmmptr->seq ==
SEQ_VAL_ADD(locssptr->min_seqno, vec_len)) {
837 vec_size = (vec_len - 1) / 8 + 1;
841 LOG_DBG(
"--- Control Message Entry ---\n");
842 LOG_DBG(
"Seed ID: ");
843 LOG_DBG_SEED(locssptr->seed_id);
845 LOG_DBG(
"S=%u\n", locssptr->seed_id.s);
846 LOG_DBG(
"Min Sequence Number: %u\n", locssptr->min_seqno);
847 LOG_DBG(
"Size of message set: %u\n", vec_len);
848 LOG_DBG(
"Vector is %u bytes\n", vec_size);
853 seed_info_len =
sizeof(
struct seed_info);
856 seed_info_len =
sizeof(
struct seed_info_s1);
859 seed_info_len =
sizeof(
struct seed_info_s2);
862 seed_info_len =
sizeof(
struct seed_info_s3);
865 memcpy(((
void *)locsiptr) + seed_info_len, vector, vec_size);
866 locsiptr = ((
void *)locsiptr) + seed_info_len + vec_size;
867 payload_len += seed_info_len + vec_size;
871 LOG_DBG(
"--- End of Messages --\n");
874 uipbuf_set_len_field(
UIP_IP_BUF, UIP_ICMPH_LEN + payload_len);
877 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
881 LOG_DBG(
"ICMP Out from ");
887 LOG_DBG(
"MPL Contol Message Out - %u bytes\n", payload_len);
891 MPL_STATS_ADD(icmp_out);
895 data_message_expiration(
void *ptr, uint8_t suppress)
898 locmmptr = ((
struct mpl_msg *)ptr);
904 if(suppress == TRICKLE_TIMER_TX_OK) {
905 LOG_DBG(
"Data message TX\n");
907 LOG_DBG_SEED(locmmptr->seed->seed_id);
908 LOG_DBG_(
", S=%u, Seq=%u\n", locmmptr->seed->seed_id.s, locmmptr->seq);
915 uip_ip6addr_copy(&
UIP_IP_BUF->destipaddr, &locmmptr->seed->domain->data_addr);
918 UIP_EXT_BUF->next = UIP_PROTO_UDP;
919 lochbhmptr = UIP_EXT_OPT_FIRST;
920 lochbhmptr->type = HBHO_OPT_TYPE_MPL;
921 lochbhmptr->flags = 0x00;
922 switch(locmmptr->seed->seed_id.s) {
924 UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
925 lochbhmptr->len = MPL_OPT_LEN_S0;
928 uip_len += HBHO_BASE_LEN + HBHO_S0_LEN;
930 lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
931 lochbhmptr->padn.opt_len = 0x00;
934 UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
935 lochbhmptr->len = MPL_OPT_LEN_S1;
938 seed_id_host_to_net(&((
struct mpl_hbho_s1 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
939 uip_len += HBHO_BASE_LEN + HBHO_S1_LEN;
943 UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
944 lochbhmptr->len = MPL_OPT_LEN_S2;
947 seed_id_host_to_net(&((
struct mpl_hbho_s2 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
948 uip_len += HBHO_BASE_LEN + HBHO_S2_LEN;
950 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
951 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
954 UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
955 lochbhmptr->len = MPL_OPT_LEN_S3;
958 seed_id_host_to_net(&((
struct mpl_hbho_s3 *)lochbhmptr)->seed_id, &locmmptr->seed->seed_id);
959 uip_len += HBHO_BASE_LEN + HBHO_S3_LEN;
961 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
962 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
965 lochbhmptr->seq = locmmptr->seq;
970 memcpy(((
void *)UIP_EXT_BUF) + 8 + UIP_EXT_BUF->len * 8, &locmmptr->data, locmmptr->size);
973 uip_ip6addr_copy(&
UIP_IP_BUF->srcipaddr, &locmmptr->srcipaddr);
976 UIP_MCAST6_STATS_ADD(mcast_out);
982 control_message_expiration(
void *ptr, uint8_t suppress)
985 locdsptr = ((
struct mpl_domain *)ptr);
991 if(suppress == TRICKLE_TIMER_TX_OK) {
998 mpl_maddr_check(
void)
1002 for(elem = &
uip_ds6_if.maddr_list[UIP_DS6_MADDR_NB - 1];
1006 locdsptr = domain_set_lookup(&elem->ipaddr);
1008 locdsptr = domain_set_allocate(&elem->ipaddr);
1010 LOG_ERR(
"Failed to allocate domain set in mpl_maddr_check()\n");
1016 for(locdsptr = &domain_set[
MPL_DOMAIN_SET_SIZE - 1]; locdsptr >= domain_set; locdsptr--) {
1018 domain_set_free(locdsptr);
1023 lifetime_timer_expiration(
void *ptr)
1026 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; seed_set <= locssptr; locssptr--) {
1029 locmmptr =
list_head(locssptr->min_seq);
1030 while(locmmptr != NULL) {
1037 if(locmmptr == NULL) {
1040 LOG_INFO_SEED(locssptr->seed_id);
1041 LOG_INFO_(
" expired. Freeing...\n");
1042 seed_set_free(locssptr);
1045 if(locssptr->lifetime > 0) {
1046 locssptr->lifetime--;
1055 static seed_id_t seed_id;
1057 static uint8_t *vector;
1058 static uint8_t vector_len;
1059 static uint8_t r_missing;
1060 static uint8_t l_missing;
1062 LOG_INFO(
"MPL ICMP Control Message In\n");
1064 #if UIP_CONF_IPV6_CHECKS 1066 LOG_ERR(
"ICMPv6 In, bad dest ");
1069 MPL_STATS_ADD(icmp_bad);
1074 LOG_ERR(
"ICMPv6 In, bad ICMP type\n");
1075 MPL_STATS_ADD(icmp_bad);
1080 LOG_ERR(
"ICMPv6 In, bad ICMP type\n");
1081 MPL_STATS_ADD(icmp_bad);
1086 LOG_ERR(
"ICMPv6 In, bad TTL\n");
1087 MPL_STATS_ADD(icmp_bad);
1092 LOG_INFO(
"MPL ICMP Control Message from ");
1099 locdsptr = domain_set_lookup(&
UIP_IP_BUF->destipaddr);
1102 LOG_INFO(
"New MPL Domain ");
1105 locdsptr = domain_set_allocate(&
UIP_IP_BUF->destipaddr);
1107 LOG_ERR(
"Couldn't allocate new domain. Dropping.\n");
1108 UIP_MCAST6_STATS_ADD(icmp_bad);
1117 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
1118 for(locssptr = &seed_set[
MPL_SEED_SET_SIZE - 1]; locssptr >= seed_set; locssptr--) {
1120 LOG_DBG(
"Checking remote for seed ");
1121 LOG_DBG_SEED(locssptr->seed_id);
1124 (
struct seed_info *)((
void *)UIP_ICMP_PAYLOAD +
uip_len - uip_l3_icmp_hdr_len)) {
1128 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info) + SEED_INFO_GET_LEN(locsiptr);
1135 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1) + SEED_INFO_GET_LEN(locsiptr);
1142 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2) + SEED_INFO_GET_LEN(locsiptr);
1149 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3) + SEED_INFO_GET_LEN(locsiptr);
1157 LOG_DBG(
"Remote is missing seed ");
1158 LOG_DBG_SEED(locssptr->seed_id);
1161 if(
list_head(locssptr->min_seq) != NULL) {
1163 LOG_DBG(
"Resetting timer for messages\n");
1165 LOG_DBG(
"Starting timer for messages\n");
1178 locsiptr = (
struct seed_info *)UIP_ICMP_PAYLOAD;
1180 (
struct seed_info *)((
void *)UIP_ICMP_PAYLOAD +
uip_len - uip_l3_icmp_hdr_len)) {
1189 LOG_DBG(
"Control Message for Seed Id: ");
1190 LOG_DBG_SEED(seed_id);
1191 LOG_DBG_(
"Min Seq Number: %u, %u bytes\n", locsiptr->min_seqno,
SEED_INFO_GET_LEN(locsiptr));
1194 locssptr = seed_set_lookup(&seed_id, locdsptr);
1196 LOG_DBG(
"Unknown seed in seed info\n");
1206 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info);
1209 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1);
1212 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2);
1215 vector = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3);
1220 locmmptr =
list_head(locssptr->min_seq);
1221 if(locmmptr == NULL) {
1234 if(locmmptr->seq != locsiptr->min_seqno) {
1236 while(locmmptr->seq !=
SEQ_VAL_ADD(locsiptr->min_seqno, r) && r <= vector_len) {
1240 while(locmmptr != NULL && locmmptr->seq != locsiptr->min_seqno) {
1246 if(r > vector_len || locmmptr == NULL) {
1247 LOG_WARN(
"Seed sets of local and remote have no overlap.\n");
1249 locmmptr =
list_head(locssptr->min_seq);
1259 LOG_DBG(
"Our max sequence number is greater than their max sequence number\n");
1262 if(
list_head(locssptr->min_seq) != NULL) {
1284 while(locmmptr->seq !=
SEQ_VAL_ADD(locsiptr->min_seqno, r)) {
1291 LOG_DBG(
"We are missing seq=%u\n",
SEQ_VAL_ADD(locsiptr->min_seqno, r));
1301 LOG_DBG(
"Remote is missing seq=%u\n", locmmptr->seq);
1313 }
while(locmmptr != NULL && r <= vector_len);
1316 if(locmmptr != NULL || r < vector_len) {
1321 while(r < vector_len) {
1324 LOG_DBG(
"We are missing seq=%u which is greater than our max seq number\n",
SEQ_VAL_ADD(locsiptr->min_seqno, r));
1329 }
else if(r >= vector_len && locmmptr != NULL) {
1333 while(locmmptr != NULL) {
1334 LOG_DBG(
"Remote is missing all above seq=%u\n", locmmptr->seq);
1347 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info) + SEED_INFO_GET_LEN(locsiptr);
1350 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s1) + SEED_INFO_GET_LEN(locsiptr);
1353 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s2) + SEED_INFO_GET_LEN(locsiptr);
1356 locsiptr = ((
void *)locsiptr) +
sizeof(
struct seed_info_s3) + SEED_INFO_GET_LEN(locsiptr);
1365 if(l_missing || r_missing) {
1366 LOG_INFO(
"Inconsistency detected l=%u, r=%u\n", l_missing, r_missing);
1371 LOG_INFO(
"Domain is consistent \n");
1383 static seed_id_t seed_id;
1384 static uint16_t seq_val;
1386 static struct mpl_msg *mmiterptr;
1387 static struct uip_ext_hdr *hptr;
1389 LOG_INFO(
"Multicast I/O\n");
1391 #if UIP_CONF_IPV6_CHECKS 1393 LOG_ERR(
"Mcast I/O, bad destination\n");
1394 UIP_MCAST6_STATS_ADD(mcast_bad);
1395 return UIP_MCAST6_DROP;
1402 LOG_ERR(
"Mcast I/O, bad source\n");
1403 UIP_MCAST6_STATS_ADD(mcast_bad);
1404 return UIP_MCAST6_DROP;
1408 if(uip_ds6_is_my_addr(&
UIP_IP_BUF->srcipaddr) && in == MPL_DGRAM_IN) {
1409 LOG_WARN(
"Received message from ourselves.\n");
1410 return UIP_MCAST6_DROP;
1415 LOG_ERR(
"Mcast I/O, bad proto\n");
1416 LOG_DBG(
"Next Proto was %u\n",
UIP_IP_BUF->proto);
1417 UIP_MCAST6_STATS_ADD(mcast_bad);
1418 return UIP_MCAST6_DROP;
1421 if(UIP_EXT_OPT_FIRST->type != HBHO_OPT_TYPE_MPL) {
1422 LOG_ERR(
"Mcast I/O, bad HBHO type\n");
1423 UIP_MCAST6_STATS_ADD(mcast_bad);
1424 return UIP_MCAST6_DROP;
1427 lochbhmptr = UIP_EXT_OPT_FIRST;
1429 LOG_DBG(
"HBHO T=%u, L=%u, M=%u, V=%u, S=%u, SEQ=0x%x\n",
1430 lochbhmptr->type, lochbhmptr->len,
HBH_GET_M(lochbhmptr),
1434 #if UIP_MCAST6_STATS 1435 if(in == MPL_DGRAM_IN) {
1436 UIP_MCAST6_STATS_ADD(mcast_in_all);
1442 LOG_ERR(
"Invalid V bit - dropping...\n");
1443 return UIP_MCAST6_DROP;
1447 LOG_DBG(
"Incoming message S value = %u\n", S);
1461 LOG_DBG(
"MPL Domain is ");
1466 locdsptr = domain_set_lookup(&
UIP_IP_BUF->destipaddr);
1469 locdsptr = domain_set_allocate(&
UIP_IP_BUF->destipaddr);
1470 LOG_INFO(
"New MPL Domain ");
1474 LOG_ERR(
"Couldn't add to MPL Domain Set. Dropping.\n");
1475 UIP_MCAST6_STATS_ADD(mcast_dropped);
1476 return UIP_MCAST6_DROP;
1481 MPL_CONTROL_MESSAGE_IMIN,
1482 MPL_CONTROL_MESSAGE_IMAX,
1483 MPL_CONTROL_MESSAGE_K)) {
1484 LOG_ERR(
"Unable to configure trickle timer for domain. Dropping,...\n");
1485 domain_set_free(locdsptr);
1486 return UIP_MCAST6_DROP;
1491 locssptr = seed_set_lookup(&seed_id, locdsptr);
1493 seq_val = lochbhmptr->seq;
1498 LOG_INFO(
"Too old\n");
1499 UIP_MCAST6_STATS_ADD(mcast_dropped);
1500 return UIP_MCAST6_DROP;
1502 if(
list_head(locssptr->min_seq) != NULL) {
1506 LOG_INFO(
"Seen before\n");
1512 UIP_MCAST6_STATS_ADD(mcast_dropped);
1513 return UIP_MCAST6_DROP;
1522 locssptr = seed_set_allocate();
1523 LOG_INFO(
"New seed\n");
1526 LOG_ERR(
"Failed to allocate seed set\n");
1527 UIP_MCAST6_STATS_ADD(mcast_dropped);
1528 return UIP_MCAST6_DROP;
1530 memset(locssptr, 0,
sizeof(
struct mpl_seed));
1533 locssptr->domain = locdsptr;
1537 locmmptr = buffer_allocate();
1539 LOG_INFO(
"Buffer allocation failed. Reclaiming...\n");
1542 LOG_ERR(
"Buffer reclaim failed. Dropping...\n");
1543 UIP_MCAST6_STATS_ADD(mcast_dropped);
1544 return UIP_MCAST6_DROP;
1549 LOG_INFO(
"Message from seed ");
1550 LOG_INFO_SEED(locssptr->seed_id);
1554 uip_ip6addr_copy(&locmmptr->srcipaddr, &
UIP_IP_BUF->srcipaddr);
1556 #if UIP_MCAST6_STATS 1557 if(in == MPL_DGRAM_IN) {
1558 UIP_MCAST6_STATS_ADD(mcast_in_unique);
1563 hptr = (
struct uip_ext_hdr *)UIP_EXT_BUF;
1564 while(hptr->next != UIP_PROTO_UDP) {
1565 hptr = ((
void *)hptr) + hptr->len * 8 + 8;
1567 hptr = ((
void *)hptr) + hptr->len * 8 + 8;
1569 memcpy(&locmmptr->data, hptr, locmmptr->size);
1570 locmmptr->seq = seq_val;
1571 locmmptr->seed = locssptr;
1573 MPL_DATA_MESSAGE_IMIN,
1574 MPL_DATA_MESSAGE_IMAX,
1575 MPL_DATA_MESSAGE_K)) {
1576 LOG_ERR(
"Failed to configure timer for message. Dropping...\n");
1577 buffer_free(locmmptr);
1578 return UIP_MCAST6_DROP;
1582 if(
list_head(locssptr->min_seq) == NULL) {
1584 locssptr->min_seqno = locmmptr->seq;
1589 list_insert(locssptr->min_seq, mmiterptr, locmmptr);
1596 #if MPL_PROACTIVE_FORWARDING 1601 LOG_INFO(
"Min Seq Number=%u, %u values\n", locssptr->min_seqno, locssptr->count);
1605 #if MPL_CONTROL_MESSAGE_TIMER_EXPIRATIONS > 0 1622 #if MPL_PROACTIVE_FORWARDING 1624 LOG_DBG(
"MPL Domain is inconsistent\n");
1627 LOG_DBG(
"MPL Domain is consistent\n");
1633 return UIP_MCAST6_ACCEPT;
1639 if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1641 if(local_seed_id.s == MPL_SEED_ID_UNKNOWN) {
1642 LOG_ERR(
"Our seed ID is not yet known.\n");
1649 LOG_ERR(
"Multicast Out can not add HBHO. Packet too long\n");
1654 memmove(UIP_EXT_BUF_NEXT, UIP_EXT_BUF,
uip_len - UIP_IPH_LEN);
1655 memset(UIP_EXT_BUF, 0, HBHO_TOTAL_LEN);
1660 #if MPL_SEED_ID_TYPE == 0 1661 UIP_EXT_BUF->len = HBHO_S0_LEN / 8;
1662 #elif MPL_SEED_ID_TYPE == 1 1663 UIP_EXT_BUF->len = HBHO_S1_LEN / 8;
1664 #elif MPL_SEED_ID_TYPE == 2 1665 UIP_EXT_BUF->len = HBHO_S2_LEN / 8;
1666 #elif MPL_SEED_ID_TYPE == 3 1667 UIP_EXT_BUF->len = HBHO_S3_LEN / 8;
1671 lochbhmptr = UIP_EXT_OPT_FIRST;
1672 lochbhmptr->type = HBHO_OPT_TYPE_MPL;
1673 lochbhmptr->flags = 0x00;
1677 #if MPL_SEED_ID_TYPE == 0 1678 lochbhmptr->len = MPL_OPT_LEN_S0;
1680 lochbhmptr->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1681 lochbhmptr->padn.opt_type = 0x00;
1682 #elif MPL_SEED_ID_TYPE == 1 1683 lochbhmptr->len = MPL_OPT_LEN_S1;
1685 #elif MPL_SEED_ID_TYPE == 2 1686 lochbhmptr->len = MPL_OPT_LEN_S2;
1688 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1689 ((
struct mpl_hbho_s2 *)lochbhmptr)->padn.opt_len = 0x00;
1690 #elif MPL_SEED_ID_TYPE == 3 1691 lochbhmptr->len = MPL_OPT_LEN_S3;
1693 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_type = UIP_EXT_HDR_OPT_PADN;
1694 ((
struct mpl_hbho_s3 *)lochbhmptr)->padn.opt_len = 0x00;
1699 lochbhmptr->seq = last_seq;
1710 LOG_INFO(
"Multicast Out\n");
1711 LOG_DBG(
"HBHO: Next Header=0x%x, Header Len (exc. 1st 8 bytes)=%u\n",
1712 UIP_EXT_BUF->next, UIP_EXT_BUF->len);
1713 LOG_DBG(
"MPL Option Type 0x%x: Len=%u, S=%u, M=%u, V=%u, Seq=0x%x\n",
1714 lochbhmptr->type, lochbhmptr->len,
HBH_GET_S(lochbhmptr),
1726 if(
accept(MPL_DGRAM_OUT)) {
1728 UIP_MCAST6_STATS_ADD(mcast_out);
1738 if(!uip_ds6_is_my_maddr(&
UIP_IP_BUF->destipaddr)) {
1739 LOG_INFO(
"Not in our domain. No further processing\n");
1740 return UIP_MCAST6_DROP;
1747 if(
accept(MPL_DGRAM_IN) == UIP_MCAST6_DROP) {
1748 LOG_INFO(
"Packet dropped\n");
1749 return UIP_MCAST6_DROP;
1751 LOG_INFO(
"Ours. Deliver to upper layers\n");
1752 UIP_MCAST6_STATS_ADD(mcast_in_ours);
1753 return UIP_MCAST6_ACCEPT;
1759 LOG_INFO(
"Multicast Protocol for Low Power and Lossy Networks - RFC7731\n");
1774 #if MPL_SUB_TO_ALL_FORWARDERS 1776 ALL_MPL_FORWARDERS(&all_forwarders, UIP_MCAST6_SCOPE_REALM_LOCAL);
1777 if(!uip_ds6_maddr_add(&all_forwarders)) {
1778 LOG_ERR(
"Failed to subscribe to All Forwarders MPL Address\n");
#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)