ReactOS 0.4.15-dev-7834-g00c4b3d
igmp.c
Go to the documentation of this file.
1
7/*
8 * Copyright (c) 2002 CITEL Technologies Ltd.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * This file is a contribution to the lwIP TCP/IP stack.
36 * The Swedish Institute of Computer Science and Adam Dunkels
37 * are specifically granted permission to redistribute this
38 * source code.
39*/
40
41/*-------------------------------------------------------------
42Note 1)
43Although the rfc requires V1 AND V2 capability
44we will only support v2 since now V1 is very old (August 1989)
45V1 can be added if required
46
47a debug print and statistic have been implemented to
48show this up.
49-------------------------------------------------------------
50-------------------------------------------------------------
51Note 2)
52A query for a specific group address (as opposed to ALLHOSTS)
53has now been implemented as I am unsure if it is required
54
55a debug print and statistic have been implemented to
56show this up.
57-------------------------------------------------------------
58-------------------------------------------------------------
59Note 3)
60The router alert rfc 2113 is implemented in outgoing packets
61but not checked rigorously incoming
62-------------------------------------------------------------
63Steve Reynolds
64------------------------------------------------------------*/
65
66/*-----------------------------------------------------------------------------
67 * RFC 988 - Host extensions for IP multicasting - V0
68 * RFC 1054 - Host extensions for IP multicasting -
69 * RFC 1112 - Host extensions for IP multicasting - V1
70 * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
71 * RFC 3376 - Internet Group Management Protocol, Version 3 - V3
72 * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
73 * RFC 2113 - IP Router Alert Option -
74 *----------------------------------------------------------------------------*/
75
76/*-----------------------------------------------------------------------------
77 * Includes
78 *----------------------------------------------------------------------------*/
79
80#include "lwip/opt.h"
81
82#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
83
84#include "lwip/igmp.h"
85#include "lwip/debug.h"
86#include "lwip/def.h"
87#include "lwip/mem.h"
88#include "lwip/ip.h"
89#include "lwip/inet_chksum.h"
90#include "lwip/netif.h"
91#include "lwip/icmp.h"
92#include "lwip/udp.h"
93#include "lwip/tcp.h"
94#include "lwip/stats.h"
95
96#include "string.h"
97
98/*
99 * IGMP constants
100 */
101#define IGMP_TTL 1
102#define IGMP_MINLEN 8
103#define ROUTER_ALERT 0x9404U
104#define ROUTER_ALERTLEN 4
105
106/*
107 * IGMP message types, including version number.
108 */
109#define IGMP_MEMB_QUERY 0x11 /* Membership query */
110#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
111#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
112#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
113
114/* Group membership states */
115#define IGMP_GROUP_NON_MEMBER 0
116#define IGMP_GROUP_DELAYING_MEMBER 1
117#define IGMP_GROUP_IDLE_MEMBER 2
118
122#ifdef PACK_STRUCT_USE_INCLUDES
123# include "arch/bpstruct.h"
124#endif
126struct igmp_msg {
127 PACK_STRUCT_FIELD(u8_t igmp_msgtype);
128 PACK_STRUCT_FIELD(u8_t igmp_maxresp);
129 PACK_STRUCT_FIELD(u16_t igmp_checksum);
130 PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
133#ifdef PACK_STRUCT_USE_INCLUDES
134# include "arch/epstruct.h"
135#endif
136
137
138static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
139static err_t igmp_remove_group(struct igmp_group *group);
140static void igmp_timeout( struct igmp_group *group);
141static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
142static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
143static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
144static void igmp_send(struct igmp_group *group, u8_t type);
145
146
147static struct igmp_group* igmp_group_list;
148static ip_addr_t allsystems;
149static ip_addr_t allrouters;
150
151
155void
156igmp_init(void)
157{
158 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
159
160 IP4_ADDR(&allsystems, 224, 0, 0, 1);
161 IP4_ADDR(&allrouters, 224, 0, 0, 2);
162}
163
164#ifdef LWIP_DEBUG
168void
169igmp_dump_group_list()
170{
171 struct igmp_group *group = igmp_group_list;
172
173 while (group != NULL) {
174 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
175 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
176 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
177 group = group->next;
178 }
179 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
180}
181#else
182#define igmp_dump_group_list()
183#endif /* LWIP_DEBUG */
184
190err_t
191igmp_start(struct netif *netif)
192{
193 struct igmp_group* group;
194
195 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
196
197 group = igmp_lookup_group(netif, &allsystems);
198
199 if (group != NULL) {
200 group->group_state = IGMP_GROUP_IDLE_MEMBER;
201 group->use++;
202
203 /* Allow the igmp messages at the MAC level */
204 if (netif->igmp_mac_filter != NULL) {
205 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
206 ip_addr_debug_print(IGMP_DEBUG, &allsystems);
207 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
208 netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
209 }
210
211 return ERR_OK;
212 }
213
214 return ERR_MEM;
215}
216
222err_t
223igmp_stop(struct netif *netif)
224{
225 struct igmp_group *group = igmp_group_list;
226 struct igmp_group *prev = NULL;
227 struct igmp_group *next;
228
229 /* look for groups joined on this interface further down the list */
230 while (group != NULL) {
231 next = group->next;
232 /* is it a group joined on this interface? */
233 if (group->netif == netif) {
234 /* is it the first group of the list? */
235 if (group == igmp_group_list) {
236 igmp_group_list = next;
237 }
238 /* is there a "previous" group defined? */
239 if (prev != NULL) {
240 prev->next = next;
241 }
242 /* disable the group at the MAC level */
243 if (netif->igmp_mac_filter != NULL) {
244 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
245 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
246 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
247 netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
248 }
249 /* free group */
250 memp_free(MEMP_IGMP_GROUP, group);
251 } else {
252 /* change the "previous" */
253 prev = group;
254 }
255 /* move to "next" */
256 group = next;
257 }
258 return ERR_OK;
259}
260
266void
267igmp_report_groups(struct netif *netif)
268{
269 struct igmp_group *group = igmp_group_list;
270
271 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
272
273 while (group != NULL) {
274 if (group->netif == netif) {
275 igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
276 }
277 group = group->next;
278 }
279}
280
289struct igmp_group *
290igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
291{
292 struct igmp_group *group = igmp_group_list;
293
294 while (group != NULL) {
295 if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
296 return group;
297 }
298 group = group->next;
299 }
300
301 /* to be clearer, we return NULL here instead of
302 * 'group' (which is also NULL at this point).
303 */
304 return NULL;
305}
306
315struct igmp_group *
316igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
317{
318 struct igmp_group *group = igmp_group_list;
319
320 /* Search if the group already exists */
321 group = igmp_lookfor_group(ifp, addr);
322 if (group != NULL) {
323 /* Group already exists. */
324 return group;
325 }
326
327 /* Group doesn't exist yet, create a new one */
328 group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
329 if (group != NULL) {
330 group->netif = ifp;
331 ip_addr_set(&(group->group_address), addr);
332 group->timer = 0; /* Not running */
333 group->group_state = IGMP_GROUP_NON_MEMBER;
334 group->last_reporter_flag = 0;
335 group->use = 0;
336 group->next = igmp_group_list;
337
338 igmp_group_list = group;
339 }
340
341 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
343 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
344
345 return group;
346}
347
354static err_t
355igmp_remove_group(struct igmp_group *group)
356{
357 err_t err = ERR_OK;
358
359 /* Is it the first group? */
360 if (igmp_group_list == group) {
361 igmp_group_list = group->next;
362 } else {
363 /* look for group further down the list */
364 struct igmp_group *tmpGroup;
365 for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
366 if (tmpGroup->next == group) {
367 tmpGroup->next = group->next;
368 break;
369 }
370 }
371 /* Group not found in the global igmp_group_list */
372 if (tmpGroup == NULL)
373 err = ERR_ARG;
374 }
375 /* free group */
376 memp_free(MEMP_IGMP_GROUP, group);
377
378 return err;
379}
380
388void
389igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
390{
391 struct ip_hdr * iphdr;
392 struct igmp_msg* igmp;
393 struct igmp_group* group;
394 struct igmp_group* groupref;
395
396 IGMP_STATS_INC(igmp.recv);
397
398 /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
399 iphdr = (struct ip_hdr *)p->payload;
400 if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
401 pbuf_free(p);
402 IGMP_STATS_INC(igmp.lenerr);
403 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
404 return;
405 }
406
407 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
408 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
409 LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
411 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
412
413 /* Now calculate and check the checksum */
414 igmp = (struct igmp_msg *)p->payload;
415 if (inet_chksum(igmp, p->len)) {
416 pbuf_free(p);
417 IGMP_STATS_INC(igmp.chkerr);
418 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
419 return;
420 }
421
422 /* Packet is ok so find an existing group */
423 group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
424
425 /* If group can be found or create... */
426 if (!group) {
427 pbuf_free(p);
428 IGMP_STATS_INC(igmp.drop);
429 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
430 return;
431 }
432
433 /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
434 switch (igmp->igmp_msgtype) {
435 case IGMP_MEMB_QUERY: {
436 /* IGMP_MEMB_QUERY to the "all systems" address ? */
437 if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
438 /* THIS IS THE GENERAL QUERY */
439 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)));
440
441 if (igmp->igmp_maxresp == 0) {
442 IGMP_STATS_INC(igmp.rx_v1);
443 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
444 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
445 } else {
446 IGMP_STATS_INC(igmp.rx_general);
447 }
448
449 groupref = igmp_group_list;
450 while (groupref) {
451 /* Do not send messages on the all systems group address! */
452 if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
453 igmp_delaying_member(groupref, igmp->igmp_maxresp);
454 }
455 groupref = groupref->next;
456 }
457 } else {
458 /* IGMP_MEMB_QUERY to a specific group ? */
459 if (!ip_addr_isany(&igmp->igmp_group_address)) {
460 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
461 ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
462 if (ip_addr_cmp(dest, &allsystems)) {
463 ip_addr_t groupaddr;
464 LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
465 /* we first need to re-look for the group since we used dest last time */
466 ip_addr_copy(groupaddr, igmp->igmp_group_address);
467 group = igmp_lookfor_group(inp, &groupaddr);
468 } else {
469 LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
470 }
471
472 if (group != NULL) {
473 IGMP_STATS_INC(igmp.rx_group);
474 igmp_delaying_member(group, igmp->igmp_maxresp);
475 } else {
476 IGMP_STATS_INC(igmp.drop);
477 }
478 } else {
479 IGMP_STATS_INC(igmp.proterr);
480 }
481 }
482 break;
483 }
484 case IGMP_V2_MEMB_REPORT: {
485 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
486 IGMP_STATS_INC(igmp.rx_report);
487 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
488 /* This is on a specific group we have already looked up */
489 group->timer = 0; /* stopped */
490 group->group_state = IGMP_GROUP_IDLE_MEMBER;
491 group->last_reporter_flag = 0;
492 }
493 break;
494 }
495 default: {
496 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
497 igmp->igmp_msgtype, group->group_state, &group, group->netif));
498 IGMP_STATS_INC(igmp.proterr);
499 break;
500 }
501 }
502
503 pbuf_free(p);
504 return;
505}
506
514err_t
515igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
516{
517 err_t err = ERR_VAL; /* no matching interface */
518 struct igmp_group *group;
519 struct netif *netif;
520
521 /* make sure it is multicast address */
522 LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
523 LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
524
525 /* loop through netif's */
527 while (netif != NULL) {
528 /* Should we join this interface ? */
529 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
530 /* find group or create a new one if not found */
531 group = igmp_lookup_group(netif, groupaddr);
532
533 if (group != NULL) {
534 /* This should create a new group, check the state to make sure */
535 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
536 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
537 } else {
538 /* OK - it was new group */
539 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
541 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
542
543 /* If first use of the group, allow the group at the MAC level */
544 if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
545 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
547 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
548 netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
549 }
550
551 IGMP_STATS_INC(igmp.tx_join);
552 igmp_send(group, IGMP_V2_MEMB_REPORT);
553
554 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
555
556 /* Need to work out where this timer comes from */
557 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
558 }
559 /* Increment group use */
560 group->use++;
561 /* Join on this interface */
562 err = ERR_OK;
563 } else {
564 /* Return an error even if some network interfaces are joined */
566 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
567 return ERR_MEM;
568 }
569 }
570 /* proceed to next network interface */
571 netif = netif->next;
572 }
573
574 return err;
575}
576
584err_t
585igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
586{
587 err_t err = ERR_VAL; /* no matching interface */
588 struct igmp_group *group;
589 struct netif *netif;
590
591 /* make sure it is multicast address */
592 LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
593 LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
594
595 /* loop through netif's */
597 while (netif != NULL) {
598 /* Should we leave this interface ? */
599 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
600 /* find group */
601 group = igmp_lookfor_group(netif, groupaddr);
602
603 if (group != NULL) {
604 /* Only send a leave if the flag is set according to the state diagram */
605 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
607 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
608
609 /* If there is no other use of the group */
610 if (group->use <= 1) {
611 /* If we are the last reporter for this group */
612 if (group->last_reporter_flag) {
613 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
614 IGMP_STATS_INC(igmp.tx_leave);
615 igmp_send(group, IGMP_LEAVE_GROUP);
616 }
617
618 /* Disable the group at the MAC level */
619 if (netif->igmp_mac_filter != NULL) {
620 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
622 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
623 netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
624 }
625
626 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
628 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
629
630 /* Free the group */
631 igmp_remove_group(group);
632 } else {
633 /* Decrement group use */
634 group->use--;
635 }
636 /* Leave on this interface */
637 err = ERR_OK;
638 } else {
639 /* It's not a fatal error on "leavegroup" */
640 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
641 }
642 }
643 /* proceed to next network interface */
644 netif = netif->next;
645 }
646
647 return err;
648}
649
654void
655igmp_tmr(void)
656{
657 struct igmp_group *group = igmp_group_list;
658
659 while (group != NULL) {
660 if (group->timer > 0) {
661 group->timer--;
662 if (group->timer == 0) {
663 igmp_timeout(group);
664 }
665 }
666 group = group->next;
667 }
668}
669
676static void
677igmp_timeout(struct igmp_group *group)
678{
679 /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
680 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
681 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
682 ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
683 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
684
685 IGMP_STATS_INC(igmp.tx_report);
686 igmp_send(group, IGMP_V2_MEMB_REPORT);
687 }
688}
689
697static void
698igmp_start_timer(struct igmp_group *group, u8_t max_time)
699{
700 /* ensure the input value is > 0 */
701 if (max_time == 0) {
702 max_time = 1;
703 }
704 /* ensure the random value is > 0 */
705 group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
706}
707
714static void
715igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
716{
717 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
718 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
719 ((group->timer == 0) || (maxresp < group->timer)))) {
720 igmp_start_timer(group, maxresp);
721 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
722 }
723}
724
725
744static err_t
745igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
746{
747 /* This is the "router alert" option */
748 u16_t ra[2];
749 ra[0] = PP_HTONS(ROUTER_ALERT);
750 ra[1] = 0x0000; /* Router shall examine packet */
751 IGMP_STATS_INC(igmp.xmit);
752 return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
753}
754
761static void
762igmp_send(struct igmp_group *group, u8_t type)
763{
764 struct pbuf* p = NULL;
765 struct igmp_msg* igmp = NULL;
768
769 /* IP header + "router alert" option + IGMP header */
770 p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
771
772 if (p) {
773 igmp = (struct igmp_msg *)p->payload;
774 LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
775 (p->len >= sizeof(struct igmp_msg)));
776 ip_addr_copy(src, group->netif->ip_addr);
777
778 if (type == IGMP_V2_MEMB_REPORT) {
779 dest = &(group->group_address);
780 ip_addr_copy(igmp->igmp_group_address, group->group_address);
781 group->last_reporter_flag = 1; /* Remember we were the last to report */
782 } else {
783 if (type == IGMP_LEAVE_GROUP) {
784 dest = &allrouters;
785 ip_addr_copy(igmp->igmp_group_address, group->group_address);
786 }
787 }
788
789 if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
790 igmp->igmp_msgtype = type;
791 igmp->igmp_maxresp = 0;
792 igmp->igmp_checksum = 0;
793 igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
794
795 igmp_ip_output_if(p, &src, dest, group->netif);
796 }
797
798 pbuf_free(p);
799 } else {
800 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
801 IGMP_STATS_INC(igmp.memerr);
802 }
803}
804
805#endif /* LWIP_IGMP */
#define PACK_STRUCT_END
Definition: arch.h:64
#define PACK_STRUCT_BEGIN
Definition: arch.h:60
#define PACK_STRUCT_FIELD(x)
Definition: arch.h:68
#define PP_HTONS(x)
Definition: def.h:88
#define NULL
Definition: types.h:112
#define PACK_STRUCT_STRUCT
Definition: cc.h:59
signed short s16_t
Definition: cc.h:29
unsigned long u32_t
Definition: cc.h:25
#define U32_F
Definition: cc.h:39
unsigned char u8_t
Definition: cc.h:23
unsigned short u16_t
Definition: cc.h:24
#define IP_PROTO_IGMP
Definition: ip.h:53
#define IPH_HL(hdr)
Definition: ip.h:147
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:95
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:74
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:66
#define ERR_MEM
Definition: err.h:53
#define ERR_ARG
Definition: err.h:70
#define ERR_OK
Definition: err.h:52
#define ERR_VAL
Definition: err.h:58
s8_t err_t
Definition: err.h:47
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
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
u16_t inet_chksum(void *dataptr, u16_t len)
Definition: inet_chksum.c:396
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:198
#define ip_addr_isany(addr1)
Definition: ip_addr.h:200
#define ip_addr_ismulticast(addr1)
Definition: ip_addr.h:208
#define IP_ADDR_ANY
Definition: ip_addr.h:92
#define ip_addr_set(dest, src)
Definition: ip_addr.h:164
#define IP4_ADDR(ipaddr, a, b, c, d)
Definition: ip_addr.h:139
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:162
typedefPACK_STRUCT_END struct ip_addr ip_addr_t
Definition: ip_addr.h:64
#define ip_addr_debug_print(debug, ipaddr)
Definition: ip_addr.h:212
if(dx< 0)
Definition: linetemp.h:194
void * memp_malloc(memp_t type)
Definition: memp.c:390
void memp_free(memp_t type, void *mem)
Definition: memp.c:435
static char * dest
Definition: rtl.c:135
struct netif * netif_list
Definition: netif.c:75
#define NETIF_FLAG_IGMP
Definition: netif.h:95
#define IGMP_DEBUG
Definition: opt.h:1947
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
Definition: pbuf.c:511
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:207
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:618
@ PBUF_RAM
Definition: pbuf.h:58
@ PBUF_TRANSPORT
Definition: pbuf.h:51
static unsigned __int64 next
Definition: rand_nt.c:6
#define err(...)
#define IGMP_STATS_INC(x)
Definition: stats.h:195
struct define * next
Definition: compiler.c:65
Definition: ip.h:116
struct ip_addr src dest
Definition: ip.h:96
Definition: netif.h:136
u8_t flags
Definition: netif.h:192
ip_addr_t ip_addr
Definition: netif.h:141
struct netif * next
Definition: netif.h:138
Definition: pbuf.h:79