Free (GPLv2) TCP/IP stack developed by TASS Belgium
Dependents: lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more
pico_igmp.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 RFC 1112, 2236, 3376, 3569, 3678, 4607 00006 00007 Authors: Kristof Roelants (IGMPv3), Simon Maes, Brecht Van Cauwenberghe 00008 *********************************************************************/ 00009 00010 #include "pico_stack.h" 00011 #include "pico_ipv4.h" 00012 #include "pico_igmp.h" 00013 #include "pico_config.h" 00014 #include "pico_eth.h" 00015 #include "pico_addressing.h" 00016 #include "pico_frame.h" 00017 #include "pico_tree.h" 00018 #include "pico_device.h" 00019 #include "pico_socket.h" 00020 00021 #if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST) 00022 00023 #define igmp_dbg(...) do {} while(0) 00024 /* #define igmp_dbg dbg */ 00025 00026 /* membership states */ 00027 #define IGMP_STATE_NON_MEMBER (0x0) 00028 #define IGMP_STATE_DELAYING_MEMBER (0x1) 00029 #define IGMP_STATE_IDLE_MEMBER (0x2) 00030 00031 /* events */ 00032 #define IGMP_EVENT_DELETE_GROUP (0x0) 00033 #define IGMP_EVENT_CREATE_GROUP (0x1) 00034 #define IGMP_EVENT_UPDATE_GROUP (0x2) 00035 #define IGMP_EVENT_QUERY_RECV (0x3) 00036 #define IGMP_EVENT_REPORT_RECV (0x4) 00037 #define IGMP_EVENT_TIMER_EXPIRED (0x5) 00038 00039 /* message types */ 00040 #define IGMP_TYPE_MEM_QUERY (0x11) 00041 #define IGMP_TYPE_MEM_REPORT_V1 (0x12) 00042 #define IGMP_TYPE_MEM_REPORT_V2 (0x16) 00043 #define IGMP_TYPE_LEAVE_GROUP (0x17) 00044 #define IGMP_TYPE_MEM_REPORT_V3 (0x22) 00045 00046 /* group record types */ 00047 #define IGMP_MODE_IS_INCLUDE (1) 00048 #define IGMP_MODE_IS_EXCLUDE (2) 00049 #define IGMP_CHANGE_TO_INCLUDE_MODE (3) 00050 #define IGMP_CHANGE_TO_EXCLUDE_MODE (4) 00051 #define IGMP_ALLOW_NEW_SOURCES (5) 00052 #define IGMP_BLOCK_OLD_SOURCES (6) 00053 00054 /* host flag */ 00055 #define IGMP_HOST_LAST (0x1) 00056 #define IGMP_HOST_NOT_LAST (0x0) 00057 00058 /* list of timers, counters and their default values */ 00059 #define IGMP_ROBUSTNESS (2u) 00060 #define IGMP_QUERY_INTERVAL (125) /* secs */ 00061 #define IGMP_QUERY_RESPONSE_INTERVAL (10u) /* secs */ 00062 #define IGMP_STARTUP_QUERY_INTERVAL (IGMPV3_QUERY_INTERVAL / 4) 00063 #define IGMP_STARTUP_QUERY_COUNT (IGMPV3_ROBUSTNESS) 00064 #define IGMP_LAST_MEMBER_QUERY_INTERVAL (1) /* secs */ 00065 #define IGMP_LAST_MEMBER_QUERY_COUNT (IGMPV3_ROBUSTNESS) 00066 #define IGMP_UNSOLICITED_REPORT_INTERVAL (1) /* secs */ 00067 #define IGMP_DEFAULT_MAX_RESPONSE_TIME (100) 00068 00069 /* custom timers types */ 00070 #define IGMP_TIMER_GROUP_REPORT (1) 00071 #define IGMP_TIMER_V1_QUERIER (2) 00072 #define IGMP_TIMER_V2_QUERIER (3) 00073 00074 /* IGMP groups */ 00075 #define IGMP_ALL_HOST_GROUP long_be(0xE0000001) /* 224.0.0.1 */ 00076 #define IGMP_ALL_ROUTER_GROUP long_be(0xE0000002) /* 224.0.0.2 */ 00077 #define IGMPV3_ALL_ROUTER_GROUP long_be(0xE0000016) /* 224.0.0.22 */ 00078 00079 /* misc */ 00080 #define IGMP_TIMER_STOPPED (1) 00081 #define IP_OPTION_ROUTER_ALERT_LEN (4u) 00082 #define IGMP_MAX_GROUPS (32) /* max 255 */ 00083 00084 PACKED_STRUCT_DEF igmp_message { 00085 uint8_t type; 00086 uint8_t max_resp_time; 00087 uint16_t crc; 00088 uint32_t mcast_group; 00089 }; 00090 00091 PACKED_STRUCT_DEF igmpv3_query { 00092 uint8_t type; 00093 uint8_t max_resp_time; 00094 uint16_t crc; 00095 uint32_t mcast_group; 00096 uint8_t rsq; 00097 uint8_t qqic; 00098 uint16_t sources; 00099 }; 00100 00101 PACKED_STRUCT_DEF igmpv3_group_record { 00102 uint8_t type; 00103 uint8_t aux; 00104 uint16_t sources; 00105 uint32_t mcast_group; 00106 }; 00107 00108 PACKED_STRUCT_DEF igmpv3_report { 00109 uint8_t type; 00110 uint8_t res0; 00111 uint16_t crc; 00112 uint16_t res1; 00113 uint16_t groups; 00114 }; 00115 00116 struct igmp_parameters { 00117 uint8_t event; 00118 uint8_t state; 00119 uint8_t last_host; 00120 uint8_t filter_mode; 00121 uint8_t max_resp_time; 00122 struct pico_ip4 mcast_link; 00123 struct pico_ip4 mcast_group; 00124 struct pico_tree *MCASTFilter; 00125 struct pico_frame *f; 00126 }; 00127 00128 struct igmp_timer { 00129 uint8_t type; 00130 uint8_t stopped; 00131 pico_time start; 00132 pico_time delay; 00133 struct pico_ip4 mcast_link; 00134 struct pico_ip4 mcast_group; 00135 struct pico_frame *f; 00136 void (*callback)(struct igmp_timer *t); 00137 }; 00138 00139 /* queues */ 00140 static struct pico_queue igmp_in = { 00141 0 00142 }; 00143 static struct pico_queue igmp_out = { 00144 0 00145 }; 00146 00147 /* finite state machine caller */ 00148 static int pico_igmp_process_event(struct igmp_parameters *p); 00149 00150 /* state callback prototype */ 00151 typedef int (*callback)(struct igmp_parameters *); 00152 00153 static inline int igmpt_type_compare(struct igmp_timer *a, struct igmp_timer *b) 00154 { 00155 if (a->type < b->type) 00156 return -1; 00157 00158 if (a->type > b->type) 00159 return 1; 00160 00161 return 0; 00162 } 00163 00164 00165 static inline int igmpt_group_compare(struct igmp_timer *a, struct igmp_timer *b) 00166 { 00167 return pico_ipv4_compare(&a->mcast_group, &b->mcast_group); 00168 } 00169 00170 static inline int igmpt_link_compare(struct igmp_timer *a, struct igmp_timer *b) 00171 { 00172 return pico_ipv4_compare(&a->mcast_link, &b->mcast_link); 00173 } 00174 00175 /* redblack trees */ 00176 static int igmp_timer_cmp(void *ka, void *kb) 00177 { 00178 struct igmp_timer *a = ka, *b = kb; 00179 int cmp = igmpt_type_compare(a, b); 00180 if (cmp) 00181 return cmp; 00182 00183 cmp = igmpt_group_compare(a, b); 00184 if (cmp) 00185 return cmp; 00186 00187 return igmpt_link_compare(a, b); 00188 00189 } 00190 PICO_TREE_DECLARE(IGMPTimers, igmp_timer_cmp); 00191 00192 static inline int igmpparm_group_compare(struct igmp_parameters *a, struct igmp_parameters *b) 00193 { 00194 return pico_ipv4_compare(&a->mcast_group, &b->mcast_group); 00195 } 00196 00197 static inline int igmpparm_link_compare(struct igmp_parameters *a, struct igmp_parameters *b) 00198 { 00199 return pico_ipv4_compare(&a->mcast_link, &b->mcast_link); 00200 } 00201 00202 static int igmp_parameters_cmp(void *ka, void *kb) 00203 { 00204 struct igmp_parameters *a = ka, *b = kb; 00205 int cmp = igmpparm_group_compare(a, b); 00206 if (cmp) 00207 return cmp; 00208 00209 return igmpparm_link_compare(a, b); 00210 } 00211 PICO_TREE_DECLARE(IGMPParameters, igmp_parameters_cmp); 00212 00213 static int igmp_sources_cmp(void *ka, void *kb) 00214 { 00215 struct pico_ip4 *a = ka, *b = kb; 00216 return pico_ipv4_compare(a, b); 00217 } 00218 PICO_TREE_DECLARE(IGMPAllow, igmp_sources_cmp); 00219 PICO_TREE_DECLARE(IGMPBlock, igmp_sources_cmp); 00220 00221 static struct igmp_parameters *pico_igmp_find_parameter(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) 00222 { 00223 struct igmp_parameters test = { 00224 0 00225 }; 00226 if (!mcast_link || !mcast_group) 00227 return NULL; 00228 00229 test.mcast_link.addr = mcast_link->addr; 00230 test.mcast_group.addr = mcast_group->addr; 00231 return pico_tree_findKey(&IGMPParameters, &test); 00232 } 00233 00234 static int pico_igmp_delete_parameter(struct igmp_parameters *p) 00235 { 00236 if (pico_tree_delete(&IGMPParameters, p)) 00237 PICO_FREE(p); 00238 else 00239 return -1; 00240 00241 return 0; 00242 } 00243 00244 static void pico_igmp_timer_expired(pico_time now, void *arg) 00245 { 00246 struct igmp_timer *t = NULL, *timer = NULL, test = { 00247 0 00248 }; 00249 00250 IGNORE_PARAMETER(now); 00251 t = (struct igmp_timer *)arg; 00252 test.type = t->type; 00253 test.mcast_link = t->mcast_link; 00254 test.mcast_group = t->mcast_group; 00255 igmp_dbg("IGMP: timer expired for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay); 00256 timer = pico_tree_findKey(&IGMPTimers, &test); 00257 if (!timer) { 00258 return; 00259 } 00260 00261 if (timer->stopped == IGMP_TIMER_STOPPED) { 00262 PICO_FREE(t); 00263 return; 00264 } 00265 00266 if (timer->start + timer->delay < PICO_TIME_MS()) { 00267 pico_tree_delete(&IGMPTimers, timer); 00268 if (timer->callback) 00269 timer->callback(timer); 00270 00271 PICO_FREE(timer); 00272 } else { 00273 igmp_dbg("IGMP: restart timer for %08X, delay %lu, new delay %lu\n", t->mcast_group.addr, t->delay, (timer->start + timer->delay) - PICO_TIME_MS()); 00274 pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_igmp_timer_expired, timer); 00275 } 00276 00277 return; 00278 } 00279 00280 static int pico_igmp_timer_reset(struct igmp_timer *t) 00281 { 00282 struct igmp_timer *timer = NULL, test = { 00283 0 00284 }; 00285 00286 igmp_dbg("IGMP: reset timer for %08X, delay %lu\n", t->mcast_group.addr, t->delay); 00287 test.type = t->type; 00288 test.mcast_link = t->mcast_link; 00289 test.mcast_group = t->mcast_group; 00290 timer = pico_tree_findKey(&IGMPTimers, &test); 00291 if (!timer) 00292 return -1; 00293 00294 *timer = *t; 00295 timer->start = PICO_TIME_MS(); 00296 return 0; 00297 } 00298 00299 static int pico_igmp_timer_start(struct igmp_timer *t) 00300 { 00301 struct igmp_timer *timer = NULL, test = { 00302 0 00303 }; 00304 00305 igmp_dbg("IGMP: start timer for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay); 00306 test.type = t->type; 00307 test.mcast_link = t->mcast_link; 00308 test.mcast_group = t->mcast_group; 00309 timer = pico_tree_findKey(&IGMPTimers, &test); 00310 if (timer) 00311 return pico_igmp_timer_reset(t); 00312 00313 timer = PICO_ZALLOC(sizeof(struct igmp_timer)); 00314 if (!timer) { 00315 pico_err = PICO_ERR_ENOMEM; 00316 return -1; 00317 } 00318 00319 *timer = *t; 00320 timer->start = PICO_TIME_MS(); 00321 00322 pico_tree_insert(&IGMPTimers, timer); 00323 pico_timer_add(timer->delay, &pico_igmp_timer_expired, timer); 00324 return 0; 00325 } 00326 00327 static int pico_igmp_timer_stop(struct igmp_timer *t) 00328 { 00329 struct igmp_timer *timer = NULL, test = { 00330 0 00331 }; 00332 00333 test.type = t->type; 00334 test.mcast_link = t->mcast_link; 00335 test.mcast_group = t->mcast_group; 00336 timer = pico_tree_findKey(&IGMPTimers, &test); 00337 if (!timer) 00338 return 0; 00339 00340 igmp_dbg("IGMP: stop timer for %08X, delay %lu\n", timer->mcast_group.addr, timer->delay); 00341 timer->stopped = IGMP_TIMER_STOPPED; 00342 return 0; 00343 } 00344 00345 static int pico_igmp_timer_is_running(struct igmp_timer *t) 00346 { 00347 struct igmp_timer *timer = NULL, test = { 00348 0 00349 }; 00350 00351 test.type = t->type; 00352 test.mcast_link = t->mcast_link; 00353 test.mcast_group = t->mcast_group; 00354 timer = pico_tree_findKey(&IGMPTimers, &test); 00355 if (timer) 00356 return 1; 00357 00358 return 0; 00359 } 00360 00361 static struct igmp_timer *pico_igmp_find_timer(uint8_t type, struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) 00362 { 00363 struct igmp_timer test = { 00364 0 00365 }; 00366 00367 test.type = type; 00368 test.mcast_link = *mcast_link; 00369 test.mcast_group = *mcast_group; 00370 return pico_tree_findKey(&IGMPTimers, &test); 00371 } 00372 00373 static void pico_igmp_report_expired(struct igmp_timer *t) 00374 { 00375 struct igmp_parameters *p = NULL; 00376 00377 p = pico_igmp_find_parameter(&t->mcast_link, &t->mcast_group); 00378 if (!p) 00379 return; 00380 00381 p->event = IGMP_EVENT_TIMER_EXPIRED; 00382 pico_igmp_process_event(p); 00383 } 00384 00385 static void pico_igmp_v2querier_expired(struct igmp_timer *t) 00386 { 00387 struct pico_ipv4_link *link = NULL; 00388 struct pico_tree_node *index = NULL, *_tmp = NULL; 00389 00390 link = pico_ipv4_link_by_dev(t->f->dev); 00391 if (!link) 00392 return; 00393 00394 /* When changing compatibility mode, cancel all pending response 00395 * and retransmission timers. 00396 */ 00397 pico_tree_foreach_safe(index, &IGMPTimers, _tmp) 00398 { 00399 ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED; 00400 pico_tree_delete(&IGMPTimers, index->keyValue); 00401 } 00402 igmp_dbg("IGMP: switch to compatibility mode IGMPv3\n"); 00403 link->mcast_compatibility = PICO_IGMPV3; 00404 return; 00405 } 00406 00407 static int pico_igmp_is_checksum_valid(struct pico_frame *f) 00408 { 00409 struct pico_ipv4_hdr *hdr = NULL; 00410 uint8_t ihl = 24, datalen = 0; 00411 00412 hdr = (struct pico_ipv4_hdr *)f->net_hdr; 00413 ihl = (uint8_t)((hdr->vhl & 0x0F) * 4); /* IHL is in 32bit words */ 00414 datalen = (uint8_t)(short_be(hdr->len) - ihl); 00415 00416 if (short_be(pico_checksum(f->transport_hdr, datalen)) == 0) 00417 return 1; 00418 00419 igmp_dbg("IGMP: invalid checksum\n"); 00420 return 0; 00421 } 00422 00423 /* RFC 3376 $7.1 */ 00424 static int pico_igmp_compatibility_mode(struct pico_frame *f) 00425 { 00426 struct pico_ipv4_hdr *hdr = NULL; 00427 struct pico_ipv4_link *link = NULL; 00428 struct pico_tree_node *index = NULL, *_tmp = NULL; 00429 struct igmp_timer t = { 00430 0 00431 }; 00432 uint8_t ihl = 24, datalen = 0; 00433 00434 link = pico_ipv4_link_by_dev(f->dev); 00435 if (!link) 00436 return -1; 00437 00438 hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00439 ihl = (uint8_t)((hdr->vhl & 0x0F) * 4); /* IHL is in 32bit words */ 00440 datalen = (uint8_t)(short_be(hdr->len) - ihl); 00441 igmp_dbg("IGMP: IHL = %u, LEN = %u, OCTETS = %u\n", ihl, short_be(hdr->len), datalen); 00442 00443 if (datalen >= 12) { 00444 /* IGMPv3 query */ 00445 t.type = IGMP_TIMER_V2_QUERIER; 00446 if (pico_igmp_timer_is_running(&t)) { /* IGMPv2 querier present timer still running */ 00447 igmp_dbg("Timer is already running\n"); 00448 return -1; 00449 } else { 00450 link->mcast_compatibility = PICO_IGMPV3; 00451 igmp_dbg("IGMP Compatibility: v3\n"); 00452 return 0; 00453 } 00454 } else if (datalen == 8) { 00455 struct igmp_message *query = (struct igmp_message *)f->transport_hdr; 00456 if (query->max_resp_time != 0) { 00457 /* IGMPv2 query */ 00458 /* When changing compatibility mode, cancel all pending response 00459 * and retransmission timers. 00460 */ 00461 pico_tree_foreach_safe(index, &IGMPTimers, _tmp) 00462 { 00463 ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED; 00464 pico_tree_delete(&IGMPTimers, index->keyValue); 00465 } 00466 igmp_dbg("IGMP: switch to compatibility mode IGMPv2\n"); 00467 link->mcast_compatibility = PICO_IGMPV2; 00468 t.type = IGMP_TIMER_V2_QUERIER; 00469 t.delay = ((IGMP_ROBUSTNESS * link->mcast_last_query_interval) + IGMP_QUERY_RESPONSE_INTERVAL) * 1000; 00470 t.f = f; 00471 t.callback = pico_igmp_v2querier_expired; 00472 /* only one of this type of timer may exist! */ 00473 pico_igmp_timer_start(&t); 00474 } else { 00475 /* IGMPv1 query, not supported */ 00476 return -1; 00477 } 00478 } else { 00479 /* invalid query, silently ignored */ 00480 return -1; 00481 } 00482 00483 return 0; 00484 } 00485 00486 static struct igmp_parameters *pico_igmp_analyse_packet(struct pico_frame *f) 00487 { 00488 struct igmp_message *message = NULL; 00489 struct igmp_parameters *p = NULL; 00490 struct pico_ipv4_link *link = NULL; 00491 struct pico_ip4 mcast_group = { 00492 0 00493 }; 00494 00495 link = pico_ipv4_link_by_dev(f->dev); 00496 if (!link) 00497 return NULL; 00498 00499 /* IGMPv2 and IGMPv3 have a similar structure for the first 8 bytes */ 00500 message = (struct igmp_message *)f->transport_hdr; 00501 mcast_group.addr = message->mcast_group; 00502 p = pico_igmp_find_parameter(&link->address, &mcast_group); 00503 if (!p && mcast_group.addr == 0) { /* general query */ 00504 p = PICO_ZALLOC(sizeof(struct igmp_parameters)); 00505 if (!p) 00506 return NULL; 00507 00508 p->state = IGMP_STATE_NON_MEMBER; 00509 p->mcast_link.addr = link->address.addr; 00510 p->mcast_group.addr = mcast_group.addr; 00511 pico_tree_insert(&IGMPParameters, p); 00512 } else if (!p) { 00513 return NULL; 00514 } 00515 00516 switch (message->type) { 00517 case IGMP_TYPE_MEM_QUERY: 00518 p->event = IGMP_EVENT_QUERY_RECV; 00519 break; 00520 case IGMP_TYPE_MEM_REPORT_V1: 00521 p->event = IGMP_EVENT_REPORT_RECV; 00522 break; 00523 case IGMP_TYPE_MEM_REPORT_V2: 00524 p->event = IGMP_EVENT_REPORT_RECV; 00525 break; 00526 case IGMP_TYPE_MEM_REPORT_V3: 00527 p->event = IGMP_EVENT_REPORT_RECV; 00528 break; 00529 default: 00530 return NULL; 00531 } 00532 p->max_resp_time = message->max_resp_time; /* if IGMPv3 report this will be 0 (res0 field) */ 00533 p->f = f; 00534 00535 return p; 00536 } 00537 00538 static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f) 00539 { 00540 struct igmp_parameters *p = NULL; 00541 IGNORE_PARAMETER(self); 00542 00543 if (!pico_igmp_is_checksum_valid(f)) 00544 goto out; 00545 00546 if (pico_igmp_compatibility_mode(f) < 0) 00547 goto out; 00548 00549 p = pico_igmp_analyse_packet(f); 00550 if (!p) 00551 goto out; 00552 00553 return pico_igmp_process_event(p); 00554 00555 out: 00556 pico_frame_discard(f); 00557 return 0; 00558 } 00559 00560 static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) 00561 { 00562 /* packets are directly transferred to the IP layer by calling pico_ipv4_frame_push */ 00563 IGNORE_PARAMETER(self); 00564 IGNORE_PARAMETER(f); 00565 return 0; 00566 } 00567 00568 /* Interface: protocol definition */ 00569 struct pico_protocol pico_proto_igmp = { 00570 .name = "igmp", 00571 .proto_number = PICO_PROTO_IGMP, 00572 .layer = PICO_LAYER_TRANSPORT, 00573 .process_in = pico_igmp_process_in, 00574 .process_out = pico_igmp_process_out, 00575 .q_in = &igmp_in, 00576 .q_out = &igmp_out, 00577 }; 00578 00579 int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state) 00580 { 00581 struct igmp_parameters *p = NULL; 00582 00583 if (mcast_group->addr == IGMP_ALL_HOST_GROUP) 00584 return 0; 00585 00586 p = pico_igmp_find_parameter(mcast_link, mcast_group); 00587 if (!p && state == PICO_IGMP_STATE_CREATE) { 00588 p = PICO_ZALLOC(sizeof(struct igmp_parameters)); 00589 if (!p) { 00590 pico_err = PICO_ERR_ENOMEM; 00591 return -1; 00592 } 00593 00594 if (!mcast_link || !mcast_group) { 00595 pico_err = PICO_ERR_EINVAL; 00596 return -1; 00597 } 00598 00599 p->state = IGMP_STATE_NON_MEMBER; 00600 p->mcast_link = *mcast_link; 00601 p->mcast_group = *mcast_group; 00602 pico_tree_insert(&IGMPParameters, p); 00603 } else if (!p) { 00604 pico_err = PICO_ERR_EINVAL; 00605 return -1; 00606 } 00607 00608 switch (state) { 00609 case PICO_IGMP_STATE_CREATE: 00610 p->event = IGMP_EVENT_CREATE_GROUP; 00611 break; 00612 00613 case PICO_IGMP_STATE_UPDATE: 00614 p->event = IGMP_EVENT_UPDATE_GROUP; 00615 break; 00616 00617 case PICO_IGMP_STATE_DELETE: 00618 p->event = IGMP_EVENT_DELETE_GROUP; 00619 break; 00620 00621 default: 00622 return -1; 00623 } 00624 p->filter_mode = filter_mode; 00625 p->MCASTFilter = _MCASTFilter; 00626 00627 return pico_igmp_process_event(p); 00628 } 00629 00630 static int pico_igmp_send_report(struct igmp_parameters *p, struct pico_frame *f) 00631 { 00632 struct pico_ip4 dst = { 00633 0 00634 }; 00635 struct pico_ip4 mcast_group = { 00636 0 00637 }; 00638 struct pico_ipv4_link *link = NULL; 00639 00640 link = pico_ipv4_link_get(&p->mcast_link); 00641 if (!link) 00642 return -1; 00643 00644 mcast_group.addr = p->mcast_group.addr; 00645 switch (link->mcast_compatibility) { 00646 case PICO_IGMPV2: 00647 if (p->event == IGMP_EVENT_DELETE_GROUP) 00648 dst.addr = IGMP_ALL_ROUTER_GROUP; 00649 else 00650 dst.addr = mcast_group.addr; 00651 00652 break; 00653 00654 case PICO_IGMPV3: 00655 dst.addr = IGMPV3_ALL_ROUTER_GROUP; 00656 break; 00657 00658 default: 00659 pico_err = PICO_ERR_EPROTONOSUPPORT; 00660 return -1; 00661 } 00662 00663 igmp_dbg("IGMP: send membership report on group %08X to %08X\n", mcast_group.addr, dst.addr); 00664 pico_ipv4_frame_push(f, &dst, PICO_PROTO_IGMP); 00665 return 0; 00666 } 00667 00668 static int8_t pico_igmp_generate_report(struct igmp_parameters *p) 00669 { 00670 struct pico_ipv4_link *link = NULL; 00671 int i = 0; 00672 00673 link = pico_ipv4_link_get(&p->mcast_link); 00674 if (!link) { 00675 pico_err = PICO_ERR_EINVAL; 00676 return -1; 00677 } 00678 00679 switch (link->mcast_compatibility) { 00680 case PICO_IGMPV1: 00681 pico_err = PICO_ERR_EPROTONOSUPPORT; 00682 return -1; 00683 00684 case PICO_IGMPV2: 00685 { 00686 struct igmp_message *report = NULL; 00687 uint8_t report_type = IGMP_TYPE_MEM_REPORT_V2; 00688 if (p->event == IGMP_EVENT_DELETE_GROUP) 00689 report_type = IGMP_TYPE_LEAVE_GROUP; 00690 00691 p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + sizeof(struct igmp_message)); 00692 p->f->net_len = (uint16_t)(p->f->net_len + IP_OPTION_ROUTER_ALERT_LEN); 00693 p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN; 00694 p->f->transport_len = (uint16_t)(p->f->transport_len - IP_OPTION_ROUTER_ALERT_LEN); 00695 p->f->dev = pico_ipv4_link_find(&p->mcast_link); 00696 /* p->f->len is correctly set by alloc */ 00697 00698 report = (struct igmp_message *)p->f->transport_hdr; 00699 report->type = report_type; 00700 report->max_resp_time = IGMP_DEFAULT_MAX_RESPONSE_TIME; 00701 report->mcast_group = p->mcast_group.addr; 00702 00703 report->crc = 0; 00704 report->crc = short_be(pico_checksum(report, sizeof(struct igmp_message))); 00705 break; 00706 } 00707 case PICO_IGMPV3: 00708 { 00709 struct igmpv3_report *report = NULL; 00710 struct igmpv3_group_record *record = NULL; 00711 struct pico_mcast_group *g = NULL, test = { 00712 0 00713 }; 00714 struct pico_tree_node *index = NULL, *_tmp = NULL; 00715 struct pico_tree *IGMPFilter = NULL; 00716 struct pico_ip4 *source = NULL; 00717 uint8_t record_type = 0; 00718 uint8_t sources = 0; 00719 uint16_t len = 0; 00720 00721 test.mcast_addr = p->mcast_group; 00722 g = pico_tree_findKey(link->MCASTGroups, &test); 00723 if (!g) { 00724 pico_err = PICO_ERR_EINVAL; 00725 return -1; 00726 } 00727 00728 if (p->event == IGMP_EVENT_DELETE_GROUP) { /* "non-existent" state of filter mode INCLUDE and empty source list */ 00729 p->filter_mode = PICO_IP_MULTICAST_INCLUDE; 00730 p->MCASTFilter = NULL; 00731 } 00732 00733 if (p->event == IGMP_EVENT_QUERY_RECV) { 00734 goto igmp3_report; 00735 } 00736 00737 00738 /* cleanup filters */ 00739 pico_tree_foreach_safe(index, &IGMPAllow, _tmp) 00740 { 00741 pico_tree_delete(&IGMPAllow, index->keyValue); 00742 } 00743 pico_tree_foreach_safe(index, &IGMPBlock, _tmp) 00744 { 00745 pico_tree_delete(&IGMPBlock, index->keyValue); 00746 } 00747 00748 switch (g->filter_mode) { 00749 00750 case PICO_IP_MULTICAST_INCLUDE: 00751 switch (p->filter_mode) { 00752 case PICO_IP_MULTICAST_INCLUDE: 00753 if (p->event == IGMP_EVENT_DELETE_GROUP) { /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */ 00754 /* TO_IN (B) */ 00755 record_type = IGMP_CHANGE_TO_INCLUDE_MODE; 00756 IGMPFilter = &IGMPAllow; 00757 if (p->MCASTFilter) { 00758 pico_tree_foreach(index, p->MCASTFilter) /* B */ 00759 { 00760 pico_tree_insert(&IGMPAllow, index->keyValue); 00761 sources++; 00762 } 00763 } /* else { IGMPAllow stays empty } */ 00764 00765 break; 00766 } 00767 00768 /* ALLOW (B-A) */ 00769 /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */ 00770 if (p->event == IGMP_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */ 00771 record_type = IGMP_CHANGE_TO_INCLUDE_MODE; 00772 else 00773 record_type = IGMP_ALLOW_NEW_SOURCES; 00774 00775 IGMPFilter = &IGMPAllow; 00776 pico_tree_foreach(index, p->MCASTFilter) /* B */ 00777 { 00778 pico_tree_insert(&IGMPAllow, index->keyValue); 00779 sources++; 00780 } 00781 pico_tree_foreach(index, &g->MCASTSources) /* A */ 00782 { 00783 source = pico_tree_findKey(&IGMPAllow, index->keyValue); 00784 if (source) { 00785 pico_tree_delete(&IGMPAllow, source); 00786 sources--; 00787 } 00788 } 00789 if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */ 00790 break; 00791 00792 /* BLOCK (A-B) */ 00793 record_type = IGMP_BLOCK_OLD_SOURCES; 00794 IGMPFilter = &IGMPBlock; 00795 pico_tree_foreach(index, &g->MCASTSources) /* A */ 00796 { 00797 pico_tree_insert(&IGMPBlock, index->keyValue); 00798 sources++; 00799 } 00800 pico_tree_foreach(index, p->MCASTFilter) /* B */ 00801 { 00802 source = pico_tree_findKey(&IGMPBlock, index->keyValue); 00803 if (source) { 00804 pico_tree_delete(&IGMPBlock, source); 00805 sources--; 00806 } 00807 } 00808 if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */ 00809 break; 00810 00811 /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report (RFC 3376 $5.1) */ 00812 p->f = NULL; 00813 return 0; 00814 00815 case PICO_IP_MULTICAST_EXCLUDE: 00816 /* TO_EX (B) */ 00817 record_type = IGMP_CHANGE_TO_EXCLUDE_MODE; 00818 IGMPFilter = &IGMPBlock; 00819 pico_tree_foreach(index, p->MCASTFilter) /* B */ 00820 { 00821 pico_tree_insert(&IGMPBlock, index->keyValue); 00822 sources++; 00823 } 00824 break; 00825 00826 default: 00827 pico_err = PICO_ERR_EINVAL; 00828 return -1; 00829 } 00830 break; 00831 00832 case PICO_IP_MULTICAST_EXCLUDE: 00833 switch (p->filter_mode) { 00834 case PICO_IP_MULTICAST_INCLUDE: 00835 /* TO_IN (B) */ 00836 record_type = IGMP_CHANGE_TO_INCLUDE_MODE; 00837 IGMPFilter = &IGMPAllow; 00838 if (p->MCASTFilter) { 00839 pico_tree_foreach(index, p->MCASTFilter) /* B */ 00840 { 00841 pico_tree_insert(&IGMPAllow, index->keyValue); 00842 sources++; 00843 } 00844 } /* else { IGMPAllow stays empty } */ 00845 00846 break; 00847 00848 case PICO_IP_MULTICAST_EXCLUDE: 00849 /* BLOCK (B-A) */ 00850 record_type = IGMP_BLOCK_OLD_SOURCES; 00851 IGMPFilter = &IGMPBlock; 00852 pico_tree_foreach(index, p->MCASTFilter) 00853 { 00854 pico_tree_insert(&IGMPBlock, index->keyValue); 00855 sources++; 00856 } 00857 pico_tree_foreach(index, &g->MCASTSources) /* A */ 00858 { 00859 source = pico_tree_findKey(&IGMPBlock, index->keyValue); /* B */ 00860 if (source) { 00861 pico_tree_delete(&IGMPBlock, source); 00862 sources--; 00863 } 00864 } 00865 if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */ 00866 break; 00867 00868 /* ALLOW (A-B) */ 00869 record_type = IGMP_ALLOW_NEW_SOURCES; 00870 IGMPFilter = &IGMPAllow; 00871 pico_tree_foreach(index, &g->MCASTSources) 00872 { 00873 pico_tree_insert(&IGMPAllow, index->keyValue); 00874 sources++; 00875 } 00876 pico_tree_foreach(index, p->MCASTFilter) /* B */ 00877 { 00878 source = pico_tree_findKey(&IGMPAllow, index->keyValue); /* A */ 00879 if (source) { 00880 pico_tree_delete(&IGMPAllow, source); 00881 sources--; 00882 } 00883 } 00884 if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */ 00885 break; 00886 00887 /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report (RFC 3376 $5.1) */ 00888 p->f = NULL; 00889 return 0; 00890 00891 default: 00892 pico_err = PICO_ERR_EINVAL; 00893 return -1; 00894 } 00895 break; 00896 00897 default: 00898 pico_err = PICO_ERR_EINVAL; 00899 return -1; 00900 } 00901 00902 igmp3_report: 00903 len = (uint16_t)(sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (sources * sizeof(struct pico_ip4))); 00904 p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)(IP_OPTION_ROUTER_ALERT_LEN + len)); 00905 p->f->net_len = (uint16_t)(p->f->net_len + IP_OPTION_ROUTER_ALERT_LEN); 00906 p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN; 00907 p->f->transport_len = (uint16_t)(p->f->transport_len - IP_OPTION_ROUTER_ALERT_LEN); 00908 p->f->dev = pico_ipv4_link_find(&p->mcast_link); 00909 /* p->f->len is correctly set by alloc */ 00910 00911 report = (struct igmpv3_report *)p->f->transport_hdr; 00912 report->type = IGMP_TYPE_MEM_REPORT_V3; 00913 report->res0 = 0; 00914 report->crc = 0; 00915 report->res1 = 0; 00916 report->groups = short_be(1); 00917 00918 record = (struct igmpv3_group_record *)(((uint8_t *)report) + sizeof(struct igmpv3_report)); 00919 record->type = record_type; 00920 record->aux = 0; 00921 record->sources = short_be(sources); 00922 record->mcast_group = p->mcast_group.addr; 00923 if (IGMPFilter && !pico_tree_empty(IGMPFilter)) { 00924 uint32_t *source_addr = (uint32_t *)((uint8_t *)record + sizeof(struct igmpv3_group_record)); 00925 i = 0; 00926 pico_tree_foreach(index, IGMPFilter) 00927 { 00928 source_addr[i] = ((struct pico_ip4 *)index->keyValue)->addr; 00929 i++; 00930 } 00931 } 00932 00933 report->crc = short_be(pico_checksum(report, len)); 00934 break; 00935 } 00936 00937 default: 00938 pico_err = PICO_ERR_EINVAL; 00939 return -1; 00940 } 00941 return 0; 00942 } 00943 00944 /* stop timer, send leave if flag set */ 00945 static int stslifs(struct igmp_parameters *p) 00946 { 00947 struct igmp_timer t = { 00948 0 00949 }; 00950 00951 igmp_dbg("IGMP: event = leave group | action = stop timer, send leave if flag set\n"); 00952 00953 t.type = IGMP_TIMER_GROUP_REPORT; 00954 t.mcast_link = p->mcast_link; 00955 t.mcast_group = p->mcast_group; 00956 if (pico_igmp_timer_stop(&t) < 0) 00957 return -1; 00958 00959 /* always send leave, even if not last host */ 00960 if (pico_igmp_send_report(p, p->f) < 0) 00961 return -1; 00962 00963 pico_igmp_delete_parameter(p); 00964 igmp_dbg("IGMP: new state = non-member\n"); 00965 return 0; 00966 } 00967 00968 /* send report, set flag, start timer */ 00969 static int srsfst(struct igmp_parameters *p) 00970 { 00971 struct igmp_timer t = { 00972 0 00973 }; 00974 struct pico_frame *copy_frame = NULL; 00975 00976 igmp_dbg("IGMP: event = join group | action = send report, set flag, start timer\n"); 00977 00978 p->last_host = IGMP_HOST_LAST; 00979 00980 if (pico_igmp_generate_report(p) < 0) 00981 return -1; 00982 00983 if (!p->f) 00984 return 0; 00985 00986 copy_frame = pico_frame_copy(p->f); 00987 if (!copy_frame) { 00988 pico_err = PICO_ERR_ENOMEM; 00989 return -1; 00990 } 00991 00992 if (pico_igmp_send_report(p, copy_frame) < 0) 00993 return -1; 00994 00995 t.type = IGMP_TIMER_GROUP_REPORT; 00996 t.mcast_link = p->mcast_link; 00997 t.mcast_group = p->mcast_group; 00998 t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); 00999 t.f = p->f; 01000 t.callback = pico_igmp_report_expired; 01001 pico_igmp_timer_start(&t); 01002 01003 p->state = IGMP_STATE_DELAYING_MEMBER; 01004 igmp_dbg("IGMP: new state = delaying member\n"); 01005 return 0; 01006 } 01007 01008 /* merge report, send report, reset timer (IGMPv3 only) */ 01009 static int mrsrrt(struct igmp_parameters *p) 01010 { 01011 struct igmp_timer *t = NULL; 01012 struct pico_frame *copy_frame = NULL; 01013 struct pico_ipv4_link *link = NULL; 01014 01015 igmp_dbg("IGMP: event = update group | action = merge report, send report, reset timer (IGMPv3 only)\n"); 01016 01017 link = pico_ipv4_link_get(&p->mcast_link); 01018 if (!link) 01019 return -1; 01020 01021 if (link->mcast_compatibility != PICO_IGMPV3) { 01022 igmp_dbg("IGMP: no IGMPv3 compatible router on network\n"); 01023 return -1; 01024 } 01025 01026 /* XXX: merge with pending report rfc 3376 $5.1 */ 01027 01028 copy_frame = pico_frame_copy(p->f); 01029 if (!copy_frame) 01030 return -1; 01031 01032 if (pico_igmp_send_report(p, copy_frame) < 0) 01033 return -1; 01034 01035 t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); 01036 if (!t) 01037 return -1; 01038 01039 t->delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); 01040 pico_igmp_timer_reset(t); 01041 01042 p->state = IGMP_STATE_DELAYING_MEMBER; 01043 igmp_dbg("IGMP: new state = delaying member\n"); 01044 return 0; 01045 } 01046 01047 /* send report, start timer (IGMPv3 only) */ 01048 static int srst(struct igmp_parameters *p) 01049 { 01050 struct igmp_timer t = { 01051 0 01052 }; 01053 struct pico_frame *copy_frame = NULL; 01054 struct pico_ipv4_link *link = NULL; 01055 01056 igmp_dbg("IGMP: event = update group | action = send report, start timer (IGMPv3 only)\n"); 01057 01058 link = pico_ipv4_link_get(&p->mcast_link); 01059 if (!link) 01060 return -1; 01061 01062 if (link->mcast_compatibility != PICO_IGMPV3) { 01063 igmp_dbg("IGMP: no IGMPv3 compatible router on network\n"); 01064 return -1; 01065 } 01066 01067 if (pico_igmp_generate_report(p) < 0) 01068 return -1; 01069 01070 if (!p->f) 01071 return 0; 01072 01073 copy_frame = pico_frame_copy(p->f); 01074 if (!copy_frame) 01075 return -1; 01076 01077 if (pico_igmp_send_report(p, copy_frame) < 0) 01078 return -1; 01079 01080 t.type = IGMP_TIMER_GROUP_REPORT; 01081 t.mcast_link = p->mcast_link; 01082 t.mcast_group = p->mcast_group; 01083 t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); 01084 t.f = p->f; 01085 t.callback = pico_igmp_report_expired; 01086 pico_igmp_timer_start(&t); 01087 01088 p->state = IGMP_STATE_DELAYING_MEMBER; 01089 igmp_dbg("IGMP: new state = delaying member\n"); 01090 return 0; 01091 } 01092 01093 /* send leave if flag set */ 01094 static int slifs(struct igmp_parameters *p) 01095 { 01096 igmp_dbg("IGMP: event = leave group | action = send leave if flag set\n"); 01097 01098 /* always send leave, even if not last host */ 01099 if (pico_igmp_send_report(p, p->f) < 0) 01100 return -1; 01101 01102 pico_igmp_delete_parameter(p); 01103 igmp_dbg("IGMP: new state = non-member\n"); 01104 return 0; 01105 } 01106 01107 /* start timer */ 01108 static int st(struct igmp_parameters *p) 01109 { 01110 struct igmp_timer t = { 01111 0 01112 }; 01113 01114 igmp_dbg("IGMP: event = query received | action = start timer\n"); 01115 01116 if (pico_igmp_generate_report(p) < 0) { 01117 igmp_dbg("Failed to generate report\n"); 01118 return -1; 01119 } 01120 01121 if (!p->f) { 01122 igmp_dbg("No pending frame\n"); 01123 return -1; 01124 } 01125 01126 t.type = IGMP_TIMER_GROUP_REPORT; 01127 t.mcast_link = p->mcast_link; 01128 t.mcast_group = p->mcast_group; 01129 t.delay = (pico_rand() % ((1u + p->max_resp_time) * 100u)); 01130 t.f = p->f; 01131 t.callback = pico_igmp_report_expired; 01132 pico_igmp_timer_start(&t); 01133 01134 p->state = IGMP_STATE_DELAYING_MEMBER; 01135 igmp_dbg("IGMP: new state = delaying member\n"); 01136 return 0; 01137 } 01138 01139 /* stop timer, clear flag */ 01140 static int stcl(struct igmp_parameters *p) 01141 { 01142 struct igmp_timer t = { 01143 0 01144 }; 01145 01146 igmp_dbg("IGMP: event = report received | action = stop timer, clear flag\n"); 01147 01148 t.type = IGMP_TIMER_GROUP_REPORT; 01149 t.mcast_link = p->mcast_link; 01150 t.mcast_group = p->mcast_group; 01151 if (pico_igmp_timer_stop(&t) < 0) 01152 return -1; 01153 01154 p->last_host = IGMP_HOST_NOT_LAST; 01155 p->state = IGMP_STATE_IDLE_MEMBER; 01156 igmp_dbg("IGMP: new state = idle member\n"); 01157 return 0; 01158 } 01159 01160 /* send report, set flag */ 01161 static int srsf(struct igmp_parameters *p) 01162 { 01163 igmp_dbg("IGMP: event = timer expired | action = send report, set flag\n"); 01164 01165 if (pico_igmp_send_report(p, p->f) < 0) 01166 return -1; 01167 01168 p->state = IGMP_STATE_IDLE_MEMBER; 01169 igmp_dbg("IGMP: new state = idle member\n"); 01170 return 0; 01171 } 01172 01173 /* reset timer if max response time < current timer */ 01174 static int rtimrtct(struct igmp_parameters *p) 01175 { 01176 struct igmp_timer *t = NULL; 01177 uint32_t time_to_run = 0; 01178 01179 igmp_dbg("IGMP: event = query received | action = reset timer if max response time < current timer\n"); 01180 01181 t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); 01182 if (!t) 01183 return -1; 01184 01185 time_to_run = (uint32_t)(t->start + t->delay - PICO_TIME_MS()); 01186 if ((p->max_resp_time * 100u) < time_to_run) { /* max_resp_time in units of 1/10 seconds */ 01187 t->delay = pico_rand() % ((1u + p->max_resp_time) * 100u); 01188 pico_igmp_timer_reset(t); 01189 } 01190 01191 p->state = IGMP_STATE_DELAYING_MEMBER; 01192 igmp_dbg("IGMP: new state = delaying member\n"); 01193 return 0; 01194 } 01195 01196 static int discard(struct igmp_parameters *p) 01197 { 01198 igmp_dbg("IGMP: ignore and discard frame\n"); 01199 pico_frame_discard(p->f); 01200 return 0; 01201 } 01202 01203 /* finite state machine table */ 01204 const callback host_membership_diagram_table[3][6] = 01205 { /* event |Delete Group |Create Group |Update Group |Query Received |Report Received |Timer Expired */ 01206 /* state Non-Member */ 01207 { discard, srsfst, srsfst, discard, discard, discard }, 01208 /* state Delaying Member */ { stslifs, mrsrrt, mrsrrt, rtimrtct, stcl, srsf }, 01209 /* state Idle Member */ { slifs, srst, srst, st, discard, discard } 01210 }; 01211 01212 static int pico_igmp_process_event(struct igmp_parameters *p) 01213 { 01214 struct pico_tree_node *index = NULL; 01215 struct igmp_parameters *_p = NULL; 01216 01217 igmp_dbg("IGMP: process event on group address %08X\n", p->mcast_group.addr); 01218 if (p->event == IGMP_EVENT_QUERY_RECV && p->mcast_group.addr == 0) { /* general query */ 01219 pico_tree_foreach(index, &IGMPParameters) { 01220 _p = index->keyValue; 01221 _p->max_resp_time = p->max_resp_time; 01222 _p->event = IGMP_EVENT_QUERY_RECV; 01223 igmp_dbg("IGMP: for each mcast_group = %08X | state = %u\n", _p->mcast_group.addr, _p->state); 01224 host_membership_diagram_table[_p->state][_p->event](_p); 01225 } 01226 } else { 01227 igmp_dbg("IGMP: state = %u (0: non-member - 1: delaying member - 2: idle member)\n", p->state); 01228 host_membership_diagram_table[p->state][p->event](p); 01229 } 01230 01231 return 0; 01232 } 01233 01234 #else 01235 static struct pico_queue igmp_in = { 01236 0 01237 }; 01238 static struct pico_queue igmp_out = { 01239 0 01240 }; 01241 01242 static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f) { 01243 IGNORE_PARAMETER(self); 01244 IGNORE_PARAMETER(f); 01245 pico_err = PICO_ERR_EPROTONOSUPPORT; 01246 return -1; 01247 } 01248 01249 static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) { 01250 IGNORE_PARAMETER(self); 01251 IGNORE_PARAMETER(f); 01252 return -1; 01253 } 01254 01255 /* Interface: protocol definition */ 01256 struct pico_protocol pico_proto_igmp = { 01257 .name = "igmp", 01258 .proto_number = PICO_PROTO_IGMP, 01259 .layer = PICO_LAYER_TRANSPORT, 01260 .process_in = pico_igmp_process_in, 01261 .process_out = pico_igmp_process_out, 01262 .q_in = &igmp_in, 01263 .q_out = &igmp_out, 01264 }; 01265 01266 int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state) { 01267 IGNORE_PARAMETER(mcast_link); 01268 IGNORE_PARAMETER(mcast_group); 01269 IGNORE_PARAMETER(filter_mode); 01270 IGNORE_PARAMETER(_MCASTFilter); 01271 IGNORE_PARAMETER(state); 01272 pico_err = PICO_ERR_EPROTONOSUPPORT; 01273 return -1; 01274 } 01275 #endif
Generated on Tue Jul 12 2022 15:59:21 by 1.7.2