From 408320f2ba90555d1e8754f6c9836d512fdc9d70 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Wed, 27 Mar 2024 11:26:14 +0800 Subject: [PATCH] net/udp: Support deliver multicast packets back to local apps Signed-off-by: Zhe Weng --- net/inet/ipv4_setsockopt.c | 10 ++--- net/inet/ipv6_setsockopt.c | 10 +++-- net/udp/udp_send.c | 88 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/net/inet/ipv4_setsockopt.c b/net/inet/ipv4_setsockopt.c index 741e6168cd..d5b932994e 100644 --- a/net/inet/ipv4_setsockopt.c +++ b/net/inet/ipv4_setsockopt.c @@ -305,10 +305,6 @@ int ipv4_setsockopt(FAR struct socket *psock, int option, /* The following IPv4 socket options are defined, but not implemented */ - case IP_MULTICAST_LOOP: /* Set/read boolean that determines - * whether sent multicast packets - * should be looped back to local - * sockets. */ case IP_UNBLOCK_SOURCE: /* Unblock previously blocked multicast * source */ case IP_BLOCK_SOURCE: /* Stop receiving multicast data from @@ -327,8 +323,12 @@ int ipv4_setsockopt(FAR struct socket *psock, int option, nwarn("WARNING: Unimplemented IPv4 option: %d\n", option); ret = -ENOSYS; break; -#endif /* CONFIG_NET_IGMP */ + case IP_MULTICAST_LOOP: /* Set/read boolean that determines + * whether sent multicast packets + * should be looped back to local + * sockets. */ +#endif /* CONFIG_NET_IGMP */ case IP_PKTINFO: { FAR struct socket_conn_s *conn; diff --git a/net/inet/ipv6_setsockopt.c b/net/inet/ipv6_setsockopt.c index 2fc08de040..f0a0e2e480 100644 --- a/net/inet/ipv6_setsockopt.c +++ b/net/inet/ipv6_setsockopt.c @@ -137,13 +137,11 @@ int ipv6_setsockopt(FAR struct socket *psock, int option, ret = OK; break; } -#endif +#endif /* NET_UDP_HAVE_STACK */ +#endif /* CONFIG_NET_MLD */ /* The following IPv6 socket options are defined, but not implemented */ - case IPV6_MULTICAST_LOOP: /* Multicast packets are delivered back to - * the local application */ -#endif case IPV6_V6ONLY: /* Restrict AF_INET6 socket to IPv6 * communications only */ nwarn("WARNING: Unimplemented IPv6 option: %d\n", option); @@ -160,6 +158,10 @@ int ipv6_setsockopt(FAR struct socket *psock, int option, } break; +#ifdef CONFIG_NET_MLD + case IPV6_MULTICAST_LOOP: /* Multicast packets are delivered back to + * the local application */ +#endif case IPV6_RECVPKTINFO: case IPV6_RECVHOPLIMIT: { diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c index dc5bc8c077..27c90b92f9 100644 --- a/net/udp/udp_send.c +++ b/net/udp/udp_send.c @@ -58,9 +58,67 @@ #include "devif/devif.h" #include "inet/inet.h" +#include "socket/socket.h" #include "utils/utils.h" #include "udp/udp.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: udp_send_loopback + * + * Description: + * Send a copy of the UDP packet to ourself. + * + * Input Parameters: + * dev - The device driver structure to use in the send operation + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_NET_SOCKOPTS) && \ + (defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_MLD)) +static void udp_send_loopback(FAR struct net_driver_s *dev) +{ + FAR struct iob_s *iob = netdev_iob_clone(dev, true); + if (iob == NULL) + { + nerr("ERROR: IOB clone failed when looping UDP.\n"); + return; + } + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (IFF_IS_IPv4(dev->d_flags)) +#endif + { + ninfo("IPv4 frame\n"); + NETDEV_RXIPV4(dev); + ipv4_input(dev); + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + ninfo("IPv6 frame\n"); + NETDEV_RXIPV6(dev); + ipv6_input(dev); + } +#endif /* CONFIG_NET_IPv6 */ + + /* Restore device IOB with backup IOB */ + + netdev_iob_replace(dev, iob); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -192,9 +250,7 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn) #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 - if (conn->domain == PF_INET || - (conn->domain == PF_INET6 && - ip6_is_ipv4addr((FAR struct in6_addr *)conn->u.ipv6.raddr))) + if (IFF_IS_IPv4(dev->d_flags)) #endif { udp->udpchksum = ~udp_ipv4_chksum(dev); @@ -221,6 +277,32 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn) #ifdef CONFIG_NET_STATISTICS g_netstats.udp.sent++; #endif + +#ifdef CONFIG_NET_SOCKOPTS + /* Try loopback multicast to ourself. */ + +#ifdef CONFIG_NET_IGMP + if (_SO_GETOPT(conn->sconn.s_options, IP_MULTICAST_LOOP) && +#ifdef CONFIG_NET_IPv6 + IFF_IS_IPv4(dev->d_flags) && +#endif + IN_MULTICAST(NTOHL(raddr))) + { + udp_send_loopback(dev); + } +#endif /* CONFIG_NET_IGMP */ + +#ifdef CONFIG_NET_MLD + if (_SO_GETOPT(conn->sconn.s_options, IPV6_MULTICAST_LOOP) && +#ifdef CONFIG_NET_IPv4 + IFF_IS_IPv6(dev->d_flags) && +#endif + IN6_IS_ADDR_MULTICAST((FAR struct in6_addr *)conn->u.ipv6.raddr)) + { + udp_send_loopback(dev); + } +#endif /* CONFIG_NET_MLD */ +#endif /* CONFIG_NET_SOCKOPTS */ } }