ReactOS  0.4.15-dev-1397-g19779b3
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 /*-------------------------------------------------------------
42 Note 1)
43 Although the rfc requires V1 AND V2 capability
44 we will only support v2 since now V1 is very old (August 1989)
45 V1 can be added if required
46 
47 a debug print and statistic have been implemented to
48 show this up.
49 -------------------------------------------------------------
50 -------------------------------------------------------------
51 Note 2)
52 A query for a specific group address (as opposed to ALLHOSTS)
53 has now been implemented as I am unsure if it is required
54 
55 a debug print and statistic have been implemented to
56 show this up.
57 -------------------------------------------------------------
58 -------------------------------------------------------------
59 Note 3)
60 The router alert rfc 2113 is implemented in outgoing packets
61 but not checked rigorously incoming
62 -------------------------------------------------------------
63 Steve 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
126 struct 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 
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_delaying_member(struct igmp_group *group, u8_t maxresp);
143 static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
144 static void igmp_send(struct igmp_group *group, u8_t type);
145 
146 
147 static struct igmp_group* igmp_group_list;
148 static ip_addr_t allsystems;
149 static ip_addr_t allrouters;
150 
151 
155 void
156 igmp_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
165 
168 void
169 igmp_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 
190 err_t
191 igmp_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 
222 err_t
223 igmp_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 
266 void
267 igmp_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 
289 struct igmp_group *
290 igmp_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 
315 struct igmp_group *
316 igmp_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 
354 static err_t
355 igmp_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 
388 void
389 igmp_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 "));
410  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
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 
514 err_t
515 igmp_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 */
526  netif = netif_list;
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: "));
540  ip_addr_debug_print(IGMP_DEBUG, groupaddr);
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 "));
546  ip_addr_debug_print(IGMP_DEBUG, groupaddr);
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 
584 err_t
585 igmp_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 */
596  netif = netif_list;
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: "));
606  ip_addr_debug_print(IGMP_DEBUG, groupaddr);
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 "));
621  ip_addr_debug_print(IGMP_DEBUG, groupaddr);
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: "));
627  ip_addr_debug_print(IGMP_DEBUG, groupaddr);
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 
654 void
655 igmp_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 
676 static void
677 igmp_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 
697 static void
698 igmp_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 
714 static void
715 igmp_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 
744 static err_t
745 igmp_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 
761 static void
762 igmp_send(struct igmp_group *group, u8_t type)
763 {
764  struct pbuf* p = NULL;
765  struct igmp_msg* igmp = NULL;
767  ip_addr_t* dest = 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 ERR_ARG
Definition: err.h:70
struct netif * netif_list
Definition: netif.c:75
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:162
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
Definition: pbuf.c:511
#define U32_F
Definition: cc.h:39
#define IGMP_STATS_INC(x)
Definition: stats.h:195
typedefPACK_STRUCT_END struct ip_addr ip_addr_t
Definition: ip_addr.h:64
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:66
#define PACK_STRUCT_FIELD(x)
Definition: arch.h:68
void memp_free(memp_t type, void *mem)
Definition: memp.c:435
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:207
Definition: pbuf.h:58
#define IP_PROTO_IGMP
Definition: ip.h:53
#define IP4_ADDR(ipaddr, a, b, c, d)
Definition: ip_addr.h:139
#define ERR_VAL
Definition: err.h:58
#define PACK_STRUCT_STRUCT
Definition: cc.h:59
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:618
s8_t err_t
Definition: err.h:47
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:95
#define PP_HTONS(x)
Definition: def.h:88
#define IGMP_DEBUG
Definition: opt.h:1947
u16_t inet_chksum(void *dataptr, u16_t len)
Definition: inet_chksum.c:396
#define ERR_OK
Definition: err.h:52
struct netif * next
Definition: netif.h:138
GLboolean GLuint group
Definition: glext.h:11120
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define ip_addr_ismulticast(addr1)
Definition: ip_addr.h:208
Definition: pbuf.h:79
unsigned long u32_t
Definition: cc.h:25
u8_t flags
Definition: netif.h:192
#define IP_ADDR_ANY
Definition: ip_addr.h:92
#define ip_addr_debug_print(debug, ipaddr)
Definition: ip_addr.h:212
Definition: netif.h:136
#define NETIF_FLAG_IGMP
Definition: netif.h:95
ip_addr_t ip_addr
Definition: netif.h:141
GLenum const GLvoid * addr
Definition: glext.h:9621
#define PACK_STRUCT_BEGIN
Definition: arch.h:60
struct ip_addr src dest
Definition: ip.h:96
GLenum src
Definition: glext.h:6340
#define err(...)
static unsigned __int64 next
Definition: rand_nt.c:6
#define ip_addr_set(dest, src)
Definition: ip_addr.h:164
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:74
#define ip_addr_isany(addr1)
Definition: ip_addr.h:200
Definition: ip.h:116
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:198
#define IPH_HL(hdr)
Definition: ip.h:147
#define ERR_MEM
Definition: fontsub.h:52
struct define * next
Definition: compiler.c:65
unsigned char u8_t
Definition: cc.h:23
#define NULL
Definition: types.h:112
#define PACK_STRUCT_END
Definition: arch.h:64
static char * dest
Definition: rtl.c:135
unsigned short u16_t
Definition: cc.h:24
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
void * memp_malloc(memp_t type)
Definition: memp.c:390
GLfloat GLfloat p
Definition: glext.h:8902
signed short s16_t
Definition: cc.h:29