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 <[email protected]>
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 <[email protected]>
---
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 */