From 9b98c8f97e88ddc6db3e3e14ad5415ff780d381a Mon Sep 17 00:00:00 2001
From: wanfeng <wanfeng@kylinos.cn>
Date: Thu, 27 Jun 2024 09:40:41 +0800
Subject: [PATCH] Improve the size of multicast specifications, with a maximum
 of 16 groups and 32 members per group

---
 src/core/ipv4/igmp.c     |  11 ++-
 src/core/ipv6/mld6.c     |   6 +-
 src/core/mcast.c         | 165 +++++++++++++++++++++++++--------------
 src/include/lwip/mcast.h |   8 +-
 src/include/lwipopts.h   |   1 +
 5 files changed, 128 insertions(+), 63 deletions(-)

diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c
index 2567a41..af298be 100644
--- a/src/core/ipv4/igmp.c
+++ b/src/core/ipv4/igmp.c
@@ -449,8 +449,8 @@ igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
               LWIP_ASSERT("igmp_v3_query packet source address array not aligned!", !((mem_ptr_t)src_buf & 0x3));
               ip4_addr_t igmp_v3_group_address;
               memcpy(&igmp_v3_group_address, &igmp_v3->igmp_v3_group_address, sizeof(igmp_v3_group_address));
-              if (mcast_ip4_filter_interest(inp, (const ip4_addr_t *)&igmp_v3_group_address, src_buf, src_cnt)) {  
-	      /* We interest! */
+              if (mcast_ip4_filter_interest(inp, (const ip4_addr_t *)&igmp_v3_group_address, src_buf, src_cnt)) {
+                /* We interest! */
                 igmp_v3_delaying_member(group, igmp_v3->igmp_v3_maxresp);
               }
 
@@ -463,6 +463,7 @@ igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
             }
           }
         }
+        break;
       }
 #endif /* LWIP_IGMP_V3 */
       /* IGMP_MEMB_QUERY to the "all systems" address ? */
@@ -617,13 +618,14 @@ igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
       }
 
       IGMP_STATS_INC(igmp.tx_join);
+#if !LWIP_IGMP_V3
       igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
 
       igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
 
       /* Need to work out where this timer comes from */
       group->group_state = IGMP_GROUP_DELAYING_MEMBER;
-
+#endif
 
 #if LWIP_IGMP_V3
       igmp_v3_send(netif, group, IGMP_V3_MEMB_REPORT);
@@ -715,16 +717,19 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
       /* Remove the group from the list */
       igmp_remove_group(netif, group);
 
+#if !LWIP_IGMP_V3
       /* 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"));
         IGMP_STATS_INC(igmp.tx_leave);
         igmp_send(netif, group, IGMP_LEAVE_GROUP);
       }
+#endif
 
 #if LWIP_IGMP_V3
       /* If we are the last reporter for this group */
       if (group->v3_last_reporter_flag) {
+        IGMP_STATS_INC(igmp.tx_leave);
         igmp_v3_send(netif, group, IGMP_LEAVE_GROUP);
       }
 #endif /* LWIP_IGMP_V3 */
diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c
index 29c45bc..3aecb35 100644
--- a/src/core/ipv6/mld6.c
+++ b/src/core/ipv6/mld6.c
@@ -313,7 +313,7 @@ mld6_input(struct pbuf *p, struct netif *inp)
           }
         }
       }
-
+      break;
     }
 #endif
     /* Is it a general query? */
@@ -451,8 +451,10 @@ mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
 
     /* Report our membership. */
     MLD6_STATS_INC(mld6.tx_report);
+#if !LWIP_IPV6_MLD_V2
     mld6_send(netif, group, ICMP6_TYPE_MLR);
     mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+#endif
 #if LWIP_IPV6_MLD_V2
     mld6_v2_send(netif, group, ICMP6_TYPE_MLR2);
     mld6_v2_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
@@ -536,10 +538,12 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
       mld6_remove_group(netif, group);
 
       /* If we are the last reporter for this group */
+#if !LWIP_IPV6_MLD_V2
       if (group->last_reporter_flag) {
         MLD6_STATS_INC(mld6.tx_leave);
         mld6_send(netif, group, ICMP6_TYPE_MLD);
       }
