Subject: kern/7640: (udp) socket can get stuck if ICMP is received
To: None <gnats-bugs@gnats.netbsd.org>
From: None <Havard.Eidnes@runit.sintef.no>
List: netbsd-bugs
Date: 05/24/1999 09:50:57
>Number:         7640
>Category:       kern
>Synopsis:       (udp) socket can get stuck if ICMP is received
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon May 24 09:50:01 1999
>Last-Modified:
>Originator:     Havard Eidnes
>Organization:
	RUNIT AS
>Release:        NetBSD-1.3K
>Environment:
	
System: NetBSD vader.runit.sintef.no 1.3I NetBSD 1.3I (VADER) #0: Sat Jan 9 18:53:46 MET 1999 he@hugin.runit.sintef.no:/usr/src/sys/arch/i386/compile/VADER i386


>Description:
	vat's source code contains the following comment, cut and
	pasted from FreeBSD's patch-af of their port of vat:

+               /*
+                * Due to a bug in kern/uipc_socket.c, on several
+                * systems, datagram sockets incorrectly persist
+                * in an error state on receipt of any ICMP
+                * error.  This causes unicast connection
+                * rendezvous problems, and worse, multicast
+                * transmission problems because several systems
+                * incorrectly send port unreachables for 
+                * multicast destinations.  Our work around
+                * is to call getsockopt(..., SO_ERROR, ...)
+                * which resets so->so_error.
+                *
+                * This bug originated at CSRG in Berkeley
+                * and was present in the BSD Reno networking
+                * code release.  It has since been fixed
+                * in OSF-3.x.  It is know to remain
+                * in 4.4BSD and AIX-4.1.3.
+                *
+                * A fix is to change the following lines from
+                * kern/uipc_socket.c:
+                *
+                *      if (so_serror)
+                *              snderr(so->so_error);
+                *
+                * to:
+                *
+                *      if (so->so_error) {
+                *              error = so->so_error;
+                *              so->so_error = 0;
+                *              splx(s);
+                *              goto release;
+                *      }
+                *
+                */

	There is another scenario where this error will occur, and
	that is if you try to use a NetBSD host as a continous traffic
	source of (in my case UDP) traffic.  If an ICMP Source Quench
	or ICMP Port Unreachable is received, the sending socket will
	get stuck not sending any more traffic and always returning
	the same error over and over again.


>How-To-Repeat:
	Write a program to send a continous stream of UDP datagrams to
	another (local) host's port 9, while that port 9 is turned off
	(causing a Port Unreachable to be returned).  Watch the UDP
	sender stop after the first reception of that ICMP message.

	While it could be argued that's the right thing to do in
	exactly this instance, completely locking up on ICMP Source
	Quench reception is, umm, not very nice.


>Fix:
	I'm not 100% sure of this, e.g. what effect will it have on
	TCP sockets?  Someone more versed in the innards of this code
	should take a closer look at this fix.

--- uipc_socket.c.old   Sat Jan 23 17:30:32 1999
+++ uipc_socket.c   Mon May 24 18:43:00 1999
@@ -403,6 +403,9 @@
                if (so->so_state & SS_CANTSENDMORE)
                        snderr(EPIPE);
-               if (so->so_error)
-                       snderr(so->so_error);
+               if (so->so_error) {
+                       error = so->so_error;
+                       so->so_error = 0;
+                       snderr(error);
+               }
                if ((so->so_state & SS_ISCONNECTED) == 0) {
                        if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
>Audit-Trail:
>Unformatted: