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 <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2023-11-01 19:57:27 +08:00 committed by Xiang Xiao
parent 7c322c250a
commit 43ecf36d78
8 changed files with 96 additions and 5 deletions

View File

@ -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 */
};
/****************************************************************************

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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