net/udp_input: Only dup packets for broadcast / multicast.
We found previous multicast support (https://github.com/apache/nuttx/pull/12015) harms some unicast situation, and the `udp_input` should not dup packets for unicast. Now, we only pass broadcast / multicast packets into each listener and let the code under control of `CONFIG_NET_BROADCAST`. Ref: https://github.com/torvalds/linux/blob/v6.8/net/ipv4/udp.c#L2219 Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
37a6806bb4
commit
41ab3a9cfe
@ -63,6 +63,53 @@
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_is_broadcast
|
||||
*
|
||||
* Description:
|
||||
* Check if the destination address is a broadcast/multicast address.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device driver structure containing the received UDP packet
|
||||
*
|
||||
* Returned Value:
|
||||
* True if the destination address is a broadcast/multicast address
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_NET_SOCKOPTS) && defined(CONFIG_NET_BROADCAST)
|
||||
static bool udp_is_broadcast(FAR struct net_driver_s *dev)
|
||||
{
|
||||
/* Check if the destination address is a broadcast/multicast address */
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
# ifdef CONFIG_NET_IPv6
|
||||
if (IFF_IS_IPv4(dev->d_flags))
|
||||
# endif
|
||||
{
|
||||
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
|
||||
in_addr_t destipaddr = net_ip4addr_conv32(ipv4->destipaddr);
|
||||
|
||||
return net_ipv4addr_cmp(destipaddr, INADDR_BROADCAST) ||
|
||||
IN_MULTICAST(NTOHL(destipaddr)) ||
|
||||
(net_ipv4addr_maskcmp(destipaddr, dev->d_ipaddr, dev->d_netmask)
|
||||
&& net_ipv4addr_broadcast(destipaddr, dev->d_netmask));
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
# ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
# endif
|
||||
{
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
return net_is_addr_mcast(ipv6->destipaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_input_conn
|
||||
*
|
||||
@ -162,7 +209,7 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen)
|
||||
{
|
||||
FAR struct udp_hdr_s *udp;
|
||||
FAR struct udp_conn_s *conn;
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
#if defined(CONFIG_NET_SOCKOPTS) && defined(CONFIG_NET_BROADCAST)
|
||||
FAR struct udp_conn_s *nextconn;
|
||||
FAR struct iob_s *iob;
|
||||
#endif
|
||||
@ -243,32 +290,38 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen)
|
||||
{
|
||||
/* We'll only get multiple conn when we support SO_REUSEADDR */
|
||||
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
/* Do we have second connection that can hold this packet? */
|
||||
#if defined(CONFIG_NET_SOCKOPTS) && defined(CONFIG_NET_BROADCAST)
|
||||
/* Check if the destination is a broadcast/multicast address */
|
||||
|
||||
while ((nextconn = udp_active(dev, conn, udp)) != NULL)
|
||||
if (udp_is_broadcast(dev))
|
||||
{
|
||||
/* Yes... There are multiple listeners on the same port.
|
||||
* We need to clone the packet and deliver it to each listener.
|
||||
*/
|
||||
/* Do we have second connection that can hold this packet? */
|
||||
|
||||
iob = netdev_iob_clone(dev, true);
|
||||
if (iob == NULL)
|
||||
while ((nextconn = udp_active(dev, conn, udp)) != NULL)
|
||||
{
|
||||
nerr("ERROR: IOB clone failed.\n");
|
||||
break; /* We can still process one time without clone. */
|
||||
}
|
||||
/* Yes... There are multiple listeners on the same port.
|
||||
* We need to clone the packet and deliver it to each
|
||||
* listener.
|
||||
*/
|
||||
|
||||
ret = udp_input_conn(dev, conn, udpiplen);
|
||||
if (ret < 0)
|
||||
{
|
||||
nwarn("WARNING: A conn failed to process the packet %d\n",
|
||||
ret); /* We can still continue for next conn. */
|
||||
}
|
||||
iob = netdev_iob_clone(dev, true);
|
||||
if (iob == NULL)
|
||||
{
|
||||
nerr("ERROR: IOB clone failed.\n");
|
||||
break; /* We can still process once without clone. */
|
||||
}
|
||||
|
||||
netdev_iob_replace(dev, iob);
|
||||
udp = IPBUF(iplen);
|
||||
conn = nextconn;
|
||||
ret = udp_input_conn(dev, conn, udpiplen);
|
||||
if (ret < 0)
|
||||
{
|
||||
nwarn("WARNING: A conn failed to process the pkt %d\n",
|
||||
ret); /* We can still continue for next conn. */
|
||||
}
|
||||
|
||||
netdev_iob_replace(dev, iob);
|
||||
udp = IPBUF(iplen);
|
||||
conn = nextconn;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user