+#endif
 #if LWIP_IPV6_MLD_V2
       /* If we are the last reporter for this group */
       if (group->v2_last_reporter_flag) {
diff --git a/src/core/mcast.c b/src/core/mcast.c
index fa46f10..0df6373 100644
--- a/src/core/mcast.c
+++ b/src/core/mcast.c
@@ -449,6 +449,81 @@ mcast_ip6_filter_interest(struct netif *netif, const ip6_addr_t *multi_addr, con
 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
 
 #if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD)
+
+#if (LWIP_IPV4 && LWIP_IGMP) 
+err_t
+mcast_mc_new_src(struct ip4_mc *mc, const ip_addr_t *src_addr)
+{
+  struct igmp_src *src;
+  if (mc->num_src >= LWIP_MCAST_SRC_TBL_SIZE) {
+    return ERR_MEM;
+  }
+  src = (struct igmp_src *)mem_malloc(sizeof(struct igmp_src));
+  if (src == NULL) {
+    return ERR_MEM; /* no memory */
+  }
+  ip4_addr_set(&src->src_addr, ip_2_ip4(src_addr));
+  src->next = mc->src;
+  mc->src = src;
+  mc->num_src++;
+  return ERR_OK;
+}
+
+err_t
+mcast_mc_free_src(struct ip4_mc *mc, struct igmp_src *src, struct igmp_src *src_prev)
+{
+  if (src == NULL) {
+    return ERR_OK;
+  }
+  if (src_prev) {
+    src_prev->next = src->next;
+  } else {
+    mc->src = src->next;
+  }
+  mem_free(src);
+  if (mc->num_src > 0)
+    mc->num_src--;
+  return ERR_OK;
+}
+#endif
+
+#if (LWIP_IPV6 && LWIP_IPV6_MLD)
+err_t
+mcast_mc_new_ipv6_src(struct ip6_mc *mc, const ip_addr_t *src_addr)
+{
+  struct mld6_src *src;
+  if (mc->num_src >= LWIP_MCAST_SRC_TBL_SIZE) {
+    return ERR_MEM;
+  }
+  src = (struct mld6_src *)mem_malloc(sizeof(struct mld6_src));
+  if (src == NULL) {
+    return ERR_MEM; /* no memory */
+  }
+  ip6_addr_set(&src->src_addr, ip_2_ip6(src_addr));
+  src->next = mc->src;
+  mc->src = src;
+  mc->num_src++;
+  return ERR_OK;
+}
+
+err_t
+mcast_mc_free_ipv6_src(struct ip6_mc *mc, struct mld6_src *src, struct mld6_src *src_prev)
+{
+  if (src == NULL) {
+    return ERR_OK;
+  }
+  if (src_prev) {
+    src_prev->next = src->next;
+  } else {
+    mc->src = src->next;
+  }
+  mem_free(src);
+  if (mc->num_src > 0)
+    mc->num_src--;
+  return ERR_OK;
+}
+#endif
+
 /** Join a multicast group (Can with a source specified)
  *
  * @param ipmc multicast filter control block
@@ -480,6 +555,7 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
   if (IP_IS_V4(multi_addr)) {
     struct ip4_mc *mc;
     struct igmp_src *src;
+    err_t err;
 
     mc = mcast_ip4_mc_find(ipmc, netif, ip_2_ip4(multi_addr), NULL);
     if (mc) {
@@ -492,13 +568,9 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
           return ERR_ALREADY; /* already in source list */
         }
 
-        src = (struct igmp_src *)mem_malloc(sizeof(struct igmp_src));
-        if (src == NULL) {
+        if (mcast_mc_new_src(mc, src_addr) != ERR_OK) {
           return ERR_MEM; /* no memory */
         }
-        ip4_addr_set(&src->src_addr, ip_2_ip4(src_addr));
-        src->next = mc->src;
-        mc->src = src;
         mc->fmode = MCAST_INCLUDE; /* change to include mode */
         IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */
         return ERR_OK;
@@ -511,20 +583,19 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
       igmp_leavegroup_netif(netif, ip_2_ip4(multi_addr));
       return ERR_MEM; /* no memory */
     }
+    mc->num_src = 0;
+    mc->src = NULL;
+    mc->if_idx = netif_get_index(netif);
     ip4_addr_set(&mc->if_addr, netif_ip4_addr(netif));
     ip4_addr_set(&mc->multi_addr, ip_2_ip4(multi_addr));
 
     if (src_addr) { /* have a source specified */
       mc->fmode = MCAST_INCLUDE;
-      src = (struct igmp_src *)mem_malloc(sizeof(struct igmp_src));
-      if (src == NULL) {
+      if (mcast_mc_new_src(mc, src_addr) != ERR_OK) {
+        igmp_leavegroup_netif(netif, ip_2_ip4(multi_addr));
         mem_free(mc);
         return ERR_MEM; /* no memory */
       }
-      ip4_addr_set(&src->src_addr, ip_2_ip4(src_addr));
-      src->next = NULL;
-      mc->src = src;
-
     } else {
       mc->fmode = MCAST_EXCLUDE; /* no source specified */
       mc->src = NULL;
@@ -532,13 +603,19 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
 
     mc->next = ipmc->mc4;
     ipmc->mc4 = mc;
-    igmp_joingroup_netif(netif, ip_2_ip4(multi_addr));
+    err = igmp_joingroup_netif(netif, ip_2_ip4(multi_addr));
+    if (err != ERR_OK) {
+      ipmc->mc4 = mc->next;
+      mem_free(mc);
+    }
+    return err;
   } else
 #endif /* LWIP_IPV4 && LWIP_IGMP */
   {
 #if LWIP_IPV6 && LWIP_IPV6_MLD
     struct ip6_mc *mc;
     struct mld6_src *src;
+    err_t err;
 
     mc = mcast_ip6_mc_find(ipmc, netif, ip_2_ip6(multi_addr), NULL);
     if (mc) {
@@ -551,13 +628,9 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
           return ERR_ALREADY; /* already in source list */
         }
 
-        src = (struct mld6_src *)mem_malloc(sizeof(struct mld6_src));
-        if (src == NULL) {
+        if (mcast_mc_new_ipv6_src(mc, src_addr) != ERR_OK) {
           return ERR_MEM; /* no memory */
         }
-        ip6_addr_set(&src->src_addr, ip_2_ip6(src_addr));
-        src->next = mc->src;
-        mc->src = src;
         mc->fmode = MCAST_INCLUDE; /* change to include mode */
         IP6_MC_TRIGGER_CALL(netif, ip_2_ip6(multi_addr)); /* trigger a report */
         return ERR_OK;
@@ -570,21 +643,18 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
       mld6_leavegroup_netif(netif, ip_2_ip6(multi_addr));
       return ERR_MEM; /* no memory */
     }
+    mc->num_src = 0;
+    mc->src = NULL;
     mc->if_idx = netif_get_index(netif);
     ip6_addr_set(&mc->multi_addr, ip_2_ip6(multi_addr));
 
     if (src_addr) {
       mc->fmode = MCAST_INCLUDE;
-      src = (struct mld6_src *)mem_malloc(sizeof(struct mld6_src));
-      if (src == NULL) {
+      if (mcast_mc_new_ipv6_src(mc, src_addr) != ERR_OK) {
         mld6_leavegroup_netif(netif, ip_2_ip6(multi_addr));
         mem_free(mc);
         return ERR_MEM; /* no memory */
       }
-      ip6_addr_set(&src->src_addr, ip_2_ip6(src_addr));
-      src->next = NULL;
-      mc->src = src;
-
     } else {
       mc->fmode = MCAST_EXCLUDE; /* no source specified */
       mc->src = NULL;
@@ -592,7 +662,12 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
 
     mc->next = ipmc->mc6;
     ipmc->mc6 = mc;
-    mld6_joingroup_netif(netif, ip_2_ip6(multi_addr));
+    err = mld6_joingroup_netif(netif, ip_2_ip6(multi_addr));
+    if (err != ERR_OK) {
+      ipmc->mc6 = mc->next;
+      mem_free(mc);
+    }
+    return err;
 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
   }
   return ERR_OK;
@@ -673,12 +748,7 @@ mcast_leave_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
 
       src = mcast_ip4_mc_src_find(mc, ip_2_ip4(src_addr), &src_prev);
       if (src) {
-        if (src_prev) {
-          src_prev->next = src->next;
-        } else {
-          mc->src = src->next;
-        }
-        mem_free(src);
+        mcast_mc_free_src(mc, src, src_prev);
       } else {
         return ERR_VAL;
       }
@@ -688,6 +758,7 @@ mcast_leave_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
       }
     } else { /* we want drop this group */
       mcast_ip4_mc_src_remove(mc->src);
+      mc->num_src = 0;
     }
 
     igmp_leavegroup_netif(netif, ip_2_ip4(multi_addr));
@@ -718,12 +789,7 @@ mcast_leave_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
 
       src = mcast_ip6_mc_src_find(mc, ip_2_ip6(src_addr), &src_prev);
       if (src) {
-        if (src_prev) {
-          src_prev->next = src->next;
-        } else {
-          mc->src = src->next;
-        }
-        mem_free(src);
+        mcast_mc_free_ipv6_src(mc, src, src_prev);
       } else {
         return ERR_VAL;
       }
@@ -733,6 +799,7 @@ mcast_leave_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
       }
     } else { /* we want drop this group */
       mcast_ip6_mc_src_remove(mc->src);
+      mc->num_src = 0;
     }
 
     mld6_leavegroup_netif(netif, ip_2_ip6(multi_addr));
