diff options
Diffstat (limited to 'net/tipc/socket.c')
| -rw-r--r-- | net/tipc/socket.c | 76 | 
1 files changed, 35 insertions, 41 deletions
| diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 2b02a3a8031..29d94d53198 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2,7 +2,7 @@   * net/tipc/socket.c: TIPC socket API   *   * Copyright (c) 2001-2007, Ericsson AB - * Copyright (c) 2004-2008, Wind River Systems + * Copyright (c) 2004-2008, 2010-2011, Wind River Systems   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -58,6 +58,9 @@ struct tipc_sock {  #define tipc_sk(sk) ((struct tipc_sock *)(sk))  #define tipc_sk_port(sk) ((struct tipc_port *)(tipc_sk(sk)->p)) +#define tipc_rx_ready(sock) (!skb_queue_empty(&sock->sk->sk_receive_queue) || \ +			(sock->state == SS_DISCONNECTING)) +  static int backlog_rcv(struct sock *sk, struct sk_buff *skb);  static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);  static void wakeupdispatch(struct tipc_port *tport); @@ -241,7 +244,6 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,  			tipc_set_portunreliable(tp_ptr->ref, 1);  	} -	atomic_inc(&tipc_user_count);  	return 0;  } @@ -290,7 +292,7 @@ static int release(struct socket *sock)  		if (buf == NULL)  			break;  		atomic_dec(&tipc_queue_size); -		if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) +		if (TIPC_SKB_CB(buf)->handle != 0)  			buf_discard(buf);  		else {  			if ((sock->state == SS_CONNECTING) || @@ -321,7 +323,6 @@ static int release(struct socket *sock)  	sock_put(sk);  	sock->sk = NULL; -	atomic_dec(&tipc_user_count);  	return res;  } @@ -495,6 +496,8 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)  	if (likely(dest->addr.name.name.type != TIPC_CFG_SRV))  		return -EACCES; +	if (!m->msg_iovlen || (m->msg_iov[0].iov_len < sizeof(hdr))) +		return -EMSGSIZE;  	if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr)))  		return -EFAULT;  	if ((ntohs(hdr.tcm_type) & 0xC000) && (!capable(CAP_NET_ADMIN))) @@ -911,15 +914,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,  	struct tipc_port *tport = tipc_sk_port(sk);  	struct sk_buff *buf;  	struct tipc_msg *msg; +	long timeout;  	unsigned int sz;  	u32 err;  	int res;  	/* Catch invalid receive requests */ -	if (m->msg_iovlen != 1) -		return -EOPNOTSUPP;   /* Don't do multiple iovec entries yet */ -  	if (unlikely(!buf_len))  		return -EINVAL; @@ -930,6 +931,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,  		goto exit;  	} +	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);  restart:  	/* Look for a message in receive queue; wait if necessary */ @@ -939,17 +941,15 @@ restart:  			res = -ENOTCONN;  			goto exit;  		} -		if (flags & MSG_DONTWAIT) { -			res = -EWOULDBLOCK; +		if (timeout <= 0L) { +			res = timeout ? timeout : -EWOULDBLOCK;  			goto exit;  		}  		release_sock(sk); -		res = wait_event_interruptible(*sk_sleep(sk), -			(!skb_queue_empty(&sk->sk_receive_queue) || -			 (sock->state == SS_DISCONNECTING))); +		timeout = wait_event_interruptible_timeout(*sk_sleep(sk), +							   tipc_rx_ready(sock), +							   timeout);  		lock_sock(sk); -		if (res) -			goto exit;  	}  	/* Look at first message in receive queue */ @@ -991,11 +991,10 @@ restart:  			sz = buf_len;  			m->msg_flags |= MSG_TRUNC;  		} -		if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg), -					  sz))) { -			res = -EFAULT; +		res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg), +					      m->msg_iov, sz); +		if (res)  			goto exit; -		}  		res = sz;  	} else {  		if ((sock->state == SS_READY) || @@ -1038,19 +1037,15 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,  	struct tipc_port *tport = tipc_sk_port(sk);  	struct sk_buff *buf;  	struct tipc_msg *msg; +	long timeout;  	unsigned int sz;  	int sz_to_copy, target, needed;  	int sz_copied = 0; -	char __user *crs = m->msg_iov->iov_base; -	unsigned char *buf_crs;  	u32 err;  	int res = 0;  	/* Catch invalid receive attempts */ -	if (m->msg_iovlen != 1) -		return -EOPNOTSUPP;   /* Don't do multiple iovec entries yet */ -  	if (unlikely(!buf_len))  		return -EINVAL; @@ -1063,7 +1058,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,  	}  	target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); - +	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);  restart:  	/* Look for a message in receive queue; wait if necessary */ @@ -1073,17 +1068,15 @@ restart:  			res = -ENOTCONN;  			goto exit;  		} -		if (flags & MSG_DONTWAIT) { -			res = -EWOULDBLOCK; +		if (timeout <= 0L) { +			res = timeout ? timeout : -EWOULDBLOCK;  			goto exit;  		}  		release_sock(sk); -		res = wait_event_interruptible(*sk_sleep(sk), -			(!skb_queue_empty(&sk->sk_receive_queue) || -			 (sock->state == SS_DISCONNECTING))); +		timeout = wait_event_interruptible_timeout(*sk_sleep(sk), +							   tipc_rx_ready(sock), +							   timeout);  		lock_sock(sk); -		if (res) -			goto exit;  	}  	/* Look at first message in receive queue */ @@ -1112,24 +1105,25 @@ restart:  	/* Capture message data (if valid) & compute return value (always) */  	if (!err) { -		buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle); -		sz = (unsigned char *)msg + msg_size(msg) - buf_crs; +		u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle); +		sz -= offset;  		needed = (buf_len - sz_copied);  		sz_to_copy = (sz <= needed) ? sz : needed; -		if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) { -			res = -EFAULT; + +		res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset, +					      m->msg_iov, sz_to_copy); +		if (res)  			goto exit; -		} +  		sz_copied += sz_to_copy;  		if (sz_to_copy < sz) {  			if (!(flags & MSG_PEEK)) -				TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy; +				TIPC_SKB_CB(buf)->handle = +				(void *)(unsigned long)(offset + sz_to_copy);  			goto exit;  		} - -		crs += sz_to_copy;  	} else {  		if (sz_copied != 0)  			goto exit; /* can't add error msg to valid data */ @@ -1256,7 +1250,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)  	/* Enqueue message (finally!) */ -	TIPC_SKB_CB(buf)->handle = msg_data(msg); +	TIPC_SKB_CB(buf)->handle = 0;  	atomic_inc(&tipc_queue_size);  	__skb_queue_tail(&sk->sk_receive_queue, buf); @@ -1608,7 +1602,7 @@ restart:  		buf = __skb_dequeue(&sk->sk_receive_queue);  		if (buf) {  			atomic_dec(&tipc_queue_size); -			if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) { +			if (TIPC_SKB_CB(buf)->handle != 0) {  				buf_discard(buf);  				goto restart;  			} | 
