This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 43ecf36d78 udp: modify ipv4 multicast to allow different conn to join 
simultaneously
43ecf36d78 is described below

commit 43ecf36d787d681e1c194277c09f32c92f1d58be
Author: zhanghongyu <zhanghon...@xiaomi.com>
AuthorDate: Wed Nov 1 19:57:27 2023 +0800

    udp: modify ipv4 multicast to allow different conn to join simultaneously
    
    add ref count for ipv4 multicast and leave the multicast group when close
    behavior alignment with linux.
    
    Signed-off-by: zhanghongyu <zhanghon...@xiaomi.com>
---
 net/igmp/igmp.h            |  1 +
 net/igmp/igmp_join.c       |  6 +++---
 net/igmp/igmp_leave.c      | 12 ++++++++++++
 net/inet/ipv4_setsockopt.c | 23 +++++++++++++++++++++--
 net/netdev/netdev_ioctl.c  |  3 +++
 net/udp/udp.h              | 22 ++++++++++++++++++++++
 net/udp/udp_close.c        |  2 ++
 net/udp/udp_conn.c         | 32 ++++++++++++++++++++++++++++++++
 8 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/net/igmp/igmp.h b/net/igmp/igmp.h
index 1f10717268..7fac4c9d36 100644
--- a/net/igmp/igmp.h
+++ b/net/igmp/igmp.h
@@ -117,6 +117,7 @@ struct igmp_group_s
   uint8_t              ifindex; /* Interface index */
   uint8_t              flags;   /* See IGMP_ flags definitions */
   uint8_t              msgid;   /* Pending message ID (if non-zero) */
+  uint8_t              njoins;  /* Number of joins from this host */
 };
 
 /****************************************************************************
diff --git a/net/igmp/igmp_join.c b/net/igmp/igmp_join.c
index c28b10112a..32d1e840d5 100644
--- a/net/igmp/igmp_join.c
+++ b/net/igmp/igmp_join.c
@@ -160,12 +160,12 @@ int igmp_joingroup(struct net_driver_s *dev,
       /* Add the group (MAC) address to the ether drivers MAC filter list */
 
       igmp_addmcastmac(dev, (FAR in_addr_t *)&grpaddr->s_addr);
-      return OK;
     }
 
-  /* Return EEXIST if the address is already a member of the group */
+  DEBUGASSERT(group->njoins < UINT8_MAX);
+  group->njoins++;
 
-  return -EEXIST;
+  return OK;
 }
 
 #endif /* CONFIG_NET_IGMP */