@@ -818,13 +885,9 @@ mcast_block_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
 
     src = mcast_ip4_mc_src_find(mc, ip_2_ip4(blk_addr), NULL);
     if (src == NULL) {
-      src = (struct igmp_src *)mem_malloc(sizeof(struct igmp_src));
-      if (src == NULL) {
+      if (mcast_mc_new_src(mc, blk_addr) != ERR_OK) {
         return ERR_MEM;
       }
-      ip4_addr_set(&src->src_addr, ip_2_ip4(blk_addr));
-      src->next = mc->src;
-      mc->src = src;
       IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */
     }
   } else
@@ -844,13 +907,9 @@ mcast_block_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
 
     src = mcast_ip6_mc_src_find(mc, ip_2_ip6(blk_addr), NULL);
     if (src == NULL) {
-      src = (struct mld6_src *)mem_malloc(sizeof(struct mld6_src));
-      if (src == NULL) {
+      if (mcast_mc_new_ipv6_src(mc, blk_addr) != ERR_OK) {
         return ERR_MEM;
       }
-      ip6_addr_set(&src->src_addr, ip_2_ip6(blk_addr));
-      src->next = mc->src;
-      mc->src = src;
       IP6_MC_TRIGGER_CALL(netif, ip_2_ip6(multi_addr)); /* trigger a report */
     }
 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
@@ -932,12 +991,7 @@ mcast_unblock_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mu
     if (src == NULL) {
       return ERR_VAL;
     }
-    if (src_prev) {
-      src_prev->next = src->next;
-    } else {
-      mc->src = src->next;
-    }
-    mem_free(src);
+    mcast_mc_free_src(mc, src, src_prev);
     IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */
   } else
 #endif /* LWIP_IPV4 && LWIP_IGMP */
