On Thu, 28 Oct 1999, [EMAIL PROTECTED] wrote:
>> The reason is, that skb_recv_datagram is used get incoming connection requests, but 
>this checks
>> if a SOCK_STREAM socket is in TCP_ESTABLISHED state before waiting.
>
>Opla! Thank you.
>
>The patch is incorrect (racy), but you can make correct one
>if copy part of skb_recv_datagram, omitting offending line
>and some useless checks (f.e. sk->shutdown, socket_error() etc)

Ok, here is my corrected version.
Is it possible to make a generic race-free skb_wait_datagram function, because some 
other
protocols might need this too for their accept call (ax25, x25, irda, rose, spx)

Lars
--- linux.orig/net/unix/af_unix.c	Thu Oct 28 18:25:11 1999
+++ linux/net/unix/af_unix.c	Fri Oct 29 07:56:51 1999
@@ -942,10 +942,46 @@
 		sockb->state=SS_CONNECTED;
 	}
 	return 0;
 }
 
+/*
+ * Wait for a packet..
+ */
+
+static int unix_wait_for_connect(struct sock * sk, int *err)
+{
+	int error;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	__set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(sk->sleep, &wait);
+
+	if (!skb_queue_empty(&sk->receive_queue))
+		goto ready;
+
+	/* handle signals */
+	error = -ERESTARTSYS;
+	if (signal_pending(current))
+		goto out;
+
+	schedule();
+
+ready:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep, &wait);
+	return 0;
+
+out:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep, &wait);
+	*err = error;
+	return error;
+}
+
+
 static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
 {
 	unix_socket *sk = sock->sk;
 	unix_socket *tsk;
 	struct sk_buff *skb;
@@ -959,20 +995,28 @@
 	if (sk->state!=TCP_LISTEN)
 		goto out;
 
 	/* If socket state is TCP_LISTEN it cannot change,
 	   so that no locks are necessary.
+ 
+	   It's not possible to use skb_recv_datagram here,
+	   because this checks if the socket is connected.
 	 */
-
-	skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);
-	if (!skb)
-		goto out;
+	
+	while ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
+		if (flags&O_NONBLOCK) {
+			err = -EAGAIN;
+			goto out;
+		}
+		if (unix_wait_for_connect(sk, &err) != 0)
+			goto out;
+        }
 
 	tsk = skb->sk;
+	kfree_skb(skb);
 	if (skb_queue_len(&sk->receive_queue) <= sk->max_ack_backlog/2)
 		wake_up_interruptible(&sk->protinfo.af_unix.peer_wait);
-	skb_free_datagram(sk, skb);
 
 	/* attach accepted sock to socket */
 	unix_state_wlock(tsk);
 	newsock->state = SS_CONNECTED;
 	newsock->sk = tsk;

Reply via email to