diff --git a/net/igmp/igmp_leave.c b/net/igmp/igmp_leave.c
index e026340832..62c57edbcb 100644
--- a/net/igmp/igmp_leave.c
+++ b/net/igmp/igmp_leave.c
@@ -138,6 +138,18 @@ int igmp_leavegroup(struct net_driver_s *dev,
   ninfo("Leaving group: %p\n", group);
   if (group)
     {
+      DEBUGASSERT(group->njoins > 0);
+      group->njoins--;
+
+      /* Take no further actions if there are other members of this group
+       * on this host.
+       */
+
+      if (group->njoins > 0)
+        {
+          return OK;
+        }
+
       /* Cancel the timer and discard any queued Membership Reports.
        * Canceling the timer will prevent any new Membership Reports from
        * being sent; clearing the flags will discard any pending Membership
diff --git a/net/inet/ipv4_setsockopt.c b/net/inet/ipv4_setsockopt.c
index 7553cdf134..741e6168cd 100644
--- a/net/inet/ipv4_setsockopt.c
+++ b/net/inet/ipv4_setsockopt.c
@@ -126,6 +126,7 @@ int ipv4_setsockopt(FAR struct socket *psock, int option,
         }
         break;
 
+#ifdef NET_UDP_HAVE_STACK
       case IP_ADD_MEMBERSHIP:         /* Join a multicast group */
       case IP_DROP_MEMBERSHIP:        /* Leave a multicast group */
         {
@@ -142,6 +143,8 @@ int ipv4_setsockopt(FAR struct socket *psock, int option,
             }
           else
             {
+              FAR struct udp_conn_s *conn = psock->s_conn;
+
               /* Use the default network device is imr_interface is
                * INADDRY_ANY.
                */
@@ -166,17 +169,33 @@ int ipv4_setsockopt(FAR struct socket *psock, int option,
                 }
               else if (option == IP_ADD_MEMBERSHIP)
                 {
-                  ret = igmp_joingroup(dev, &mrec->imr_multiaddr);
+                  if (conn->mreq.imr_multiaddr.s_addr != 0)
+                    {
+                      ret = -EADDRINUSE;
+                    }
+                  else
+                    {
+                      ret = igmp_joingroup(dev, &mrec->imr_multiaddr);
+                      if (ret == OK)
+                        {
+                          conn->mreq.imr_multiaddr = mrec->imr_multiaddr;
+                          conn->mreq.imr_ifindex   = dev->d_ifindex;
+                        }
+                    }
                 }
               else
                 {
                   ret = igmp_leavegroup(dev, &mrec->imr_multiaddr);
+                  if (ret == OK)
+                    {
+                      conn->mreq.imr_multiaddr.s_addr = 0;
+                      conn->mreq.imr_ifindex          = 0;
+                    }
                 }
             }
         }
         break;
 
-#ifdef NET_UDP_HAVE_STACK
       case IP_MULTICAST_TTL:          /* Set/read the time-to-live value of
                                        * outgoing multicast packets */
 #endif
diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c
index a7401460fa..d1eea0c40e 100644
--- a/net/netdev/netdev_ioctl.c
+++ b/net/netdev/netdev_ioctl.c
@@ -1207,6 +1207,8 @@ static int netdev_imsf_ioctl(FAR struct socket *psock, 
int cmd,
 
   ninfo("cmd: %d\n", cmd);
 
+  net_lock();
+
   /* Execute the command */
 
   switch (cmd)
@@ -1235,6 +1237,7 @@ static int netdev_imsf_ioctl(FAR struct socket *psock, 
int cmd,
         break;
     }
 
+  net_unlock();
   return ret;
 }
 #endif
diff --git a/net/udp/udp.h b/net/udp/udp.h
index 354aefb8ea..3832ec5a0a 100644
--- a/net/udp/udp.h
+++ b/net/udp/udp.h
@@ -310,6 +310,28 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct 
sockaddr *addr);
 int udp_connect(FAR struct udp_conn_s *conn,
                 FAR const struct sockaddr *addr);
 
+#if defined(CONFIG_NET_IGMP)
+/****************************************************************************
+ * Name: udp_leavegroup
+ *
+ * Description:
+ *   This function leaves the multicast group to which the conn belongs.
+ *
+ * Input Parameters:
+ *   conn - A reference to UDP connection structure.  A value of NULL will
+ *          disconnect from any previously connected address.
+ *
+ * Assumptions:
+ *   This function is called (indirectly) from user code.  Interrupts may
+ *   be enabled.
+ *
+ ****************************************************************************/
+
+void udp_leavegroup(FAR struct udp_conn_s *conn);
+#else
+#define udp_leavegroup(c)
+#endif
+
 /****************************************************************************
  * Name: udp_close
  *
diff --git a/net/udp/udp_close.c b/net/udp/udp_close.c
index 0c2368a9ab..42ade8f897 100644
--- a/net/udp/udp_close.c
+++ b/net/udp/udp_close.c
@@ -103,6 +103,8 @@ int udp_close(FAR struct socket *psock)
       nerr("ERROR: udp_txdrain() failed: %d\n", ret);
     }
 
+  udp_leavegroup(conn);
+
 #ifdef CONFIG_NET_UDP_WRITE_BUFFERS
   /* Free any semi-permanent write buffer callback in place. */
 
diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c
index 6092584c33..2bb4f64b22 100644
--- a/net/udp/udp_conn.c
+++ b/net/udp/udp_conn.c
@@ -68,6 +68,7 @@
 #include "nat/nat.h"
 #include "netdev/netdev.h"
 #include "socket/socket.h"
+#include "igmp/igmp.h"
 #include "udp/udp.h"
 
 /****************************************************************************
@@ -1080,4 +1081,35 @@ int udp_connect(FAR struct udp_conn_s *conn, FAR const 
struct sockaddr *addr)
   return OK;
 }
 
+#if defined(CONFIG_NET_IGMP)
+/****************************************************************************
+ * Name: udp_leavegroup
+ *
+ * Description:
+ *   This function leaves the multicast group to which the conn belongs.
+ *
+ * Input Parameters:
+ *   conn - A reference to UDP connection structure.  A value of NULL will
+ *          disconnect from any previously connected address.
+ *
+ * Assumptions:
+ *   This function is called (indirectly) from user code.  Interrupts may
+ *   be enabled.
+ *
+ ****************************************************************************/
+
+void udp_leavegroup(FAR struct udp_conn_s *conn)
+{
+  if (conn->mreq.imr_multiaddr.s_addr != 0)
+    {
+      FAR struct net_driver_s *dev;
+
+      if ((dev = netdev_findbyindex(conn->mreq.imr_ifindex)) != NULL)
+        {
+          igmp_leavegroup(dev, &conn->mreq.imr_multiaddr);
+        }
+    }
+}
+#endif
+
 #endif /* CONFIG_NET && CONFIG_NET_UDP */

Reply via email to