91 #include "lwip/icmp.h"
102 #define IGMP_MINLEN 8
103 #define ROUTER_ALERT 0x9404
104 #define ROUTER_ALERTLEN 4
109 #define IGMP_MEMB_QUERY 0x11
110 #define IGMP_V1_MEMB_REPORT 0x12
111 #define IGMP_V2_MEMB_REPORT 0x16
112 #define IGMP_LEAVE_GROUP 0x17
115 #define IGMP_GROUP_NON_MEMBER 0
116 #define IGMP_GROUP_DELAYING_MEMBER 1
117 #define IGMP_GROUP_IDLE_MEMBER 2
122 #ifdef PACK_STRUCT_USE_INCLUDES
123 # include "arch/bpstruct.h"
133 #ifdef PACK_STRUCT_USE_INCLUDES
134 # include "arch/epstruct.h"
138 static struct igmp_group *igmp_lookup_group(
struct netif *ifp,
ip_addr_t *addr);
139 static err_t igmp_remove_group(
struct igmp_group *group);
140 static void igmp_timeout(
struct igmp_group *group);
141 static void igmp_start_timer(
struct igmp_group *group,
u8_t max_time);
142 static void igmp_stop_timer(
struct igmp_group *group);
143 static void igmp_delaying_member(
struct igmp_group *group,
u8_t maxresp);
145 static void igmp_send(
struct igmp_group *group,
u8_t type);
148 static struct igmp_group* igmp_group_list;
161 IP4_ADDR(&allsystems, 224, 0, 0, 1);
162 IP4_ADDR(&allrouters, 224, 0, 0, 2);
170 igmp_dump_group_list()
172 struct igmp_group *group = igmp_group_list;
174 while (group !=
NULL) {
183 #define igmp_dump_group_list()
194 struct igmp_group* group;
198 group = igmp_lookup_group(netif, &allsystems);
201 group->group_state = IGMP_GROUP_IDLE_MEMBER;
205 if (netif->igmp_mac_filter !=
NULL) {
209 netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
224 igmp_stop(
struct netif *netif)
226 struct igmp_group *group = igmp_group_list;
227 struct igmp_group *prev =
NULL;
228 struct igmp_group *next;
231 while (group !=
NULL) {
234 if (group->netif == netif) {
236 if (group == igmp_group_list) {
237 igmp_group_list = next;
244 if (netif->igmp_mac_filter !=
NULL) {
248 netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
268 igmp_report_groups(
struct netif *netif)
270 struct igmp_group *group = igmp_group_list;
274 while (group !=
NULL) {
275 if (group->netif == netif) {
276 igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
291 igmp_lookfor_group(
struct netif *ifp,
ip_addr_t *addr)
293 struct igmp_group *group = igmp_group_list;
295 while (group !=
NULL) {
296 if ((group->netif == ifp) && (
ip_addr_cmp(&(group->group_address), addr))) {
317 igmp_lookup_group(
struct netif *ifp,
ip_addr_t *addr)
319 struct igmp_group *group = igmp_group_list;
322 group = igmp_lookfor_group(ifp, addr);
329 group = (
struct igmp_group *)
memp_malloc(MEMP_IGMP_GROUP);
334 group->group_state = IGMP_GROUP_NON_MEMBER;
335 group->last_reporter_flag = 0;
337 group->next = igmp_group_list;
339 igmp_group_list = group;
342 LWIP_DEBUGF(
IGMP_DEBUG, (
"igmp_lookup_group: %sallocated a new group with address ", (group?
"":
"impossible to ")));
356 igmp_remove_group(
struct igmp_group *group)
361 if (igmp_group_list == group) {
362 igmp_group_list = group->next;
365 struct igmp_group *tmpGroup;
366 for (tmpGroup = igmp_group_list; tmpGroup !=
NULL; tmpGroup = tmpGroup->next) {
367 if (tmpGroup->next == group) {
368 tmpGroup->next = group->next;
373 if (tmpGroup ==
NULL)
390 igmp_input(
struct pbuf *p,
struct netif *inp,
ip_addr_t *dest)
393 struct igmp_msg* igmp;
394 struct igmp_group* group;
395 struct igmp_group* groupref;
415 igmp = (
struct igmp_msg *)p->
payload;
424 group = igmp_lookfor_group(inp, dest);
435 switch (igmp->igmp_msgtype) {
436 case IGMP_MEMB_QUERY: {
440 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)));
442 if (igmp->igmp_maxresp == 0) {
444 LWIP_DEBUGF(
IGMP_DEBUG, (
"igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
445 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
450 groupref = igmp_group_list;
453 if ((groupref->netif == inp) && (!(
ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
454 igmp_delaying_member(groupref, igmp->igmp_maxresp);
456 groupref = groupref->next;
465 LWIP_DEBUGF(
IGMP_DEBUG, (
" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (
int)(igmp->igmp_maxresp)));
468 group = igmp_lookfor_group(inp, &groupaddr);
470 LWIP_DEBUGF(
IGMP_DEBUG, (
" with the group address as destination [igmp_maxresp=%i]\n", (
int)(igmp->igmp_maxresp)));
475 igmp_delaying_member(group, igmp->igmp_maxresp);
485 case IGMP_V2_MEMB_REPORT: {
488 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
491 group->group_state = IGMP_GROUP_IDLE_MEMBER;
492 group->last_reporter_flag = 0;
498 igmp->igmp_msgtype, group->group_state, &group, group->netif));
519 struct igmp_group *group;
528 while (netif !=
NULL) {
532 group = igmp_lookup_group(netif, groupaddr);
536 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
545 if ((group->use==0) && (netif->igmp_mac_filter !=
NULL)) {
549 netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
553 igmp_send(group, IGMP_V2_MEMB_REPORT);
555 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
558 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
589 struct igmp_group *group;
598 while (netif !=
NULL) {
602 group = igmp_lookfor_group(netif, groupaddr);
611 if (group->use <= 1) {
613 if (group->last_reporter_flag) {
616 igmp_send(group, IGMP_LEAVE_GROUP);
620 if (netif->igmp_mac_filter !=
NULL) {
624 netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
632 igmp_remove_group(group);
658 struct igmp_group *group = igmp_group_list;
660 while (group !=
NULL) {
661 if (group->timer > 0) {
663 if (group->timer == 0) {
678 igmp_timeout(
struct igmp_group *group)
681 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
687 igmp_send(group, IGMP_V2_MEMB_REPORT);
699 igmp_start_timer(
struct igmp_group *group,
u8_t max_time)
706 group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
715 igmp_stop_timer(
struct igmp_group *group)
727 igmp_delaying_member(
struct igmp_group *group,
u8_t maxresp)
729 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
730 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
731 ((group->timer == 0) || (maxresp < group->timer)))) {
732 igmp_start_timer(group, maxresp);
733 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
764 return ip_output_if_opt(p, src, dest, IGMP_TTL, 0,
IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
774 igmp_send(
struct igmp_group *group,
u8_t type)
777 struct igmp_msg* igmp =
NULL;
785 igmp = (
struct igmp_msg *)p->
payload;
786 LWIP_ASSERT(
"igmp_send: check that first pbuf can hold struct igmp_msg",
787 (p->
len >=
sizeof(
struct igmp_msg)));
790 if (type == IGMP_V2_MEMB_REPORT) {
791 dest = &(group->group_address);
792 ip_addr_copy(igmp->igmp_group_address, group->group_address);
793 group->last_reporter_flag = 1;
795 if (type == IGMP_LEAVE_GROUP) {
797 ip_addr_copy(igmp->igmp_group_address, group->group_address);
801 if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
802 igmp->igmp_msgtype = type;
803 igmp->igmp_maxresp = 0;
804 igmp->igmp_checksum = 0;
805 igmp->igmp_checksum =
inet_chksum(igmp, IGMP_MINLEN);
807 igmp_ip_output_if(p, &src, dest, group->netif);