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 */