Subject: kern/14597: Bad UDP checksums on IPv4 multicast loopback packets
To: None <gnats-bugs@gnats.netbsd.org>
From: None <fwkg7679@mb.infoweb.ne.jp>
List: netbsd-bugs
Date: 11/16/2001 02:05:58
>Number: 14597
>Category: kern
>Synopsis: Bad UDP checksums on IPv4 multicast loopback packets
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Nov 16 02:07:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator: KUROSAWA Takahiro
>Release: NetBSD 1.5Y as of 2001-10-30
>Organization:
>Environment:
NetBSD fiva 1.5Y NetBSD 1.5Y (FIVA) #5: Wed Nov 14 21:46:43 JST 2001 kurosawa@fiva:/usr/src/sys/arch/i386/compile/FIVA i386
>Description:
IPv4 multicast loopback that is enabled by setsockopt(IPPROTO_IP, IP_MULTICAST_LOOP)
doesn't work correctly. It looks that the multicast loopback packets are dropped
due to bad UDP checksums.
Probably this results from the "delayed" checksum calculation doesn't completed for
multicast loopback packets.
>How-To-Repeat:
Run the following program. The program blocks on recvfrom(), that isn't expected
behavior. Stop the program and see udp bad checksum count of the "netstat -s"
output.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
static char sendbuf[] = "This is a multicast message.\n";
static char recvbuf[1024];
int
main(int argc, char *argv[])
{
struct sockaddr_in s_in, s_in_recv;
struct addrinfo *ai, hints;
int fd, ret;
u_char loop = 1;
size_t addrlen;
struct ip_mreq imr;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
ret = getaddrinfo("224.255.222.239", "47000", &hints, &ai);
if (ret)
errx(1, "getaddrinfo(): %s", gai_strerror(ret));
fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (fd < 0)
err(1, "socket()");
s_in = *(struct sockaddr_in *)ai->ai_addr;
s_in.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
err(1, "bind()");
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
&loop, sizeof(loop)) < 0)
err(1, "setsockopt IP_MULTICAST_LOOP");
imr.imr_multiaddr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&imr, sizeof(imr)) < 0)
err(1, "setsockopt IP_ADD_MEMBERSHIP");
if (sendto(fd, sendbuf, sizeof(sendbuf), 0, ai->ai_addr,
ai->ai_addrlen) < 0)
err(1, "sendto()");
printf("sent: %s", sendbuf);
addrlen = sizeof(s_in_recv);
if (recvfrom(fd, recvbuf, sizeof(recvbuf), 0,
(struct sockaddr *)&s_in_recv, &addrlen) < 0)
err(1, "recvfrom()");
printf("received: %s", recvbuf);
return 0;
}
>Fix:
The following patch will fix the problem:
--- sys/netinet/ip_output.c- Tue Sep 18 20:23:35 2001
+++ sys/netinet/ip_output.c Fri Nov 16 12:04:18 2001
@@ -1631,6 +1631,13 @@
ip = mtod(copym, struct ip *);
HTONS(ip->ip_len);
HTONS(ip->ip_off);
+
+ if (copym->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) {
+ in_delayed_cksum(copym);
+ copym->m_pkthdr.csum_flags &=
+ ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
+ }
+
ip->ip_sum = 0;
ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
(void) looutput(ifp, copym, sintosa(dst), NULL);
>Release-Note:
>Audit-Trail:
>Unformatted: