From 216334dac2637a9aa4353186a914e0fc0c5f19a5 Mon Sep 17 00:00:00 2001
From: Daniel Elstner <daniel.elstner@kdab.com>
Date: Mon, 19 Sep 2016 10:01:47 +0200
Subject: [PATCH] Bug #49125 addendum: Remove group from list before callback

When leaving a multicast group, remove the group from the list
before invoking the MAC filter callback. This avoids the need
for the callee to skip over the group that is about to be deleted.
---
 src/core/ipv4/igmp.c | 19 ++++++++++---------
 src/core/ipv6/mld6.c | 15 ++++++++-------
 2 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c
index ef3b8ab..a748b5b 100644
--- a/src/core/ipv4/igmp.c
+++ b/src/core/ipv4/igmp.c
@@ -284,7 +284,7 @@ igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
 }
 
 /**
- * Remove a group in the global igmp_group_list
+ * Remove a group in the global igmp_group_list, but don't free it yet
  *
  * @param group the group to remove from the global igmp_group_list
  * @return ERR_OK if group was removed from the list, an err_t otherwise
@@ -311,8 +311,6 @@ igmp_remove_group(struct igmp_group *group)
       err = ERR_ARG;
     }
   }
-  /* free group */
-  memp_free(MEMP_IGMP_GROUP, group);
 
   return err;
 }
@@ -601,6 +599,9 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
 
     /* If there is no other use of the group */
     if (group->use <= 1) {
+      /* Remove the group from the list */
+      igmp_remove_group(group);
+
       /* If we are the last reporter for this group */
       if (group->last_reporter_flag) {
         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n"));
@@ -608,6 +609,10 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
         igmp_send(group, IGMP_LEAVE_GROUP);
       }
 
+      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: remove group: "));
+      ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
+      LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
       /* Disable the group at the MAC level */
       if (netif->igmp_mac_filter != NULL) {
         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL "));
@@ -616,12 +621,8 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
         netif->igmp_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
       }
 
-      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: remove group: "));
-      ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
-      LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
-
-      /* Free the group */
-      igmp_remove_group(group);
+      /* Free group struct */
+      memp_free(MEMP_IGMP_GROUP, group);
     } else {
       /* Decrement group use */
       group->use--;
diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c
index 09fe2a2..0f92548 100644
--- a/src/core/ipv6/mld6.c
+++ b/src/core/ipv6/mld6.c
@@ -82,7 +82,7 @@ struct mld_group* mld_group_list;
 
 /* Forward declarations. */
 static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr);
-static err_t mld6_free_group(struct mld_group *group);
+static err_t mld6_remove_group(struct mld_group *group);
 static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
 static void mld6_send(struct mld_group *group, u8_t type);
 
@@ -200,13 +200,13 @@ mld6_new_group(struct netif *ifp, const ip6_addr_t *addr)
 }
 
 /**
- * Remove a group in the mld_group_list and free
+ * Remove a group from the mld_group_list, but do not free it yet
  *
  * @param group the group to remove
  * @return ERR_OK if group was removed from the list, an err_t otherwise
  */
 static err_t
-mld6_free_group(struct mld_group *group)
+mld6_remove_group(struct mld_group *group)
 {
   err_t err = ERR_OK;
 
@@ -227,8 +227,6 @@ mld6_free_group(struct mld_group *group)
       err = ERR_ARG;
     }
   }
-  /* free group */
-  memp_free(MEMP_MLD6_GROUP, group);
 
   return err;
 }
@@ -440,6 +438,9 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
   if (group != NULL) {
     /* Leave if there is no other use of the group */
     if (group->use <= 1) {
+      /* Remove the group from the list */
+      mld6_remove_group(group);
+
       /* If we are the last reporter for this group */
       if (group->last_reporter_flag) {
         MLD6_STATS_INC(mld6.tx_leave);
@@ -451,8 +452,8 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
         netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
       }
 
-      /* Free the group */
-      mld6_free_group(group);
+      /* free group struct */
+      memp_free(MEMP_MLD6_GROUP, group);
     } else {
       /* Decrement group use */
       group->use--;
-- 
2.7.4

