1/********************************************************************* 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. 3 See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. 4 5 This module handles the equalities between the IGMP and the MLD protocol 6 Authors: Roel Postelmans 7 *********************************************************************/ 8 9#include "pico_stack.h" 10#include "pico_ipv6.h" 11#include "pico_mld.h" 12#include "pico_config.h" 13#include "pico_eth.h" 14#include "pico_addressing.h" 15#include "pico_frame.h" 16#include "pico_tree.h" 17#include "pico_device.h" 18#include "pico_socket.h" 19#include "pico_icmp6.h" 20#include "pico_dns_client.h" 21#include "pico_mld.h" 22#include "pico_igmp.h" 23#include "pico_constants.h" 24#include "pico_mcast.h" 25 26#if (((defined(PICO_SUPPORT_MLD) && defined(PICO_SUPPORT_IPV6)) || defined(PICO_SUPPORT_IGMP)) && defined(PICO_SUPPORT_MCAST)) 27 28#ifdef DEBUG_MCAST 29#define multicast_dbg dbg 30#else 31#define multicast_dbg(...) do {} while(0) 32#endif 33 34#define MCAST_EVENT_DELETE_GROUP (0x0) 35#define MCAST_EVENT_CREATE_GROUP (0x1) 36#define MCAST_EVENT_UPDATE_GROUP (0x2) 37#define MCAST_EVENT_QUERY_RECV (0x3) 38#define MCAST_EVENT_REPORT_RECV (0x4) 39#define MCAST_EVENT_TIMER_EXPIRED (0x5) 40 41#define MCAST_MODE_IS_INCLUDE (1) 42#define MCAST_MODE_IS_EXCLUDE (2) 43#define MCAST_CHANGE_TO_INCLUDE_MODE (3) 44#define MCAST_CHANGE_TO_EXCLUDE_MODE (4) 45 46#define MCAST_MODE_IS_INCLUDE (1) 47#define MCAST_MODE_IS_EXCLUDE (2) 48#define MCAST_CHANGE_TO_INCLUDE_MODE (3) 49#define MCAST_CHANGE_TO_EXCLUDE_MODE (4) 50#define MCAST_ALLOW_NEW_SOURCES (5) 51#define MCAST_BLOCK_OLD_SOURCES (6) 52 53typedef int (*mcast_callback)(struct mcast_filter_parameters *); 54 55static void pico_mcast_src_filtering_cleanup(struct mcast_filter_parameters*mcast ) 56{ 57 struct pico_tree_node *index = NULL, *_tmp = NULL; 58 /* cleanup filters */ 59 pico_tree_foreach_safe(index, mcast->allow, _tmp) 60 { 61 pico_tree_delete(mcast->allow, index->keyValue); 62 } 63 pico_tree_foreach_safe(index, mcast->block, _tmp) 64 { 65 pico_tree_delete(mcast->block, index->keyValue); 66 } 67} 68static int pico_mcast_src_filtering_inc_inc(struct mcast_filter_parameters*mcast ) 69{ 70 struct pico_tree_node *index = NULL; 71 union pico_address *source; 72 /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */ 73 if (mcast->p->event == MCAST_EVENT_DELETE_GROUP) { 74 /* TO_IN (B) */ 75 mcast->record_type = MCAST_CHANGE_TO_INCLUDE_MODE; 76 mcast->filter = mcast->allow; 77 if (mcast->p->MCASTFilter) { 78 pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ 79 { 80 if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { 81 multicast_dbg("MCAST: Failed to insert entry in tree\n"); 82 return -1; 83 } 84 mcast->sources++; 85 } 86 } /* else { allow stays empty } */ 87 88 return 0; 89 } 90 91 /* ALLOW (B-A) */ 92 /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */ 93 if (mcast->p->event == MCAST_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */ 94 mcast->record_type = MCAST_CHANGE_TO_INCLUDE_MODE; 95 else 96 mcast->record_type = MCAST_ALLOW_NEW_SOURCES; 97 98 mcast->filter = mcast->allow; 99 pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ 100 { 101 if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { 102 multicast_dbg("MCAST: Failed to insert entry in tree\n"); 103 return -1; 104 } 105 mcast->sources++; 106 } 107 pico_tree_foreach(index, &mcast->g->MCASTSources) /* A */ 108 { 109 source = pico_tree_findKey(mcast->allow, index->keyValue); 110 if (source) { 111 pico_tree_delete(mcast->allow, source); 112 mcast->sources--; 113 } 114 } 115 if (!pico_tree_empty(mcast->allow)) /* record type is ALLOW */ 116 return 0; 117 118 /* BLOCK (A-B) */ 119 mcast->record_type = MCAST_BLOCK_OLD_SOURCES; 120 mcast->filter = mcast->block; 121 pico_tree_foreach(index, &mcast->g->MCASTSources) /* A */ 122 { 123 if (pico_tree_insert(mcast->block, index->keyValue) == &LEAF) { 124 multicast_dbg("MCAST: Failed to insert entry in tree\n"); 125 return -1; 126 } 127 mcast->sources++; 128 } 129 pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ 130 { 131 source = pico_tree_findKey(mcast->block, index->keyValue); 132 if (source) { 133 pico_tree_delete(mcast->block, source); 134 mcast->sources--; 135 } 136 } 137 if (!pico_tree_empty(mcast->block)) /* record type is BLOCK */ 138 return 0; 139 140 /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report */ 141 (mcast->p)->f = NULL; 142 return MCAST_NO_REPORT; 143} 144 145static int pico_mcast_src_filtering_inc_excl(struct mcast_filter_parameters*mcast ) 146{ 147 struct pico_tree_node *index = NULL; 148 mcast->record_type = MCAST_CHANGE_TO_EXCLUDE_MODE; 149 mcast->filter = mcast->block; 150 pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ 151 { 152 if (pico_tree_insert(mcast->block, index->keyValue) == &LEAF) { 153 multicast_dbg("MCAST: Failed to insert entry in tree\n"); 154 return -1; 155 } 156 mcast->sources++; 157 } 158 return 0; 159} 160static int pico_mcast_src_filtering_excl_inc(struct mcast_filter_parameters*mcast ) 161{ 162 struct pico_tree_node *index = NULL; 163 mcast->record_type = MCAST_CHANGE_TO_INCLUDE_MODE; 164 mcast->filter = mcast->allow; 165 if (mcast->p->MCASTFilter) { 166 pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ 167 { 168 if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { 169 multicast_dbg("MCAST: Failed to insert entry in tree\n"); 170 return -1; 171 } 172 mcast->sources++; 173 } 174 } /* else { allow stays empty } */ 175 176 return 0; 177} 178static int pico_mcast_src_filtering_excl_excl(struct mcast_filter_parameters*mcast ) 179{ 180 struct pico_tree_node *index = NULL; 181 struct pico_ip6 *source = NULL; 182 mcast->record_type = MCAST_BLOCK_OLD_SOURCES; 183 mcast->filter = mcast->block; 184 pico_tree_foreach(index, mcast->p->MCASTFilter) 185 { 186 if (pico_tree_insert(mcast->block, index->keyValue) == &LEAF) { 187 multicast_dbg("MCAST: Failed to insert entry in tree\n"); 188 return -1; 189 } 190 191 mcast->sources++; 192 } 193 pico_tree_foreach(index, &mcast->g->MCASTSources) /* A */ 194 { 195 source = pico_tree_findKey(mcast->block, index->keyValue); /* B */ 196 if (source) { 197 pico_tree_delete(mcast->block, source); 198 mcast->sources--; 199 } 200 } 201 if (!pico_tree_empty(mcast->block)) /* record type is BLOCK */ 202 return 0; 203 204 /* ALLOW (A-B) */ 205 mcast->record_type = MCAST_ALLOW_NEW_SOURCES; 206 mcast->filter = mcast->allow; 207 pico_tree_foreach(index, &mcast->g->MCASTSources) 208 { 209 if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { 210 multicast_dbg("MCAST: Failed to insert entry in tree\n"); 211 return -1; 212 } 213 mcast->sources++; 214 } 215 pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ 216 { 217 source = pico_tree_findKey(mcast->allow, index->keyValue); /* A */ 218 if (source) { 219 pico_tree_delete(mcast->allow, source); 220 mcast->sources--; 221 } 222 } 223 if (!pico_tree_empty(mcast->allow)) /* record type is ALLOW */ 224 return 0; 225 226 /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report */ 227 mcast->p->f = NULL; 228 return MCAST_NO_REPORT; 229} 230static const mcast_callback mcast_filter_state[2][2] = 231{ 232 { pico_mcast_src_filtering_excl_excl, pico_mcast_src_filtering_excl_inc}, 233 { pico_mcast_src_filtering_inc_excl, pico_mcast_src_filtering_inc_inc } 234}; 235int8_t pico_mcast_generate_filter(struct mcast_filter_parameters *filter, struct mcast_parameters *p) 236{ 237 int ret = -1; 238 /* "non-existent" state of filter mode INCLUDE and empty source list */ 239 if (p->event == MCAST_EVENT_DELETE_GROUP) { 240 p->filter_mode = PICO_IP_MULTICAST_INCLUDE; 241 p->MCASTFilter = NULL; 242 } 243 244 if (p->event == MCAST_EVENT_QUERY_RECV) 245 return 0; 246 247 pico_mcast_src_filtering_cleanup(filter); 248 249 if(filter->g->filter_mode <= PICO_IP_MULTICAST_INCLUDE ) 250 { 251 if(p->filter_mode <= PICO_IP_MULTICAST_INCLUDE) 252 { 253 ret = mcast_filter_state[filter->g->filter_mode][p->filter_mode](filter); 254 } 255 } 256 257 return (int8_t) ret; 258} 259#endif 260