diff options
Diffstat (limited to 'net/ax25/af_ax25.c')
| -rw-r--r-- | net/ax25/af_ax25.c | 33 | 
1 files changed, 28 insertions, 5 deletions
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 95393bb2760b..4c7030ed8d33 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1661,9 +1661,12 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,  			int flags)  {  	struct sock *sk = sock->sk; -	struct sk_buff *skb; +	struct sk_buff *skb, *last; +	struct sk_buff_head *sk_queue;  	int copied;  	int err = 0; +	int off = 0; +	long timeo;  	lock_sock(sk);  	/* @@ -1675,10 +1678,29 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,  		goto out;  	} -	/* Now we can treat all alike */ -	skb = skb_recv_datagram(sk, flags, &err); -	if (skb == NULL) -		goto out; +	/*  We need support for non-blocking reads. */ +	sk_queue = &sk->sk_receive_queue; +	skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, &err, &last); +	/* If no packet is available, release_sock(sk) and try again. */ +	if (!skb) { +		if (err != -EAGAIN) +			goto out; +		release_sock(sk); +		timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); +		while (timeo && !__skb_wait_for_more_packets(sk, sk_queue, &err, +							     &timeo, last)) { +			skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, +						      &err, &last); +			if (skb) +				break; + +			if (err != -EAGAIN) +				goto done; +		} +		if (!skb) +			goto done; +		lock_sock(sk); +	}  	if (!sk_to_ax25(sk)->pidincl)  		skb_pull(skb, 1);		/* Remove PID */ @@ -1725,6 +1747,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,  out:  	release_sock(sk); +done:  	return err;  }  | 
