UbixOS  2.0
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 /*-------------------------------------------------------------
45 Note 1)
46 Although the rfc requires V1 AND V2 capability
47 we will only support v2 since now V1 is very old (August 1989)
48 V1 can be added if required
49 
50 a debug print and statistic have been implemented to
51 show this up.
52 -------------------------------------------------------------
53 -------------------------------------------------------------
54 Note 2)
55 A query for a specific group address (as opposed to ALLHOSTS)
56 has now been implemented as I am unsure if it is required
57 
58 a debug print and statistic have been implemented to
59 show this up.
60 -------------------------------------------------------------
61 -------------------------------------------------------------
62 Note 3)
63 The router alert rfc 2113 is implemented in outgoing packets
64 but not checked rigorously incoming
65 -------------------------------------------------------------
66 Steve 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 "net/opt.h"
84 
85 #if LWIP_IPV4 && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
86 
87 #include "net/igmp.h"
88 #include "net/debug.h"
89 #include "net/def.h"
90 #include "net/mem.h"
91 #include "net/ip.h"
92 #include "net/inet_chksum.h"
93 #include "net/netif.h"
94 #include "net/stats.h"
95 #include "net/prot/igmp.h"
96 
97 #include "string.h"
98 
99 static struct igmp_group *igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr);
100 static err_t igmp_remove_group(struct netif* netif, struct igmp_group *group);
101 static void igmp_timeout(struct netif *netif, struct igmp_group *group);
102 static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
103 static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
104 static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif);
105 static void igmp_send(struct netif *netif, struct igmp_group *group, u8_t type);
106 
107 static ip4_addr_t allsystems;
108 static ip4_addr_t allrouters;
109 
113 void
114 igmp_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 
127 err_t
128 igmp_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 
159 err_t
160 igmp_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(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 
191 void
192 igmp_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 
217 struct igmp_group *
218 igmp_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_cmp(&(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 
243 static struct igmp_group *
244 igmp_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_cmp(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_cmp(addr, &allsystems) == 0));
276  group->next = list_head->next;
277  list_head->next = group;
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 
294 static err_t
295 igmp_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 the global igmp_group_list */
308  if (tmp_group == NULL) {
309  err = ERR_ARG;
310  }
311 
312  return err;
313 }
314 
322 void
323 igmp_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(IGMP_DEBUG, &(ip4_current_header()->src));
341  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
342  ip4_addr_debug_print(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_cmp(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(IGMP_DEBUG, &igmp->igmp_group_address);
398  if (ip4_addr_cmp(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;
419  case IGMP_V2_MEMB_REPORT:
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 
448 err_t
449 igmp_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 
454  /* make sure it is multicast address */
455  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
456  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
457 
458  /* loop through netif's */
459  netif = netif_list;
460  while (netif != NULL) {
461  /* Should we join this interface ? */
462  if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) {
463  err = igmp_joingroup_netif(netif, groupaddr);
464  if (err != ERR_OK) {
465  /* Return an error even if some network interfaces are joined */
467  return err;
468  }
469  }
470  /* proceed to next network interface */
471  netif = netif->next;
472  }
473 
474  return err;
475 }
476 
485 err_t
486 igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
487 {
488  struct igmp_group *group;
489 
490  /* make sure it is multicast address */
491  LWIP_ERROR("igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
492  LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
493 
494  /* make sure it is an igmp-enabled netif */
495  LWIP_ERROR("igmp_joingroup_netif: attempt to join on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;);
496 
497  /* find group or create a new one if not found */
498  group = igmp_lookup_group(netif, groupaddr);
499 
500  if (group != NULL) {
501  /* This should create a new group, check the state to make sure */
502  if (group->group_state != IGMP_GROUP_NON_MEMBER) {
503  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
504  } else {
505  /* OK - it was new group */
506  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to new group: "));
507  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
508  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
509 
510  /* If first use of the group, allow the group at the MAC level */
511  if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
512  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: igmp_mac_filter(ADD "));
513  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
514  LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
515  netif->igmp_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER);
516  }
517 
518  IGMP_STATS_INC(igmp.tx_join);
519  igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
520 
521  igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
522 
523  /* Need to work out where this timer comes from */
524  group->group_state = IGMP_GROUP_DELAYING_MEMBER;
525  }
526  /* Increment group use */
527  group->use++;
528  /* Join on this interface */
529  return ERR_OK;
530  } else {
531  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: Not enough memory to join to group\n"));
532  return ERR_MEM;
533  }
534 }
535 
544 err_t
545 igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr)
546 {
547  err_t err = ERR_VAL; /* no matching interface */
548  struct netif *netif;
549 
550  /* make sure it is multicast address */
551  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
552  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
553 
554  /* loop through netif's */
555  netif = netif_list;
556  while (netif != NULL) {
557  /* Should we leave this interface ? */
558  if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) {
559  err_t res = igmp_leavegroup_netif(netif, groupaddr);
560  if (err != ERR_OK) {
561  /* Store this result if we have not yet gotten a success */
562  err = res;
563  }
564  }
565  /* proceed to next network interface */
566  netif = netif->next;
567  }
568 
569  return err;
570 }
571 
580 err_t
581 igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
582 {
583  struct igmp_group *group;
584 
585  /* make sure it is multicast address */
586  LWIP_ERROR("igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;);
587  LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
588 
589  /* make sure it is an igmp-enabled netif */
590  LWIP_ERROR("igmp_leavegroup_netif: attempt to leave on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;);
591 
592  /* find group */
593  group = igmp_lookfor_group(netif, groupaddr);
594 
595  if (group != NULL) {
596  /* Only send a leave if the flag is set according to the state diagram */
597  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: Leaving group: "));
598  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
599  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
600 
601  /* If there is no other use of the group */
602  if (group->use <= 1) {
603  /* Remove the group from the list */
604  igmp_remove_group(netif, group);
605 
606  /* If we are the last reporter for this group */
607  if (group->last_reporter_flag) {
608  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n"));
609  IGMP_STATS_INC(igmp.tx_leave);
610  igmp_send(netif, group, IGMP_LEAVE_GROUP);
611  }
612 
613  /* Disable the group at the MAC level */
614  if (netif->igmp_mac_filter != NULL) {
615  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL "));
616  ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
617  LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
618  netif->igmp_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
619  }
620 
621  /* Free group struct */
622  memp_free(MEMP_IGMP_GROUP, group);
623  } else {
624  /* Decrement group use */
625  group->use--;
626  }
627  return ERR_OK;
628  } else {
629  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: not member of group\n"));
630  return ERR_VAL;
631  }
632 }
633 
638 void
639 igmp_tmr(void)
640 {
641  struct netif *netif = netif_list;
642 
643  while (netif != NULL) {
644  struct igmp_group *group = netif_igmp_data(netif);
645 
646  while (group != NULL) {
647  if (group->timer > 0) {
648  group->timer--;
649  if (group->timer == 0) {
650  igmp_timeout(netif, group);
651  }
652  }
653  group = group->next;
654  }
655  netif = netif->next;
656  }
657 }
658 
665 static void
666 igmp_timeout(struct netif *netif, struct igmp_group *group)
667 {
668  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group
669  (unless it is the allsystems group) */
670  if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
671  (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) {
672  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
673  ip4_addr_debug_print(IGMP_DEBUG, &(group->group_address));
674  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)netif));
675 
676  group->group_state = IGMP_GROUP_IDLE_MEMBER;
677 
678  IGMP_STATS_INC(igmp.tx_report);
679  igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
680  }
681 }
682 
690 static void
691 igmp_start_timer(struct igmp_group *group, u8_t max_time)
692 {
693 #ifdef LWIP_RAND
694  group->timer = max_time > 2 ? (LWIP_RAND() % max_time) : 1;
695 #else /* LWIP_RAND */
696  /* ATTENTION: use this only if absolutely necessary! */
697  group->timer = max_time / 2;
698 #endif /* LWIP_RAND */
699 
700  if (group->timer == 0) {
701  group->timer = 1;
702  }
703 }
704 
711 static void
712 igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
713 {
714  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
715  ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
716  ((group->timer == 0) || (maxresp < group->timer)))) {
717  igmp_start_timer(group, maxresp);
718  group->group_state = IGMP_GROUP_DELAYING_MEMBER;
719  }
720 }
721 
722 
739 static err_t
740 igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif)
741 {
742  /* This is the "router alert" option */
743  u16_t ra[2];
744  ra[0] = PP_HTONS(ROUTER_ALERT);
745  ra[1] = 0x0000; /* Router shall examine packet */
746  IGMP_STATS_INC(igmp.xmit);
747  return ip4_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
748 }
749 
756 static void
757 igmp_send(struct netif *netif, struct igmp_group *group, u8_t type)
758 {
759  struct pbuf* p = NULL;
760  struct igmp_msg* igmp = NULL;
761  ip4_addr_t src = *IP4_ADDR_ANY4;
762  ip4_addr_t* dest = NULL;
763 
764  /* IP header + "router alert" option + IGMP header */
766 
767  if (p) {
768  igmp = (struct igmp_msg *)p->payload;
769  LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
770  (p->len >= sizeof(struct igmp_msg)));
771  ip4_addr_copy(src, *netif_ip4_addr(netif));
772 
773  if (type == IGMP_V2_MEMB_REPORT) {
774  dest = &(group->group_address);
775  ip4_addr_copy(igmp->igmp_group_address, group->group_address);
776  group->last_reporter_flag = 1; /* Remember we were the last to report */
777  } else {
778  if (type == IGMP_LEAVE_GROUP) {
779  dest = &allrouters;
780  ip4_addr_copy(igmp->igmp_group_address, group->group_address);
781  }
782  }
783 
784  if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
785  igmp->igmp_msgtype = type;
786  igmp->igmp_maxresp = 0;
787  igmp->igmp_checksum = 0;
788  igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
789 
790  igmp_ip_output_if(p, &src, dest, netif);
791  }
792 
793  pbuf_free(p);
794  } else {
795  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
796  IGMP_STATS_INC(igmp.memerr);
797  }
798 }
799 
800 #endif /* LWIP_IPV4 && LWIP_IGMP */
opt.h
IGMP_GROUP_NON_MEMBER
#define IGMP_GROUP_NON_MEMBER
Definition: igmp.h:64
pbuf::len
u16_t len
Definition: pbuf.h:159
def.h
NETIF_FLAG_IGMP
#define NETIF_FLAG_IGMP
Definition: netif.h:106
LWIP_ASSERT
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
ROUTER_ALERT
#define ROUTER_ALERT
Definition: igmp.h:52
u16_t
uint16_t u16_t
Definition: arch.h:124
string.h
igmp.h
IGMP_LEAVE_GROUP
#define IGMP_LEAVE_GROUP
Definition: igmp.h:61
PBUF_TRANSPORT
Definition: pbuf.h:76
pbuf_free
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:715
igmp_msg
Definition: igmp.h:75
memp_malloc
void * memp_malloc(memp_t type)
Definition: memp.c:385
IGMP_STATS_INC
#define IGMP_STATS_INC(x)
Definition: stats.h:352
IGMP_V2_MEMB_REPORT
#define IGMP_V2_MEMB_REPORT
Definition: igmp.h:60
netif::flags
u8_t flags
Definition: netif.h:313
NETIF_DEL_MAC_FILTER
Definition: netif.h:153
memp_free
void memp_free(memp_t type, void *mem)
Definition: memp.c:469
NETIF_ADD_MAC_FILTER
Definition: netif.h:155
IGMP_TTL
#define IGMP_TTL
Definition: igmp.h:50
stats.h
ERR_MEM
Definition: err.h:65
netif.h
LWIP_ERROR
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:135
pbuf_alloc
struct pbuf * pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)
Definition: pbuf.c:248
u8_t
uint8_t u8_t
Definition: arch.h:122
netif
Definition: netif.h:233
IGMP_GROUP_IDLE_MEMBER
#define IGMP_GROUP_IDLE_MEMBER
Definition: igmp.h:66
ERR_ARG
Definition: err.h:96
IGMP_DEBUG
#define IGMP_DEBUG
Definition: lwipopts.h:445
igmp.h
ROUTER_ALERTLEN
#define ROUTER_ALERTLEN
Definition: igmp.h:53
netif::next
struct netif * next
Definition: netif.h:235
PBUF_RAM
Definition: pbuf.h:108
netif_list
struct netif * netif_list
Definition: netif.c:104
ERR_OK
Definition: err.h:63
err_t
s8_t err_t
Definition: err.h:57
ip.h
IGMP_MINLEN
#define IGMP_MINLEN
Definition: igmp.h:51
IGMP_GROUP_DELAYING_MEMBER
#define IGMP_GROUP_DELAYING_MEMBER
Definition: igmp.h:65
IP_PROTO_IGMP
#define IP_PROTO_IGMP
Definition: ip.h:43
inet_chksum
u16_t inet_chksum(const void *dataptr, u16_t len)
Definition: inet_chksum.c:555
mem.h
ERR_VAL
Definition: err.h:75
pbuf
Definition: pbuf.h:142
LWIP_DEBUGF
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:164
inet_chksum.h
debug.h
IGMP_MEMB_QUERY
#define IGMP_MEMB_QUERY
Definition: igmp.h:58
pbuf::payload
void * payload
Definition: pbuf.h:147
PP_HTONS
#define PP_HTONS(x)
Definition: def.h:79
NULL
#define NULL
Definition: fat_string.h:17