@@ -959,12 +1013,7 @@ mcast_unblock_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mu
     if (src == NULL) {
       return ERR_VAL;
     }
-    if (src_prev) {
-      src_prev->next = src->next;
-    } else {
-      mc->src = src->next;
-    }
-    mem_free(src);
+    mcast_mc_free_ipv6_src(mc, src, src_prev);
     IP6_MC_TRIGGER_CALL(netif, ip_2_ip6(multi_addr)); /* trigger a report */
 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
   }
diff --git a/src/include/lwip/mcast.h b/src/include/lwip/mcast.h
index 16a27ae..6067a3c 100644
--- a/src/include/lwip/mcast.h
+++ b/src/include/lwip/mcast.h
@@ -4,7 +4,7 @@
  */
 
 /*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification,
@@ -56,12 +56,16 @@
 /** the IPv4 multicast filter */
 struct ip4_mc {
   struct ip4_mc *next;
+  /** the interface index */
+  u8_t if_idx;
   /** the interface address */
   ip4_addr_t if_addr;
   /** the group address */
   ip4_addr_t multi_addr;
   /** the source address list filter mode 0: EXCLUDE 1: INCLUDE */
   u8_t fmode;
+  /** the num of source address**/
+  u8_t num_src;
   /** the source address list */
   struct igmp_src *src;
 };
@@ -84,6 +88,8 @@ struct ip6_mc {
   ip6_addr_t multi_addr;
   /** the source address list filter mode 0: EXCLUDE 1: INCLUDE */
   u8_t fmode;
+  /** the num of source address**/
+  u8_t num_src;
   /** the source address list */
   struct mld6_src *src;
 };
diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h
index cb3154a..44dcddf 100644
--- a/src/include/lwipopts.h
+++ b/src/include/lwipopts.h
@@ -194,6 +194,7 @@
 
 #define MEMP_NUM_UDP_PCB (GAZELLE_MAX_CLIENTS + GAZELLE_RESERVED_CLIENTS)
 #define MEMP_NUM_IGMP_GROUP 16
+#define MEMP_NUM_MLD6_GROUP 16
 
 #define DEFAULT_UDP_RECVMBOX_SIZE 4096
 
-- 
2.25.1

