STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
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_IPV4 && 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/stats.h"
92 
93 #include "string.h"
94 
95 /*
96  * IGMP constants
97  */
98 #define IGMP_TTL 1
99 #define IGMP_MINLEN 8
100 #define ROUTER_ALERT 0x9404U
101 #define ROUTER_ALERTLEN 4
102 
103 /*
104  * IGMP message types, including version number.
105  */
106 #define IGMP_MEMB_QUERY 0x11 /* Membership query */
107 #define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
108 #define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
109 #define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
110 
111 /* Group membership states */
112 #define IGMP_GROUP_NON_MEMBER 0
113 #define IGMP_GROUP_DELAYING_MEMBER 1
114 #define IGMP_GROUP_IDLE_MEMBER 2
115 
119 #ifdef PACK_STRUCT_USE_INCLUDES
120 # include "arch/bpstruct.h"
121 #endif
123 struct igmp_msg {
124  PACK_STRUCT_FLD_8(u8_t igmp_msgtype);
125  PACK_STRUCT_FLD_8(u8_t igmp_maxresp);
126  PACK_STRUCT_FIELD(u16_t igmp_checksum);
127  PACK_STRUCT_FLD_S(ip4_addr_p_t igmp_group_address);
130 #ifdef PACK_STRUCT_USE_INCLUDES
131 # include "arch/epstruct.h"
132 #endif
133 
134 
135 static struct igmp_group *igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr);
136 static err_t igmp_remove_group(struct igmp_group *group);
137 static void igmp_timeout( struct igmp_group *group);
138 static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
139 static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
140 static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif);
141 static void igmp_send(struct igmp_group *group, u8_t type);
142 
143 
144 static struct igmp_group* igmp_group_list;
145 static ip4_addr_t allsystems;
146 static ip4_addr_t allrouters;
147 
148 
152 void
153 igmp_init(void)
154 {
155  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
156 
157  IP4_ADDR(&allsystems, 224, 0, 0, 1);
158  IP4_ADDR(&allrouters, 224, 0, 0, 2);
159 }
160 
166 err_t
167 igmp_start(struct netif *netif)
168 {
169  struct igmp_group* group;
170 
171  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", (void*)netif));
172 
173  group = igmp_lookup_group(netif, &allsystems);
174 
175  if (group != NULL) {
176  group->group_state = IGMP_GROUP_IDLE_MEMBER;
177  group->use++;
178 
179  /* Allow the igmp messages at the MAC level */
180  if (netif->igmp_mac_filter != NULL) {
181  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
182  ip4_addr_debug_print_val(IGMP_DEBUG, allsystems);
183  LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
184  netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
185  }
186 
187  return ERR_OK;
188  }
189 
190  return ERR_MEM;
191 }
192 
198 err_t
199 igmp_stop(struct netif *netif)
200 {
201  struct igmp_group *group = igmp_group_list;
202  struct igmp_group *prev = NULL;
203  struct igmp_group *next;
204 
205  /* look for groups joined on this interface further down the list */
206  while (group != NULL) {
207  next = group->next;
208  /* is it a group joined on this interface? */
209  if (group->netif == netif) {
210  /* is it the first group of the list? */
211  if (group == igmp_group_list) {
212  igmp_group_list = next;
213  }
214  /* is there a "previous" group defined? */
215  if (prev != NULL) {
216  prev->next = next;
217  }
218  /* disable the group at the MAC level */
219  if (netif->igmp_mac_filter != NULL) {
220  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
221  ip4_addr_debug_print(IGMP_DEBUG, &group->group_address);
222  LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
223  netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
224  }
225  /* free group */
226  memp_free(MEMP_IGMP_GROUP, group);
227  } else {
228  /* change the "previous" */
229  prev = group;
230  }
231  /* move to "next" */
232  group = next;
233  }
234  return ERR_OK;
235 }
236 
242 void
243 igmp_report_groups(struct netif *netif)
244 {
245  struct igmp_group *group = igmp_group_list;
246 
247  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void*)netif));
248 
249  while (group != NULL) {
250  if ((group->netif == netif) && (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) {
251  igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
252  }
253  group = group->next;
254  }
255 }
256 
265 struct igmp_group *
266 igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr)
267 {
268  struct igmp_group *group = igmp_group_list;
269 
270  while (group != NULL) {
271  if ((group->netif == ifp) && (ip4_addr_cmp(&(group->group_address), addr))) {
272  return group;
273  }
274  group = group->next;
275  }
276 
277  /* to be clearer, we return NULL here instead of
278  * 'group' (which is also NULL at this point).
279  */
280  return NULL;
281 }
282 
291 struct igmp_group *
292 igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
293 {
294  struct igmp_group *group;
295 
296  /* Search if the group already exists */
297  group = igmp_lookfor_group(ifp, addr);
298  if (group != NULL) {
299  /* Group already exists. */
300  return group;
301  }
302 
303  /* Group doesn't exist yet, create a new one */
304  group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
305  if (group != NULL) {
306  group->netif = ifp;
307  ip4_addr_set(&(group->group_address), addr);
308  group->timer = 0; /* Not running */
309  group->group_state = IGMP_GROUP_NON_MEMBER;
310  group->last_reporter_flag = 0;
311  group->use = 0;
312  group->next = igmp_group_list;
313 
314  igmp_group_list = group;
315  }
316 
317  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
318  ip4_addr_debug_print(IGMP_DEBUG, addr);
319  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)ifp));
320 
321  return group;
322 }
323 
330 static err_t
331 igmp_remove_group(struct igmp_group *group)
332 {
333  err_t err = ERR_OK;
334 
335  /* Is it the first group? */
336  if (igmp_group_list == group) {
337  igmp_group_list = group->next;
338  } else {
339  /* look for group further down the list */
340  struct igmp_group *tmpGroup;
341  for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
342  if (tmpGroup->next == group) {
343  tmpGroup->next = group->next;
344  break;
345  }
346  }
347  /* Group not found in the global igmp_group_list */
348  if (tmpGroup == NULL) {
349  err = ERR_ARG;
350  }
351  }
352  /* free group */
353  memp_free(MEMP_IGMP_GROUP, group);
354 
355  return err;
356 }
357 
365 void
366 igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
367 {
368  struct igmp_msg* igmp;
369  struct igmp_group* group;
370  struct igmp_group* groupref;
371 
372  IGMP_STATS_INC(igmp.recv);
373 
374  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
375  if (p->len < IGMP_MINLEN) {
376  pbuf_free(p);
377  IGMP_STATS_INC(igmp.lenerr);
378  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
379  return;
380  }
381 
382  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
383  ip4_addr_debug_print(IGMP_DEBUG, &(ip4_current_header()->src));
384  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
385  ip4_addr_debug_print(IGMP_DEBUG, &(ip4_current_header()->dest));
386  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)inp));
387 
388  /* Now calculate and check the checksum */
389  igmp = (struct igmp_msg *)p->payload;
390  if (inet_chksum(igmp, p->len)) {
391  pbuf_free(p);
392  IGMP_STATS_INC(igmp.chkerr);
393  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
394  return;
395  }
396 
397  /* Packet is ok so find an existing group */
398  group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
399 
400  /* If group can be found or create... */
401  if (!group) {
402  pbuf_free(p);
403  IGMP_STATS_INC(igmp.drop);
404  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
405  return;
406  }
407 
408  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
409  switch (igmp->igmp_msgtype) {
410  case IGMP_MEMB_QUERY:
411  /* IGMP_MEMB_QUERY to the "all systems" address ? */
412  if ((ip4_addr_cmp(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) {
413  /* THIS IS THE GENERAL QUERY */
414  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)));
415 
416  if (igmp->igmp_maxresp == 0) {
417  IGMP_STATS_INC(igmp.rx_v1);
418  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
419  igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
420  } else {
421  IGMP_STATS_INC(igmp.rx_general);
422  }
423 
424  groupref = igmp_group_list;
425  while (groupref) {
426  /* Do not send messages on the all systems group address! */
427  if ((groupref->netif == inp) && (!(ip4_addr_cmp(&(groupref->group_address), &allsystems)))) {
428  igmp_delaying_member(groupref, igmp->igmp_maxresp);
429  }
430  groupref = groupref->next;
431  }
432  } else {
433  /* IGMP_MEMB_QUERY to a specific group ? */
434  if (!ip4_addr_isany(&igmp->igmp_group_address)) {
435  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
436  ip4_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
437  if (ip4_addr_cmp(dest, &allsystems)) {
438  ip4_addr_t groupaddr;
439  LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
440  /* we first need to re-look for the group since we used dest last time */
441  ip4_addr_copy(groupaddr, igmp->igmp_group_address);
442  group = igmp_lookfor_group(inp, &groupaddr);
443  } else {
444  LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
445  }
446 
447  if (group != NULL) {
448  IGMP_STATS_INC(igmp.rx_group);
449  igmp_delaying_member(group, igmp->igmp_maxresp);
450  } else {
451  IGMP_STATS_INC(igmp.drop);
452  }
453  } else {
454  IGMP_STATS_INC(igmp.proterr);
455  }
456  }
457  break;
458  case IGMP_V2_MEMB_REPORT:
459  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
460  IGMP_STATS_INC(igmp.rx_report);
461  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
462  /* This is on a specific group we have already looked up */
463  group->timer = 0; /* stopped */
464  group->group_state = IGMP_GROUP_IDLE_MEMBER;
465  group->last_reporter_flag = 0;
466  }
467  break;
468  default:
469  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
470  igmp->igmp_msgtype, group->group_state, (void*)&group, (void*)group->netif));
471  IGMP_STATS_INC(igmp.proterr);
472  break;
473  }
474 
475  pbuf_free(p);
476  return;
477 }
478 
486 err_t
487 igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr)
488 {
489  err_t err = ERR_VAL; /* no matching interface */
490  struct netif *netif;
491 
492  /* make sure it is multicast address */
493  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
494  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
495 
496  /* loop through netif's */
497  netif = netif_list;
498  while (netif != NULL) {
499  /* Should we join this interface ? */
500  if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) {
501  err = igmp_joingroup_netif(netif, groupaddr);
502  if (err != ERR_OK) {
503  /* Return an error even if some network interfaces are joined */
505  return err;
506  }
507  }
508  /* proceed to next network interface */
509  netif = netif->next;
510  }
511 
512  return err;
513 }
514 
522 err_t
523 igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
524 {
525  struct igmp_group *group;
526 
527  /* make sure it is multicast address */
528  LWIP_ERROR("igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
529  LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
530 
531  /* make sure it is an igmp-enabled netif */
532  LWIP_ERROR("igmp_joingroup_netif: attempt to join on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;);
533 
534  /* find group or create a new one if not found */
535  group = igmp_lookup_group(netif, groupaddr);
536 
537  if (group != NULL) {
538  /* This should create a new group, check the state to make sure */
539  if (group->group_state != IGMP_GROUP_NON_MEMBER) {
540  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
541  } else {
542  /* OK - it was new group */
543  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to new group: "));
544  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
545  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
546 
547  /* If first use of the group, allow the group at the MAC level */
548  if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
549  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: igmp_mac_filter(ADD "));
550  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
551  LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
552  netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
553  }
554 
555  IGMP_STATS_INC(igmp.tx_join);
556  igmp_send(group, IGMP_V2_MEMB_REPORT);
557 
558  igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
559 
560  /* Need to work out where this timer comes from */
561  group->group_state = IGMP_GROUP_DELAYING_MEMBER;
562  }
563  /* Increment group use */
564  group->use++;
565  /* Join on this interface */
566  return ERR_OK;
567  } else {
568  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: Not enough memory to join to group\n"));
569  return ERR_MEM;
570  }
571 }
572 
580 err_t
581 igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr)
582 {
583  err_t err = ERR_VAL; /* no matching interface */
584  struct netif *netif;
585 
586  /* make sure it is multicast address */
587  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
588  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
589 
590  /* loop through netif's */
591  netif = netif_list;
592  while (netif != NULL) {
593  /* Should we leave this interface ? */
594  if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) {
595  err_t res = igmp_leavegroup_netif(netif, groupaddr);
596  if (err != ERR_OK) {
597  /* Store this result if we have not yet gotten a success */
598  err = res;
599  }
600  }
601  /* proceed to next network interface */
602  netif = netif->next;
603  }
604 
605  return err;
606 }
607 
615 err_t
616 igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
617 {
618  struct igmp_group *group;
619 
620  /* make sure it is multicast address */
621  LWIP_ERROR("igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
622  LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
623 
624  /* make sure it is an igmp-enabled netif */
625  LWIP_ERROR("igmp_leavegroup_netif: attempt to leave on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;);
626 
627  /* find group */
628  group = igmp_lookfor_group(netif, groupaddr);
629 
630  if (group != NULL) {
631  /* Only send a leave if the flag is set according to the state diagram */
632  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: Leaving group: "));
633  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
634  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
635 
636  /* If there is no other use of the group */
637  if (group->use <= 1) {
638  /* If we are the last reporter for this group */
639  if (group->last_reporter_flag) {
640  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n"));
641  IGMP_STATS_INC(igmp.tx_leave);
642  igmp_send(group, IGMP_LEAVE_GROUP);
643  }
644 
645  /* Disable the group at the MAC level */
646  if (netif->igmp_mac_filter != NULL) {
647  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL "));
648  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
649  LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
650  netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
651  }
652 
653  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: remove group: "));
654  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
655  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
656 
657  /* Free the group */
658  igmp_remove_group(group);
659  } else {
660  /* Decrement group use */
661  group->use--;
662  }
663  return ERR_OK;
664  } else {
665  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: not member of group\n"));
666  return ERR_VAL;
667  }
668 }
669 
674 void
675 igmp_tmr(void)
676 {
677  struct igmp_group *group = igmp_group_list;
678 
679  while (group != NULL) {
680  if (group->timer > 0) {
681  group->timer--;
682  if (group->timer == 0) {
683  igmp_timeout(group);
684  }
685  }
686  group = group->next;
687  }
688 }
689 
696 static void
697 igmp_timeout(struct igmp_group *group)
698 {
699  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group
700  (unless it is the allsystems group) */
701  if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
702  (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) {
703  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
704  ip4_addr_debug_print(IGMP_DEBUG, &(group->group_address));
705  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)group->netif));
706 
707  IGMP_STATS_INC(igmp.tx_report);
708  igmp_send(group, IGMP_V2_MEMB_REPORT);
709  }
710 }
711 
719 static void
720 igmp_start_timer(struct igmp_group *group, u8_t max_time)
721 {
722 #ifdef LWIP_RAND
723  group->timer = max_time > 2 ? (LWIP_RAND() % max_time) : 1;
724 #else /* LWIP_RAND */
725  /* ATTENTION: use this only if absolutely necessary! */
726  group->timer = max_time / 2;
727 #endif /* LWIP_RAND */
728 
729  if (group->timer == 0) {
730  group->timer = 1;
731  }
732 }
733 
740 static void
741 igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
742 {
743  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
744  ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
745  ((group->timer == 0) || (maxresp < group->timer)))) {
746  igmp_start_timer(group, maxresp);
747  group->group_state = IGMP_GROUP_DELAYING_MEMBER;
748  }
749 }
750 
751 
770 static err_t
771 igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif)
772 {
773  /* This is the "router alert" option */
774  u16_t ra[2];
775  ra[0] = PP_HTONS(ROUTER_ALERT);
776  ra[1] = 0x0000; /* Router shall examine packet */
777  IGMP_STATS_INC(igmp.xmit);
778  return ip4_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
779 }
780 
787 static void
788 igmp_send(struct igmp_group *group, u8_t type)
789 {
790  struct pbuf* p = NULL;
791  struct igmp_msg* igmp = NULL;
792  ip4_addr_t src = *IP4_ADDR_ANY;
793  ip4_addr_t* dest = NULL;
794 
795  /* IP header + "router alert" option + IGMP header */
796  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
797 
798  if (p) {
799  igmp = (struct igmp_msg *)p->payload;
800  LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
801  (p->len >= sizeof(struct igmp_msg)));
802  ip4_addr_copy(src, *netif_ip4_addr(group->netif));
803 
804  if (type == IGMP_V2_MEMB_REPORT) {
805  dest = &(group->group_address);
806  ip4_addr_copy(igmp->igmp_group_address, group->group_address);
807  group->last_reporter_flag = 1; /* Remember we were the last to report */
808  } else {
809  if (type == IGMP_LEAVE_GROUP) {
810  dest = &allrouters;
811  ip4_addr_copy(igmp->igmp_group_address, group->group_address);
812  }
813  }
814 
815  if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
816  igmp->igmp_msgtype = type;
817  igmp->igmp_maxresp = 0;
818  igmp->igmp_checksum = 0;
819  igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
820 
821  igmp_ip_output_if(p, &src, dest, group->netif);
822  }
823 
824  pbuf_free(p);
825  } else {
826  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
827  IGMP_STATS_INC(igmp.memerr);
828  }
829 }
830 
831 #endif /* LWIP_IPV4 && LWIP_IGMP */
832 
u8_t flags
Definition: netif.h:269
struct netif * netif_list
Definition: netif.c:84
#define PACK_STRUCT_STRUCT
Definition: arch.h:68
#define ERR_VAL
Definition: err.h:58
#define IGMP_STATS_INC(x)
Definition: stats.h:286
#define PACK_STRUCT_FLD_8(x)
Definition: arch.h:78
if(LCD_Lock==DISABLE)
Definition: lcd_log.c:249
#define PACK_STRUCT_FIELD(x)
Definition: arch.h:72
void memp_free(memp_t type, void *mem)
Definition: memp.c:399
u16_t len
Definition: pbuf.h:125
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:199
#define LWIP_RAND()
Definition: cc.h:95
#define IP_PROTO_IGMP
Definition: ip.h:50
Definition: pbuf.h:77
u16_t inet_chksum(const void *dataptr, u16_t len)
Definition: inet_chksum.c:558
#define NULL
Definition: usbd_def.h:53
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:652
#define PP_HTONS(x)
Definition: def.h:97
#define IGMP_DEBUG
Definition: opt.h:2823
#define ERR_OK
Definition: err.h:52
Definition: pbuf.h:108
s8_t err_t
Definition: err.h:47
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
Definition: netif.h:182
#define NETIF_FLAG_IGMP
Definition: netif.h:97
#define PACK_STRUCT_FLD_S(x)
Definition: arch.h:84
#define PACK_STRUCT_BEGIN
Definition: arch.h:60
#define ERR_ARG
Definition: err.h:71
unsigned char u8_t
Definition: cc.h:38
#define PACK_STRUCT_END
Definition: arch.h:64
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:89
void * memp_malloc(memp_t type)
Definition: memp.c:303
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:113
#define ERR_MEM
Definition: err.h:53
unsigned short u16_t
Definition: cc.h:40
void * payload
Definition: pbuf.h:113