ReactOS 0.4.16-dev-329-g9223134
igmp.c
Go to the documentation of this file.
1
10/*
11 * Copyright (c) 2002 CITEL Technologies Ltd.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * This file is a contribution to the lwIP TCP/IP stack.
39 * The Swedish Institute of Computer Science and Adam Dunkels
40 * are specifically granted permission to redistribute this
41 * source code.
42*/
43
44/*-------------------------------------------------------------
45Note 1)
46Although the rfc requires V1 AND V2 capability
47we will only support v2 since now V1 is very old (August 1989)
48V1 can be added if required
49
50a debug print and statistic have been implemented to
51show this up.
52-------------------------------------------------------------
53-------------------------------------------------------------
54Note 2)
55A query for a specific group address (as opposed to ALLHOSTS)
56has now been implemented as I am unsure if it is required
57
58a debug print and statistic have been implemented to
59show this up.
60-------------------------------------------------------------
61-------------------------------------------------------------
62Note 3)
63The router alert rfc 2113 is implemented in outgoing packets
64but not checked rigorously incoming
65-------------------------------------------------------------
66Steve Reynolds
67------------------------------------------------------------*/
68
69/*-----------------------------------------------------------------------------
70 * RFC 988 - Host extensions for IP multicasting - V0
71 * RFC 1054 - Host extensions for IP multicasting -
72 * RFC 1112 - Host extensions for IP multicasting - V1
73 * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
74 * RFC 3376 - Internet Group Management Protocol, Version 3 - V3
75 * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
76 * RFC 2113 - IP Router Alert Option -
77 *----------------------------------------------------------------------------*/
78
79/*-----------------------------------------------------------------------------
80 * Includes
81 *----------------------------------------------------------------------------*/
82
83#include "lwip/opt.h"
84
85#if LWIP_IPV4 && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
86
87#include "lwip/igmp.h"
88#include "lwip/debug.h"
89#include "lwip/def.h"
90#include "lwip/mem.h"
91#include "lwip/ip.h"
92#include "lwip/inet_chksum.h"
93#include "lwip/netif.h"
94#include "lwip/stats.h"
95#include "lwip/prot/igmp.h"
96
97#include <string.h>
98
99static struct igmp_group *igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr);
100static err_t igmp_remove_group(struct netif *netif, struct igmp_group *group);
101static void igmp_timeout(struct netif *netif, struct igmp_group *group);
102static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
103static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
104static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif);
105static void igmp_send(struct netif *netif, struct igmp_group *group, u8_t type);
106
107static ip4_addr_t allsystems;
108static ip4_addr_t allrouters;
109
113void
114igmp_init(void)
115{
116 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
117
118 IP4_ADDR(&allsystems, 224, 0, 0, 1);
119 IP4_ADDR(&allrouters, 224, 0, 0, 2);
120}
121
127err_t
128igmp_start(struct netif *netif)
129{
130 struct igmp_group *group;
131
132 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", (void *)netif));
133
134 group = igmp_lookup_group(netif, &allsystems);
135
136 if (group != NULL) {
137 group->group_state = IGMP_GROUP_IDLE_MEMBER;
138 group->use++;
139
140 /* Allow the igmp messages at the MAC level */
141 if (netif->igmp_mac_filter != NULL) {
142 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
143 ip4_addr_debug_print_val(IGMP_DEBUG, allsystems);
144 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif));
145 netif->igmp_mac_filter(netif, &allsystems, NETIF_ADD_MAC_FILTER);
146 }
147
148 return ERR_OK;
149 }
150
151 return ERR_MEM;
152}
153
159err_t
160igmp_stop(struct netif *netif)
161{
162 struct igmp_group *group = netif_igmp_data(netif);
163
164 netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, NULL);
165
166 while (group != NULL) {
167 struct igmp_group *next = group->next; /* avoid use-after-free below */
168
169 /* disable the group at the MAC level */
170 if (netif->igmp_mac_filter != NULL) {
171 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
172 ip4_addr_debug_print_val(IGMP_DEBUG, group->group_address);
173 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif));
174 netif->igmp_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER);
175 }
176
177 /* free group */
178 memp_free(MEMP_IGMP_GROUP, group);
179
180 /* move to "next" */
181 group = next;
182 }
183 return ERR_OK;
184}
185
191void
192igmp_report_groups(struct netif *netif)
193{
194 struct igmp_group *group = netif_igmp_data(netif);
195
196 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void *)netif));
197
198 /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
199 if (group != NULL) {
200 group = group->next;
201 }
202
203 while (group != NULL) {
204 igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
205 group = group->next;
206 }
207}
208
217struct igmp_group *
218igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr)
219{
220 struct igmp_group *group = netif_igmp_data(ifp);
221
222 while (group != NULL) {
223 if (ip4_addr_eq(&(group->group_address), addr)) {
224 return group;
225 }
226 group = group->next;
227 }
228
229 /* to be clearer, we return NULL here instead of
230 * 'group' (which is also NULL at this point).
231 */
232 return NULL;
233}
234
243static struct igmp_group *
244igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
245{
246 struct igmp_group *group;
247 struct igmp_group *list_head = netif_igmp_data(ifp);
248
249 /* Search if the group already exists */
250 group = igmp_lookfor_group(ifp, addr);
251 if (group != NULL) {
252 /* Group already exists. */
253 return group;
254 }
255
256 /* Group doesn't exist yet, create a new one */
257 group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
258 if (group != NULL) {
259 ip4_addr_set(&(group->group_address), addr);
260 group->timer = 0; /* Not running */
261 group->group_state = IGMP_GROUP_NON_MEMBER;
262 group->last_reporter_flag = 0;
263 group->use = 0;
264
265 /* Ensure allsystems group is always first in list */
266 if (list_head == NULL) {
267 /* this is the first entry in linked list */
268 LWIP_ASSERT("igmp_lookup_group: first group must be allsystems",
269 (ip4_addr_eq(addr, &allsystems) != 0));
270 group->next = NULL;
271 netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group);
272 } else {
273 /* append _after_ first entry */
274 LWIP_ASSERT("igmp_lookup_group: all except first group must not be allsystems",
275 (ip4_addr_eq(addr, &allsystems) == 0));
276 group->next = list_head->next;
278 }
279 }
280
281 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group ? "" : "impossible to ")));
282 ip4_addr_debug_print(IGMP_DEBUG, addr);
283 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)ifp));
284
285 return group;
286}
287
294static err_t
295igmp_remove_group(struct netif *netif, struct igmp_group *group)
296{
297 err_t err = ERR_OK;
298 struct igmp_group *tmp_group;
299
300 /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
301 for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) {
302 if (tmp_group->next == group) {
303 tmp_group->next = group->next;
304 break;
305 }
306 }
307 /* Group not found in netif's igmp group list */
308 if (tmp_group == NULL) {
309 err = ERR_ARG;
310 }
311
312 return err;
313}
314
322void
323igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
324{
325 struct igmp_msg *igmp;
326 struct igmp_group *group;
327 struct igmp_group *groupref;
328
329 IGMP_STATS_INC(igmp.recv);
330
331 /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
332 if (p->len < IGMP_MINLEN) {
333 pbuf_free(p);
334 IGMP_STATS_INC(igmp.lenerr);
335 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
336 return;
337 }
338
339 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
340 ip4_addr_debug_print_val(IGMP_DEBUG, ip4_current_header()->src);
341 LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
342 ip4_addr_debug_print_val(IGMP_DEBUG, ip4_current_header()->dest);
343 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)inp));
344
345 /* Now calculate and check the checksum */
346 igmp = (struct igmp_msg *)p->payload;
347 if (inet_chksum(igmp, p->len)) {
348 pbuf_free(p);
349 IGMP_STATS_INC(igmp.chkerr);
350 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
351 return;
352 }
353
354 /* Packet is ok so find an existing group */
355 group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
356
357 /* If group can be found or create... */
358 if (!group) {
359 pbuf_free(p);
360 IGMP_STATS_INC(igmp.drop);
361 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
362 return;
363 }
364
365 /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
366 switch (igmp->igmp_msgtype) {
367 case IGMP_MEMB_QUERY:
368 /* IGMP_MEMB_QUERY to the "all systems" address ? */
369 if ((ip4_addr_eq(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) {
370 /* THIS IS THE GENERAL QUERY */
371 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
372
373 if (igmp->igmp_maxresp == 0) {
374 IGMP_STATS_INC(igmp.rx_v1);
375 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
376 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
377 } else {
378 IGMP_STATS_INC(igmp.rx_general);
379 }
380
381 groupref = netif_igmp_data(inp);
382
383 /* Do not send messages on the all systems group address! */
384 /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
385 if (groupref != NULL) {
386 groupref = groupref->next;
387 }
388
389 while (groupref) {
390 igmp_delaying_member(groupref, igmp->igmp_maxresp);
391 groupref = groupref->next;
392 }
393 } else {
394 /* IGMP_MEMB_QUERY to a specific group ? */
395 if (!ip4_addr_isany(&igmp->igmp_group_address)) {
396 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
397 ip4_addr_debug_print_val(IGMP_DEBUG, igmp->igmp_group_address);
398 if (ip4_addr_eq(dest, &allsystems)) {
399 ip4_addr_t groupaddr;
400 LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
401 /* we first need to re-look for the group since we used dest last time */
402 ip4_addr_copy(groupaddr, igmp->igmp_group_address);
403 group = igmp_lookfor_group(inp, &groupaddr);
404 } else {
405 LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
406 }
407
408 if (group != NULL) {
409 IGMP_STATS_INC(igmp.rx_group);
410 igmp_delaying_member(group, igmp->igmp_maxresp);
411 } else {
412 IGMP_STATS_INC(igmp.drop);
413 }
414 } else {
415 IGMP_STATS_INC(igmp.proterr);
416 }
417 }
418 break;
420 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
421 IGMP_STATS_INC(igmp.rx_report);
422 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
423 /* This is on a specific group we have already looked up */
424 group->timer = 0; /* stopped */
425 group->group_state = IGMP_GROUP_IDLE_MEMBER;
426 group->last_reporter_flag = 0;
427 }
428 break;
429 default:
430 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
431 igmp->igmp_msgtype, group->group_state, (void *)&group, (void *)inp));
432 IGMP_STATS_INC(igmp.proterr);
433 break;
434 }
435
436 pbuf_free(p);
437 return;
438}
439
448err_t
449igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr)
450{
451 err_t err = ERR_VAL; /* no matching interface */
452 struct netif *netif;
453
455
456 /* make sure it is multicast address */
457 LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
458 LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;);
459
460 /* loop through netif's */
462 /* Should we join this interface ? */
463 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_eq(netif_ip4_addr(netif), ifaddr)))) {
464 err = igmp_joingroup_netif(netif, groupaddr);
465 if (err != ERR_OK) {
466 /* Return an error even if some network interfaces are joined */
468 return err;
469 }
470 }
471 }
472
473 return err;
474}
475
484err_t
485igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
486{
487 struct igmp_group *group;
488
490
491 /* make sure it is multicast address */
492 LWIP_ERROR("igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
493 LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;);
494
495 /* make sure it is an igmp-enabled netif */
496 LWIP_ERROR("igmp_joingroup_netif: attempt to join on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;);
497
498 /* find group or create a new one if not found */
499 group = igmp_lookup_group(netif, groupaddr);
500
501 if (group != NULL) {
502 /* This should create a new group, check the state to make sure */
503 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
504 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
505 } else {
506 /* OK - it was new group */
507 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to new group: "));
508 ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
509 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
510
511 /* If first use of the group, allow the group at the MAC level */
512 if ((group->use == 0) && (netif->igmp_mac_filter != NULL)) {
513 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: igmp_mac_filter(ADD "));
514 ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
515 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif));
516 netif->igmp_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER);
517 }
518
519 IGMP_STATS_INC(igmp.tx_join);
520 igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
521
522 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
523
524 /* Need to work out where this timer comes from */
525 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
526 }
527 /* Increment group use */
528 group->use++;
529 /* Join on this interface */
530 return ERR_OK;
531 } else {
532 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: Not enough memory to join to group\n"));
533 return ERR_MEM;
534 }
535}
536
545err_t
546igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr)
547{
548 err_t err = ERR_VAL; /* no matching interface */
549 struct netif *netif;
550
552
553 /* make sure it is multicast address */
554 LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
555 LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;);
556
557 /* loop through netif's */
559 /* Should we leave this interface ? */
560 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_eq(netif_ip4_addr(netif), ifaddr)))) {
561 err_t res = igmp_leavegroup_netif(netif, groupaddr);
562 if (err != ERR_OK) {
563 /* Store this result if we have not yet gotten a success */
564 err = res;
565 }
566 }
567 }
568
569 return err;
570}
571
580err_t
581igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
582{
583 struct igmp_group *group;
584
586
587 /* make sure it is multicast address */
588 LWIP_ERROR("igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
589 LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_eq(groupaddr, &allsystems)), return ERR_VAL;);
590
591 /* make sure it is an igmp-enabled netif */
592 LWIP_ERROR("igmp_leavegroup_netif: attempt to leave on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;);
593
594 /* find group */
595 group = igmp_lookfor_group(netif, groupaddr);
596
597 if (group != NULL) {
598 /* Only send a leave if the flag is set according to the state diagram */
599 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: Leaving group: "));
600 ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
601 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
602
603 /* If there is no other use of the group */
604 if (group->use <= 1) {
605 /* Remove the group from the list */
606 igmp_remove_group(netif, group);
607
608 /* If we are the last reporter for this group */
609 if (group->last_reporter_flag) {
610 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n"));
611 IGMP_STATS_INC(igmp.tx_leave);
612 igmp_send(netif, group, IGMP_LEAVE_GROUP);
613 }
614
615 /* Disable the group at the MAC level */
616 if (netif->igmp_mac_filter != NULL) {
617 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL "));
618 ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
619 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif));
620 netif->igmp_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
621 }
622
623 /* Free group struct */
624 memp_free(MEMP_IGMP_GROUP, group);
625 } else {
626 /* Decrement group use */
627 group->use--;
628 }
629 return ERR_OK;
630 } else {
631 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: not member of group\n"));
632 return ERR_VAL;
633 }
634}
635
640void
641igmp_tmr(void)
642{
643 struct netif *netif;
644
646 struct igmp_group *group = netif_igmp_data(netif);
647
648 while (group != NULL) {
649 if (group->timer > 0) {
650 group->timer--;
651 if (group->timer == 0) {
652 igmp_timeout(netif, group);
653 }
654 }
655 group = group->next;
656 }
657 }
658}
659
666static void
667igmp_timeout(struct netif *netif, struct igmp_group *group)
668{
669 /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group
670 (unless it is the allsystems group) */
671 if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
672 (!(ip4_addr_eq(&(group->group_address), &allsystems)))) {
673 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
674 ip4_addr_debug_print_val(IGMP_DEBUG, group->group_address);
675 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)netif));
676
677 group->group_state = IGMP_GROUP_IDLE_MEMBER;
678
679 IGMP_STATS_INC(igmp.tx_report);
680 igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
681 }
682}
683
691static void
692igmp_start_timer(struct igmp_group *group, u8_t max_time)
693{
694#ifdef LWIP_RAND
695 group->timer = (u16_t)(max_time > 2 ? (LWIP_RAND() % max_time) : 1);
696#else /* LWIP_RAND */
697 /* ATTENTION: use this only if absolutely necessary! */
698 group->timer = max_time / 2;
699#endif /* LWIP_RAND */
700
701 if (group->timer == 0) {
702 group->timer = 1;
703 }
704}
705
712static void
713igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
714{
715 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
716 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
717 ((group->timer == 0) || (maxresp < group->timer)))) {
718 igmp_start_timer(group, maxresp);
719 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
720 }
721}
722
723
740static err_t
741igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif)
742{
743 /* This is the "router alert" option */
744 u16_t ra[2];
745 ra[0] = PP_HTONS(ROUTER_ALERT);
746 ra[1] = 0x0000; /* Router shall examine packet */
747 IGMP_STATS_INC(igmp.xmit);
748 return ip4_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
749}
750
757static void
758igmp_send(struct netif *netif, struct igmp_group *group, u8_t type)
759{
760 struct pbuf *p = NULL;
761 struct igmp_msg *igmp = NULL;
762 ip4_addr_t src = *IP4_ADDR_ANY4;
763 ip4_addr_t *dest = NULL;
764
765 /* IP header + "router alert" option + IGMP header */
767
768 if (p) {
769 igmp = (struct igmp_msg *)p->payload;
770 LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
771 (p->len >= sizeof(struct igmp_msg)));
772 ip4_addr_copy(src, *netif_ip4_addr(netif));
773
774 if (type == IGMP_V2_MEMB_REPORT) {
775 dest = &(group->group_address);
776 ip4_addr_copy(igmp->igmp_group_address, group->group_address);
777 group->last_reporter_flag = 1; /* Remember we were the last to report */
778 } else {
779 if (type == IGMP_LEAVE_GROUP) {
780 dest = &allrouters;
781 ip4_addr_copy(igmp->igmp_group_address, group->group_address);
782 }
783 }
784
786 igmp->igmp_msgtype = type;
787 igmp->igmp_maxresp = 0;
788 igmp->igmp_checksum = 0;
789 igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
790
791 igmp_ip_output_if(p, &src, dest, netif);
792 }
793
794 pbuf_free(p);
795 } else {
796 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
797 IGMP_STATS_INC(igmp.memerr);
798 }
799}
800
801#endif /* LWIP_IPV4 && LWIP_IGMP */
#define PP_HTONS(x)
Definition: def.h:90
#define NULL
Definition: types.h:112
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:130
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define IP_PROTO_IGMP
Definition: ip.h:47
#define ERR_MEM
Definition: fontsub.h:52
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLboolean GLuint group
Definition: glext.h:11120
GLenum const GLvoid * addr
Definition: glext.h:9621
GLfloat GLfloat p
Definition: glext.h:8902
uint8_t u8_t
Definition: arch.h:125
uint16_t u16_t
Definition: arch.h:127
s8_t err_t
Definition: err.h:96
@ ERR_OK
Definition: err.h:55
@ ERR_VAL
Definition: err.h:67
@ ERR_ARG
Definition: err.h:88
#define IGMP_DEBUG
Definition: opt.h:3378
#define LWIP_ASSERT_CORE_LOCKED()
Definition: opt.h:227
#define NETIF_FLAG_IGMP
Definition: netif.h:104
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:224
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
@ PBUF_RAM
Definition: pbuf.h:152
@ PBUF_TRANSPORT
Definition: pbuf.h:93
u16_t inet_chksum(const void *dataptr, u16_t len)
Definition: inet_chksum.c:555
if(dx< 0)
Definition: linetemp.h:194
void * memp_malloc(memp_t type)
Definition: memp.c:337
void memp_free(memp_t type, void *mem)
Definition: memp.c:420
static char * dest
Definition: rtl.c:135
#define NETIF_FOREACH(netif)
Definition: netif.h:424
@ NETIF_ADD_MAC_FILTER
Definition: netif.h:163
@ NETIF_DEL_MAC_FILTER
Definition: netif.h:161
#define IGMP_GROUP_NON_MEMBER
Definition: igmp.h:64
#define ROUTER_ALERT
Definition: igmp.h:52
#define IGMP_MEMB_QUERY
Definition: igmp.h:58
#define IGMP_V2_MEMB_REPORT
Definition: igmp.h:60
#define IGMP_LEAVE_GROUP
Definition: igmp.h:61
#define IGMP_GROUP_IDLE_MEMBER
Definition: igmp.h:66
#define IGMP_TTL
Definition: igmp.h:50
#define IGMP_GROUP_DELAYING_MEMBER
Definition: igmp.h:65
#define ROUTER_ALERTLEN
Definition: igmp.h:53
#define IGMP_MINLEN
Definition: igmp.h:51
static unsigned __int64 next
Definition: rand_nt.c:6
#define err(...)
#define IGMP_STATS_INC(x)
Definition: stats.h:352
struct define * next
Definition: compiler.c:65
Definition: igmp.h:75
Definition: list.h:15
struct list_head * next
Definition: list.h:16
Definition: netif.h:269
u8_t flags
Definition: netif.h:354
Definition: pbuf.h:186