diff options
Diffstat (limited to 'net/tipc/socket.c')
| -rw-r--r-- | net/tipc/socket.c | 904 | 
1 files changed, 502 insertions, 402 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 6cc7ddd2fb7..ef0475568f9 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1,7 +1,7 @@  /*   * net/tipc/socket.c: TIPC socket API   * - * Copyright (c) 2001-2007, 2012 Ericsson AB + * Copyright (c) 2001-2007, 2012-2014, Ericsson AB   * Copyright (c) 2004-2008, 2010-2013, Wind River Systems   * All rights reserved.   * @@ -36,35 +36,20 @@  #include "core.h"  #include "port.h" +#include "node.h"  #include <linux/export.h> -#include <net/sock.h>  #define SS_LISTENING	-1	/* socket is listening */  #define SS_READY	-2	/* socket is connectionless */  #define CONN_TIMEOUT_DEFAULT	8000	/* default connect timeout = 8s */ -struct tipc_sock { -	struct sock sk; -	struct tipc_port *p; -	struct tipc_portid peer_name; -	unsigned int conn_timeout; -}; - -#define tipc_sk(sk) ((struct tipc_sock *)(sk)) -#define tipc_sk_port(sk) (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); -static void tipc_data_ready(struct sock *sk, int len); +static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); +static void tipc_data_ready(struct sock *sk);  static void tipc_write_space(struct sock *sk); -static int release(struct socket *sock); -static int accept(struct socket *sock, struct socket *new_sock, int flags); +static int tipc_release(struct socket *sock); +static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);  static const struct proto_ops packet_ops;  static const struct proto_ops stream_ops; @@ -73,8 +58,6 @@ static const struct proto_ops msg_ops;  static struct proto tipc_proto;  static struct proto tipc_proto_kern; -static int sockets_enabled; -  /*   * Revised TIPC socket locking policy:   * @@ -120,6 +103,8 @@ static int sockets_enabled;   *   - port reference   */ +#include "socket.h" +  /**   * advance_rx_queue - discard first buffer in socket receive queue   * @@ -155,13 +140,15 @@ static void reject_rx_queue(struct sock *sk)   *   * Returns 0 on success, errno otherwise   */ -static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, -			  int kern) +static int tipc_sk_create(struct net *net, struct socket *sock, +			  int protocol, int kern)  {  	const struct proto_ops *ops;  	socket_state state;  	struct sock *sk; -	struct tipc_port *tp_ptr; +	struct tipc_sock *tsk; +	struct tipc_port *port; +	u32 ref;  	/* Validate arguments */  	if (unlikely(protocol != 0)) @@ -194,10 +181,12 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,  	if (sk == NULL)  		return -ENOMEM; -	/* Allocate TIPC port for socket to use */ -	tp_ptr = tipc_createport(sk, &dispatch, &wakeupdispatch, -				 TIPC_LOW_IMPORTANCE); -	if (unlikely(!tp_ptr)) { +	tsk = tipc_sk(sk); +	port = &tsk->port; + +	ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE); +	if (!ref) { +		pr_warn("Socket registration failed, ref. table exhausted\n");  		sk_free(sk);  		return -ENOMEM;  	} @@ -207,21 +196,19 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,  	sock->state = state;  	sock_init_data(sock, sk); -	sk->sk_backlog_rcv = backlog_rcv; +	sk->sk_backlog_rcv = tipc_backlog_rcv;  	sk->sk_rcvbuf = sysctl_tipc_rmem[1];  	sk->sk_data_ready = tipc_data_ready;  	sk->sk_write_space = tipc_write_space; -	tipc_sk(sk)->p = tp_ptr; -	tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT; - -	spin_unlock_bh(tp_ptr->lock); +	tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; +	atomic_set(&tsk->dupl_rcvcnt, 0); +	tipc_port_unlock(port);  	if (sock->state == SS_READY) { -		tipc_set_portunreturnable(tp_ptr->ref, 1); +		tipc_port_set_unreturnable(port, true);  		if (sock->type == SOCK_DGRAM) -			tipc_set_portunreliable(tp_ptr->ref, 1); +			tipc_port_set_unreliable(port, true);  	} -  	return 0;  } @@ -239,7 +226,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,  int tipc_sock_create_local(int type, struct socket **res)  {  	int rc; -	struct sock *sk;  	rc = sock_create_lite(AF_TIPC, type, 0, res);  	if (rc < 0) { @@ -248,8 +234,6 @@ int tipc_sock_create_local(int type, struct socket **res)  	}  	tipc_sk_create(&init_net, *res, 0, 1); -	sk = (*res)->sk; -  	return 0;  } @@ -262,7 +246,7 @@ int tipc_sock_create_local(int type, struct socket **res)   */  void tipc_sock_release_local(struct socket *sock)  { -	release(sock); +	tipc_release(sock);  	sock->ops = NULL;  	sock_release(sock);  } @@ -288,7 +272,7 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,  	if (ret < 0)  		return ret; -	ret = accept(sock, *newsock, flags); +	ret = tipc_accept(sock, *newsock, flags);  	if (ret < 0) {  		sock_release(*newsock);  		return ret; @@ -298,7 +282,7 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,  }  /** - * release - destroy a TIPC socket + * tipc_release - destroy a TIPC socket   * @sock: socket to destroy   *   * This routine cleans up any messages that are still queued on the socket. @@ -313,12 +297,12 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,   *   * Returns 0 on success, errno otherwise   */ -static int release(struct socket *sock) +static int tipc_release(struct socket *sock)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport; +	struct tipc_sock *tsk; +	struct tipc_port *port;  	struct sk_buff *buf; -	int res;  	/*  	 * Exit if socket isn't fully initialized (occurs when a failed accept() @@ -327,7 +311,8 @@ static int release(struct socket *sock)  	if (sk == NULL)  		return 0; -	tport = tipc_sk_port(sk); +	tsk = tipc_sk(sk); +	port = &tsk->port;  	lock_sock(sk);  	/* @@ -338,23 +323,22 @@ static int release(struct socket *sock)  		buf = __skb_dequeue(&sk->sk_receive_queue);  		if (buf == NULL)  			break; -		if (TIPC_SKB_CB(buf)->handle != 0) +		if (TIPC_SKB_CB(buf)->handle != NULL)  			kfree_skb(buf);  		else {  			if ((sock->state == SS_CONNECTING) ||  			    (sock->state == SS_CONNECTED)) {  				sock->state = SS_DISCONNECTING; -				tipc_disconnect(tport->ref); +				tipc_port_disconnect(port->ref);  			}  			tipc_reject_msg(buf, TIPC_ERR_NO_PORT);  		}  	} -	/* -	 * Delete TIPC port; this ensures no more messages are queued -	 * (also disconnects an active connection & sends a 'FIN-' to peer) +	/* Destroy TIPC port; also disconnects an active connection and +	 * sends a 'FIN-' to peer.  	 */ -	res = tipc_deleteport(tport->ref); +	tipc_port_destroy(port);  	/* Discard any remaining (connection-based) messages in receive queue */  	__skb_queue_purge(&sk->sk_receive_queue); @@ -366,11 +350,11 @@ static int release(struct socket *sock)  	sock_put(sk);  	sock->sk = NULL; -	return res; +	return 0;  }  /** - * bind - associate or disassocate TIPC name(s) with a socket + * tipc_bind - associate or disassocate TIPC name(s) with a socket   * @sock: socket structure   * @uaddr: socket address describing name(s) and desired operation   * @uaddr_len: size of socket address data structure @@ -384,36 +368,53 @@ static int release(struct socket *sock)   * NOTE: This routine doesn't need to take the socket lock since it doesn't   *       access any non-constant socket information.   */ -static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) +static int tipc_bind(struct socket *sock, struct sockaddr *uaddr, +		     int uaddr_len)  { +	struct sock *sk = sock->sk;  	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; -	u32 portref = tipc_sk_port(sock->sk)->ref; +	struct tipc_sock *tsk = tipc_sk(sk); +	int res = -EINVAL; -	if (unlikely(!uaddr_len)) -		return tipc_withdraw(portref, 0, NULL); +	lock_sock(sk); +	if (unlikely(!uaddr_len)) { +		res = tipc_withdraw(&tsk->port, 0, NULL); +		goto exit; +	} -	if (uaddr_len < sizeof(struct sockaddr_tipc)) -		return -EINVAL; -	if (addr->family != AF_TIPC) -		return -EAFNOSUPPORT; +	if (uaddr_len < sizeof(struct sockaddr_tipc)) { +		res = -EINVAL; +		goto exit; +	} +	if (addr->family != AF_TIPC) { +		res = -EAFNOSUPPORT; +		goto exit; +	}  	if (addr->addrtype == TIPC_ADDR_NAME)  		addr->addr.nameseq.upper = addr->addr.nameseq.lower; -	else if (addr->addrtype != TIPC_ADDR_NAMESEQ) -		return -EAFNOSUPPORT; +	else if (addr->addrtype != TIPC_ADDR_NAMESEQ) { +		res = -EAFNOSUPPORT; +		goto exit; +	}  	if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) &&  	    (addr->addr.nameseq.type != TIPC_TOP_SRV) && -	    (addr->addr.nameseq.type != TIPC_CFG_SRV)) -		return -EACCES; +	    (addr->addr.nameseq.type != TIPC_CFG_SRV)) { +		res = -EACCES; +		goto exit; +	} -	return (addr->scope > 0) ? -		tipc_publish(portref, addr->scope, &addr->addr.nameseq) : -		tipc_withdraw(portref, -addr->scope, &addr->addr.nameseq); +	res = (addr->scope > 0) ? +		tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) : +		tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq); +exit: +	release_sock(sk); +	return res;  }  /** - * get_name - get port ID of socket or peer socket + * tipc_getname - get port ID of socket or peer socket   * @sock: socket structure   * @uaddr: area for returned socket address   * @uaddr_len: area for returned length of socket address @@ -425,21 +426,21 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)   *       accesses socket information that is unchanging (or which changes in   *       a completely predictable manner).   */ -static int get_name(struct socket *sock, struct sockaddr *uaddr, -		    int *uaddr_len, int peer) +static int tipc_getname(struct socket *sock, struct sockaddr *uaddr, +			int *uaddr_len, int peer)  {  	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; -	struct tipc_sock *tsock = tipc_sk(sock->sk); +	struct tipc_sock *tsk = tipc_sk(sock->sk);  	memset(addr, 0, sizeof(*addr));  	if (peer) {  		if ((sock->state != SS_CONNECTED) &&  			((peer != 2) || (sock->state != SS_DISCONNECTING)))  			return -ENOTCONN; -		addr->addr.id.ref = tsock->peer_name.ref; -		addr->addr.id.node = tsock->peer_name.node; +		addr->addr.id.ref = tipc_port_peerport(&tsk->port); +		addr->addr.id.node = tipc_port_peernode(&tsk->port);  	} else { -		addr->addr.id.ref = tsock->p->ref; +		addr->addr.id.ref = tsk->port.ref;  		addr->addr.id.node = tipc_own_addr;  	} @@ -453,7 +454,7 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,  }  /** - * poll - read and possibly block on pollmask + * tipc_poll - read and possibly block on pollmask   * @file: file structure associated with the socket   * @sock: socket for which to calculate the poll bits   * @wait: ??? @@ -492,22 +493,23 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,   * imply that the operation will succeed, merely that it should be performed   * and will not block.   */ -static unsigned int poll(struct file *file, struct socket *sock, -			 poll_table *wait) +static unsigned int tipc_poll(struct file *file, struct socket *sock, +			      poll_table *wait)  {  	struct sock *sk = sock->sk; +	struct tipc_sock *tsk = tipc_sk(sk);  	u32 mask = 0;  	sock_poll_wait(file, sk_sleep(sk), wait);  	switch ((int)sock->state) {  	case SS_UNCONNECTED: -		if (!tipc_sk_port(sk)->congested) +		if (!tsk->port.congested)  			mask |= POLLOUT;  		break;  	case SS_READY:  	case SS_CONNECTED: -		if (!tipc_sk_port(sk)->congested) +		if (!tsk->port.congested)  			mask |= POLLOUT;  		/* fall thru' */  	case SS_CONNECTING: @@ -554,8 +556,34 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)  	return 0;  } +static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) +{ +	struct sock *sk = sock->sk; +	struct tipc_sock *tsk = tipc_sk(sk); +	DEFINE_WAIT(wait); +	int done; + +	do { +		int err = sock_error(sk); +		if (err) +			return err; +		if (sock->state == SS_DISCONNECTING) +			return -EPIPE; +		if (!*timeo_p) +			return -EAGAIN; +		if (signal_pending(current)) +			return sock_intr_errno(*timeo_p); + +		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); +		done = sk_wait_event(sk, timeo_p, !tsk->port.congested); +		finish_wait(sk_sleep(sk), &wait); +	} while (!done); +	return 0; +} + +  /** - * send_msg - send message in connectionless manner + * tipc_sendmsg - send message in connectionless manner   * @iocb: if NULL, indicates that socket lock is already held   * @sock: socket structure   * @m: message to send @@ -568,14 +596,15 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)   *   * Returns the number of bytes sent on success, or errno otherwise   */ -static int send_msg(struct kiocb *iocb, struct socket *sock, -		    struct msghdr *m, size_t total_len) +static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, +			struct msghdr *m, size_t total_len)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); -	struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; +	struct tipc_sock *tsk = tipc_sk(sk); +	struct tipc_port *port = &tsk->port; +	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);  	int needs_conn; -	long timeout_val; +	long timeo;  	int res = -EINVAL;  	if (unlikely(!dest)) @@ -599,36 +628,33 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,  			res = -EISCONN;  			goto exit;  		} -		if (tport->published) { +		if (tsk->port.published) {  			res = -EOPNOTSUPP;  			goto exit;  		}  		if (dest->addrtype == TIPC_ADDR_NAME) { -			tport->conn_type = dest->addr.name.name.type; -			tport->conn_instance = dest->addr.name.name.instance; +			tsk->port.conn_type = dest->addr.name.name.type; +			tsk->port.conn_instance = dest->addr.name.name.instance;  		}  		/* Abort any pending connection attempts (very unlikely) */  		reject_rx_queue(sk);  	} -	timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); - +	timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);  	do {  		if (dest->addrtype == TIPC_ADDR_NAME) {  			res = dest_name_check(dest, m);  			if (res)  				break; -			res = tipc_send2name(tport->ref, +			res = tipc_send2name(port,  					     &dest->addr.name.name,  					     dest->addr.name.domain, -					     m->msg_iovlen,  					     m->msg_iov,  					     total_len);  		} else if (dest->addrtype == TIPC_ADDR_ID) { -			res = tipc_send2port(tport->ref, +			res = tipc_send2port(port,  					     &dest->addr.id, -					     m->msg_iovlen,  					     m->msg_iov,  					     total_len);  		} else if (dest->addrtype == TIPC_ADDR_MCAST) { @@ -639,25 +665,19 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,  			res = dest_name_check(dest, m);  			if (res)  				break; -			res = tipc_multicast(tport->ref, -					     &dest->addr.nameseq, -					     m->msg_iovlen, -					     m->msg_iov, -					     total_len); +			res = tipc_port_mcast_xmit(port, +						   &dest->addr.nameseq, +						   m->msg_iov, +						   total_len);  		}  		if (likely(res != -ELINKCONG)) {  			if (needs_conn && (res >= 0))  				sock->state = SS_CONNECTING;  			break;  		} -		if (timeout_val <= 0L) { -			res = timeout_val ? timeout_val : -EWOULDBLOCK; +		res = tipc_wait_for_sndmsg(sock, &timeo); +		if (res)  			break; -		} -		release_sock(sk); -		timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), -					       !tport->congested, timeout_val); -		lock_sock(sk);  	} while (1);  exit: @@ -666,8 +686,37 @@ exit:  	return res;  } +static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) +{ +	struct sock *sk = sock->sk; +	struct tipc_sock *tsk = tipc_sk(sk); +	struct tipc_port *port = &tsk->port; +	DEFINE_WAIT(wait); +	int done; + +	do { +		int err = sock_error(sk); +		if (err) +			return err; +		if (sock->state == SS_DISCONNECTING) +			return -EPIPE; +		else if (sock->state != SS_CONNECTED) +			return -ENOTCONN; +		if (!*timeo_p) +			return -EAGAIN; +		if (signal_pending(current)) +			return sock_intr_errno(*timeo_p); + +		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); +		done = sk_wait_event(sk, timeo_p, +				     (!port->congested || !port->connected)); +		finish_wait(sk_sleep(sk), &wait); +	} while (!done); +	return 0; +} +  /** - * send_packet - send a connection-oriented message + * tipc_send_packet - send a connection-oriented message   * @iocb: if NULL, indicates that socket lock is already held   * @sock: socket structure   * @m: message to send @@ -677,18 +726,18 @@ exit:   *   * Returns the number of bytes sent on success, or errno otherwise   */ -static int send_packet(struct kiocb *iocb, struct socket *sock, -		       struct msghdr *m, size_t total_len) +static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, +			    struct msghdr *m, size_t total_len)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); -	struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; -	long timeout_val; -	int res; +	struct tipc_sock *tsk = tipc_sk(sk); +	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); +	int res = -EINVAL; +	long timeo;  	/* Handle implied connection establishment */  	if (unlikely(dest)) -		return send_msg(iocb, sock, m, total_len); +		return tipc_sendmsg(iocb, sock, m, total_len);  	if (total_len > TIPC_MAX_USER_MSG_SIZE)  		return -EMSGSIZE; @@ -696,38 +745,31 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,  	if (iocb)  		lock_sock(sk); -	timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); +	if (unlikely(sock->state != SS_CONNECTED)) { +		if (sock->state == SS_DISCONNECTING) +			res = -EPIPE; +		else +			res = -ENOTCONN; +		goto exit; +	} +	timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);  	do { -		if (unlikely(sock->state != SS_CONNECTED)) { -			if (sock->state == SS_DISCONNECTING) -				res = -EPIPE; -			else -				res = -ENOTCONN; -			break; -		} - -		res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov, -				total_len); +		res = tipc_send(&tsk->port, m->msg_iov, total_len);  		if (likely(res != -ELINKCONG))  			break; -		if (timeout_val <= 0L) { -			res = timeout_val ? timeout_val : -EWOULDBLOCK; +		res = tipc_wait_for_sndpkt(sock, &timeo); +		if (res)  			break; -		} -		release_sock(sk); -		timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), -			(!tport->congested || !tport->connected), timeout_val); -		lock_sock(sk);  	} while (1); - +exit:  	if (iocb)  		release_sock(sk);  	return res;  }  /** - * send_stream - send stream-oriented data + * tipc_send_stream - send stream-oriented data   * @iocb: (unused)   * @sock: socket structure   * @m: data to send @@ -738,11 +780,11 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,   * Returns the number of bytes sent on success (or partial success),   * or errno if no data sent   */ -static int send_stream(struct kiocb *iocb, struct socket *sock, -		       struct msghdr *m, size_t total_len) +static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, +			    struct msghdr *m, size_t total_len)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); +	struct tipc_sock *tsk = tipc_sk(sk);  	struct msghdr my_msg;  	struct iovec my_iov;  	struct iovec *curr_iov; @@ -758,16 +800,11 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,  	/* Handle special cases where there is no connection */  	if (unlikely(sock->state != SS_CONNECTED)) { -		if (sock->state == SS_UNCONNECTED) { -			res = send_packet(NULL, sock, m, total_len); -			goto exit; -		} else if (sock->state == SS_DISCONNECTING) { -			res = -EPIPE; -			goto exit; -		} else { -			res = -ENOTCONN; -			goto exit; -		} +		if (sock->state == SS_UNCONNECTED) +			res = tipc_send_packet(NULL, sock, m, total_len); +		else +			res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; +		goto exit;  	}  	if (unlikely(m->msg_name)) { @@ -795,21 +832,22 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,  	my_msg.msg_name = NULL;  	bytes_sent = 0; -	hdr_size = msg_hdr_sz(&tport->phdr); +	hdr_size = msg_hdr_sz(&tsk->port.phdr);  	while (curr_iovlen--) {  		curr_start = curr_iov->iov_base;  		curr_left = curr_iov->iov_len;  		while (curr_left) { -			bytes_to_send = tport->max_pkt - hdr_size; +			bytes_to_send = tsk->port.max_pkt - hdr_size;  			if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE)  				bytes_to_send = TIPC_MAX_USER_MSG_SIZE;  			if (curr_left < bytes_to_send)  				bytes_to_send = curr_left;  			my_iov.iov_base = curr_start;  			my_iov.iov_len = bytes_to_send; -			res = send_packet(NULL, sock, &my_msg, bytes_to_send); +			res = tipc_send_packet(NULL, sock, &my_msg, +					       bytes_to_send);  			if (res < 0) {  				if (bytes_sent)  					res = bytes_sent; @@ -830,27 +868,25 @@ exit:  /**   * auto_connect - complete connection setup to a remote port - * @sock: socket structure + * @tsk: tipc socket structure   * @msg: peer's response message   *   * Returns 0 on success, errno otherwise   */ -static int auto_connect(struct socket *sock, struct tipc_msg *msg) +static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg)  { -	struct tipc_sock *tsock = tipc_sk(sock->sk); -	struct tipc_port *p_ptr; +	struct tipc_port *port = &tsk->port; +	struct socket *sock = tsk->sk.sk_socket; +	struct tipc_portid peer; -	tsock->peer_name.ref = msg_origport(msg); -	tsock->peer_name.node = msg_orignode(msg); -	p_ptr = tipc_port_deref(tsock->p->ref); -	if (!p_ptr) -		return -EINVAL; +	peer.ref = msg_origport(msg); +	peer.node = msg_orignode(msg); -	__tipc_connect(tsock->p->ref, p_ptr, &tsock->peer_name); +	__tipc_port_connect(port->ref, port, &peer);  	if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)  		return -EINVAL; -	msg_set_importance(&p_ptr->phdr, (u32)msg_importance(msg)); +	msg_set_importance(&port->phdr, (u32)msg_importance(msg));  	sock->state = SS_CONNECTED;  	return 0;  } @@ -864,7 +900,7 @@ static int auto_connect(struct socket *sock, struct tipc_msg *msg)   */  static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)  { -	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; +	DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name);  	if (addr) {  		addr->family = AF_TIPC; @@ -949,8 +985,41 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,  	return 0;  } +static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) +{ +	struct sock *sk = sock->sk; +	DEFINE_WAIT(wait); +	long timeo = *timeop; +	int err; + +	for (;;) { +		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); +		if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { +			if (sock->state == SS_DISCONNECTING) { +				err = -ENOTCONN; +				break; +			} +			release_sock(sk); +			timeo = schedule_timeout(timeo); +			lock_sock(sk); +		} +		err = 0; +		if (!skb_queue_empty(&sk->sk_receive_queue)) +			break; +		err = sock_intr_errno(timeo); +		if (signal_pending(current)) +			break; +		err = -EAGAIN; +		if (!timeo) +			break; +	} +	finish_wait(sk_sleep(sk), &wait); +	*timeop = timeo; +	return err; +} +  /** - * recv_msg - receive packet-oriented message + * tipc_recvmsg - receive packet-oriented message   * @iocb: (unused)   * @m: descriptor for message info   * @buf_len: total size of user buffer area @@ -961,14 +1030,15 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,   *   * Returns size of returned message data, errno otherwise   */ -static int recv_msg(struct kiocb *iocb, struct socket *sock, -		    struct msghdr *m, size_t buf_len, int flags) +static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock, +			struct msghdr *m, size_t buf_len, int flags)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); +	struct tipc_sock *tsk = tipc_sk(sk); +	struct tipc_port *port = &tsk->port;  	struct sk_buff *buf;  	struct tipc_msg *msg; -	long timeout; +	long timeo;  	unsigned int sz;  	u32 err;  	int res; @@ -984,28 +1054,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,  		goto exit;  	} -	/* will be updated in set_orig_addr() if needed */ -	m->msg_namelen = 0; - -	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); +	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);  restart:  	/* Look for a message in receive queue; wait if necessary */ -	while (skb_queue_empty(&sk->sk_receive_queue)) { -		if (sock->state == SS_DISCONNECTING) { -			res = -ENOTCONN; -			goto exit; -		} -		if (timeout <= 0L) { -			res = timeout ? timeout : -EWOULDBLOCK; -			goto exit; -		} -		release_sock(sk); -		timeout = wait_event_interruptible_timeout(*sk_sleep(sk), -							   tipc_rx_ready(sock), -							   timeout); -		lock_sock(sk); -	} +	res = tipc_wait_for_rcvmsg(sock, &timeo); +	if (res) +		goto exit;  	/* Look at first message in receive queue */  	buf = skb_peek(&sk->sk_receive_queue); @@ -1023,7 +1078,7 @@ restart:  	set_orig_addr(m, msg);  	/* Capture ancillary data (optional) */ -	res = anc_data_recv(m, msg, tport); +	res = anc_data_recv(m, msg, port);  	if (res)  		goto exit; @@ -1049,8 +1104,8 @@ restart:  	/* Consume received message (optional) */  	if (likely(!(flags & MSG_PEEK))) {  		if ((sock->state != SS_READY) && -		    (++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) -			tipc_acknowledge(tport->ref, tport->conn_unacked); +		    (++port->conn_unacked >= TIPC_CONNACK_INTV)) +			tipc_acknowledge(port->ref, port->conn_unacked);  		advance_rx_queue(sk);  	}  exit: @@ -1059,7 +1114,7 @@ exit:  }  /** - * recv_stream - receive stream-oriented data + * tipc_recv_stream - receive stream-oriented data   * @iocb: (unused)   * @m: descriptor for message info   * @buf_len: total size of user buffer area @@ -1070,14 +1125,15 @@ exit:   *   * Returns size of returned message data, errno otherwise   */ -static int recv_stream(struct kiocb *iocb, struct socket *sock, -		       struct msghdr *m, size_t buf_len, int flags) +static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock, +			    struct msghdr *m, size_t buf_len, int flags)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); +	struct tipc_sock *tsk = tipc_sk(sk); +	struct tipc_port *port = &tsk->port;  	struct sk_buff *buf;  	struct tipc_msg *msg; -	long timeout; +	long timeo;  	unsigned int sz;  	int sz_to_copy, target, needed;  	int sz_copied = 0; @@ -1090,34 +1146,19 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,  	lock_sock(sk); -	if (unlikely((sock->state == SS_UNCONNECTED))) { +	if (unlikely(sock->state == SS_UNCONNECTED)) {  		res = -ENOTCONN;  		goto exit;  	} -	/* will be updated in set_orig_addr() if needed */ -	m->msg_namelen = 0; -  	target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); -	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); +	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);  restart:  	/* Look for a message in receive queue; wait if necessary */ -	while (skb_queue_empty(&sk->sk_receive_queue)) { -		if (sock->state == SS_DISCONNECTING) { -			res = -ENOTCONN; -			goto exit; -		} -		if (timeout <= 0L) { -			res = timeout ? timeout : -EWOULDBLOCK; -			goto exit; -		} -		release_sock(sk); -		timeout = wait_event_interruptible_timeout(*sk_sleep(sk), -							   tipc_rx_ready(sock), -							   timeout); -		lock_sock(sk); -	} +	res = tipc_wait_for_rcvmsg(sock, &timeo); +	if (res) +		goto exit;  	/* Look at first message in receive queue */  	buf = skb_peek(&sk->sk_receive_queue); @@ -1134,7 +1175,7 @@ restart:  	/* Optionally capture sender's address & ancillary data of first msg */  	if (sz_copied == 0) {  		set_orig_addr(m, msg); -		res = anc_data_recv(m, msg, tport); +		res = anc_data_recv(m, msg, port);  		if (res)  			goto exit;  	} @@ -1172,8 +1213,8 @@ restart:  	/* Consume received message (optional) */  	if (likely(!(flags & MSG_PEEK))) { -		if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) -			tipc_acknowledge(tport->ref, tport->conn_unacked); +		if (unlikely(++port->conn_unacked >= TIPC_CONNACK_INTV)) +			tipc_acknowledge(port->ref, port->conn_unacked);  		advance_rx_queue(sk);  	} @@ -1211,7 +1252,7 @@ static void tipc_write_space(struct sock *sk)   * @sk: socket   * @len: the length of messages   */ -static void tipc_data_ready(struct sock *sk, int len) +static void tipc_data_ready(struct sock *sk)  {  	struct socket_wq *wq; @@ -1225,17 +1266,19 @@ static void tipc_data_ready(struct sock *sk, int len)  /**   * filter_connect - Handle all incoming messages for a connection-based socket - * @tsock: TIPC socket + * @tsk: TIPC socket   * @msg: message   *   * Returns TIPC error status code and socket error status code   * once it encounters some errors   */ -static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) +static u32 filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)  { -	struct socket *sock = tsock->sk.sk_socket; +	struct sock *sk = &tsk->sk; +	struct tipc_port *port = &tsk->port; +	struct socket *sock = sk->sk_socket;  	struct tipc_msg *msg = buf_msg(*buf); -	struct sock *sk = &tsock->sk; +  	u32 retval = TIPC_ERR_NO_PORT;  	int res; @@ -1245,10 +1288,10 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)  	switch ((int)sock->state) {  	case SS_CONNECTED:  		/* Accept only connection-based messages sent by peer */ -		if (msg_connected(msg) && tipc_port_peer_msg(tsock->p, msg)) { +		if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) {  			if (unlikely(msg_errcode(msg))) {  				sock->state = SS_DISCONNECTING; -				__tipc_disconnect(tsock->p); +				__tipc_port_disconnect(port);  			}  			retval = TIPC_OK;  		} @@ -1265,7 +1308,7 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)  		if (unlikely(!msg_connected(msg)))  			break; -		res = auto_connect(sock, msg); +		res = auto_connect(tsk, msg);  		if (res) {  			sock->state = SS_DISCONNECTING;  			sk->sk_err = -res; @@ -1321,14 +1364,12 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)  static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)  {  	struct tipc_msg *msg = buf_msg(buf); -	unsigned int limit;  	if (msg_connected(msg)) -		limit = sysctl_tipc_rmem[2]; -	else -		limit = sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << -			msg_importance(msg); -	return limit; +		return sysctl_tipc_rmem[2]; + +	return sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << +		msg_importance(msg);  }  /** @@ -1346,6 +1387,7 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)  static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)  {  	struct socket *sock = sk->sk_socket; +	struct tipc_sock *tsk = tipc_sk(sk);  	struct tipc_msg *msg = buf_msg(buf);  	unsigned int limit = rcvbuf_limit(sk, buf);  	u32 res = TIPC_OK; @@ -1358,7 +1400,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)  		if (msg_connected(msg))  			return TIPC_ERR_NO_PORT;  	} else { -		res = filter_connect(tipc_sk(sk), &buf); +		res = filter_connect(tsk, &buf);  		if (res != TIPC_OK || buf == NULL)  			return res;  	} @@ -1368,16 +1410,16 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)  		return TIPC_ERR_OVERLOAD;  	/* Enqueue message */ -	TIPC_SKB_CB(buf)->handle = 0; +	TIPC_SKB_CB(buf)->handle = NULL;  	__skb_queue_tail(&sk->sk_receive_queue, buf);  	skb_set_owner_r(buf, sk); -	sk->sk_data_ready(sk, 0); +	sk->sk_data_ready(sk);  	return TIPC_OK;  }  /** - * backlog_rcv - handle incoming message from backlog queue + * tipc_backlog_rcv - handle incoming message from backlog queue   * @sk: socket   * @buf: message   * @@ -1385,65 +1427,100 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)   *   * Returns 0   */ -static int backlog_rcv(struct sock *sk, struct sk_buff *buf) +static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf)  {  	u32 res; +	struct tipc_sock *tsk = tipc_sk(sk); +	uint truesize = buf->truesize;  	res = filter_rcv(sk, buf); -	if (res) +	if (unlikely(res))  		tipc_reject_msg(buf, res); + +	if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) +		atomic_add(truesize, &tsk->dupl_rcvcnt); +  	return 0;  }  /** - * dispatch - handle incoming message - * @tport: TIPC port that received message - * @buf: message - * - * Called with port lock already taken. - * - * Returns TIPC error status code (TIPC_OK if message is not to be rejected) + * tipc_sk_rcv - handle incoming message + * @buf: buffer containing arriving message + * Consumes buffer + * Returns 0 if success, or errno: -EHOSTUNREACH   */ -static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) +int tipc_sk_rcv(struct sk_buff *buf)  { -	struct sock *sk = tport->sk; -	u32 res; +	struct tipc_sock *tsk; +	struct tipc_port *port; +	struct sock *sk; +	u32 dport = msg_destport(buf_msg(buf)); +	int err = TIPC_OK; +	uint limit; -	/* -	 * Process message if socket is unlocked; otherwise add to backlog queue -	 * -	 * This code is based on sk_receive_skb(), but must be distinct from it -	 * since a TIPC-specific filter/reject mechanism is utilized -	 */ +	/* Forward unresolved named message */ +	if (unlikely(!dport)) { +		tipc_net_route_msg(buf); +		return 0; +	} + +	/* Validate destination */ +	port = tipc_port_lock(dport); +	if (unlikely(!port)) { +		err = TIPC_ERR_NO_PORT; +		goto exit; +	} + +	tsk = tipc_port_to_sock(port); +	sk = &tsk->sk; + +	/* Queue message */  	bh_lock_sock(sk); +  	if (!sock_owned_by_user(sk)) { -		res = filter_rcv(sk, buf); +		err = filter_rcv(sk, buf);  	} else { -		if (sk_add_backlog(sk, buf, rcvbuf_limit(sk, buf))) -			res = TIPC_ERR_OVERLOAD; -		else -			res = TIPC_OK; +		if (sk->sk_backlog.len == 0) +			atomic_set(&tsk->dupl_rcvcnt, 0); +		limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt); +		if (sk_add_backlog(sk, buf, limit)) +			err = TIPC_ERR_OVERLOAD;  	} +  	bh_unlock_sock(sk); +	tipc_port_unlock(port); -	return res; +	if (likely(!err)) +		return 0; +exit: +	tipc_reject_msg(buf, err); +	return -EHOSTUNREACH;  } -/** - * wakeupdispatch - wake up port after congestion - * @tport: port to wakeup - * - * Called with port lock already taken. - */ -static void wakeupdispatch(struct tipc_port *tport) +static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)  { -	struct sock *sk = tport->sk; +	struct sock *sk = sock->sk; +	DEFINE_WAIT(wait); +	int done; -	sk->sk_write_space(sk); +	do { +		int err = sock_error(sk); +		if (err) +			return err; +		if (!*timeo_p) +			return -ETIMEDOUT; +		if (signal_pending(current)) +			return sock_intr_errno(*timeo_p); + +		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); +		done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); +		finish_wait(sk_sleep(sk), &wait); +	} while (!done); +	return 0;  }  /** - * connect - establish a connection to another TIPC port + * tipc_connect - establish a connection to another TIPC port   * @sock: socket structure   * @dest: socket address for destination port   * @destlen: size of socket address data structure @@ -1451,13 +1528,14 @@ static void wakeupdispatch(struct tipc_port *tport)   *   * Returns 0 on success, errno otherwise   */ -static int connect(struct socket *sock, struct sockaddr *dest, int destlen, -		   int flags) +static int tipc_connect(struct socket *sock, struct sockaddr *dest, +			int destlen, int flags)  {  	struct sock *sk = sock->sk;  	struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;  	struct msghdr m = {NULL,}; -	unsigned int timeout; +	long timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; +	socket_state previous;  	int res;  	lock_sock(sk); @@ -1479,8 +1557,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,  		goto exit;  	} -	timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; - +	previous = sock->state;  	switch (sock->state) {  	case SS_UNCONNECTED:  		/* Send a 'SYN-' to destination */ @@ -1493,7 +1570,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,  		if (!timeout)  			m.msg_flags = MSG_DONTWAIT; -		res = send_msg(NULL, sock, &m, 0); +		res = tipc_sendmsg(NULL, sock, &m, 0);  		if ((res < 0) && (res != -EWOULDBLOCK))  			goto exit; @@ -1502,56 +1579,35 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,  		 * case is EINPROGRESS, rather than EALREADY.  		 */  		res = -EINPROGRESS; -		break;  	case SS_CONNECTING: -		res = -EALREADY; +		if (previous == SS_CONNECTING) +			res = -EALREADY; +		if (!timeout) +			goto exit; +		timeout = msecs_to_jiffies(timeout); +		/* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ +		res = tipc_wait_for_connect(sock, &timeout);  		break;  	case SS_CONNECTED:  		res = -EISCONN;  		break;  	default:  		res = -EINVAL; -		goto exit; -	} - -	if (sock->state == SS_CONNECTING) { -		if (!timeout) -			goto exit; - -		/* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ -		release_sock(sk); -		res = wait_event_interruptible_timeout(*sk_sleep(sk), -				sock->state != SS_CONNECTING, -				timeout ? (long)msecs_to_jiffies(timeout) -					: MAX_SCHEDULE_TIMEOUT); -		lock_sock(sk); -		if (res <= 0) { -			if (res == 0) -				res = -ETIMEDOUT; -			else -				; /* leave "res" unchanged */ -			goto exit; -		} +		break;  	} - -	if (unlikely(sock->state == SS_DISCONNECTING)) -		res = sock_error(sk); -	else -		res = 0; -  exit:  	release_sock(sk);  	return res;  }  /** - * listen - allow socket to listen for incoming connections + * tipc_listen - allow socket to listen for incoming connections   * @sock: socket structure   * @len: (unused)   *   * Returns 0 on success, errno otherwise   */ -static int listen(struct socket *sock, int len) +static int tipc_listen(struct socket *sock, int len)  {  	struct sock *sk = sock->sk;  	int res; @@ -1569,23 +1625,59 @@ static int listen(struct socket *sock, int len)  	return res;  } +static int tipc_wait_for_accept(struct socket *sock, long timeo) +{ +	struct sock *sk = sock->sk; +	DEFINE_WAIT(wait); +	int err; + +	/* True wake-one mechanism for incoming connections: only +	 * one process gets woken up, not the 'whole herd'. +	 * Since we do not 'race & poll' for established sockets +	 * anymore, the common case will execute the loop only once. +	*/ +	for (;;) { +		prepare_to_wait_exclusive(sk_sleep(sk), &wait, +					  TASK_INTERRUPTIBLE); +		if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { +			release_sock(sk); +			timeo = schedule_timeout(timeo); +			lock_sock(sk); +		} +		err = 0; +		if (!skb_queue_empty(&sk->sk_receive_queue)) +			break; +		err = -EINVAL; +		if (sock->state != SS_LISTENING) +			break; +		err = sock_intr_errno(timeo); +		if (signal_pending(current)) +			break; +		err = -EAGAIN; +		if (!timeo) +			break; +	} +	finish_wait(sk_sleep(sk), &wait); +	return err; +} +  /** - * accept - wait for connection request + * tipc_accept - wait for connection request   * @sock: listening socket   * @newsock: new socket that is to be connected   * @flags: file-related flags associated with socket   *   * Returns 0 on success, errno otherwise   */ -static int accept(struct socket *sock, struct socket *new_sock, int flags) +static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)  {  	struct sock *new_sk, *sk = sock->sk;  	struct sk_buff *buf; -	struct tipc_sock *new_tsock; -	struct tipc_port *new_tport; +	struct tipc_port *new_port;  	struct tipc_msg *msg; +	struct tipc_portid peer;  	u32 new_ref; - +	long timeo;  	int res;  	lock_sock(sk); @@ -1594,19 +1686,10 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)  		res = -EINVAL;  		goto exit;  	} - -	while (skb_queue_empty(&sk->sk_receive_queue)) { -		if (flags & O_NONBLOCK) { -			res = -EWOULDBLOCK; -			goto exit; -		} -		release_sock(sk); -		res = wait_event_interruptible(*sk_sleep(sk), -				(!skb_queue_empty(&sk->sk_receive_queue))); -		lock_sock(sk); -		if (res) -			goto exit; -	} +	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); +	res = tipc_wait_for_accept(sock, timeo); +	if (res) +		goto exit;  	buf = skb_peek(&sk->sk_receive_queue); @@ -1615,9 +1698,8 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)  		goto exit;  	new_sk = new_sock->sk; -	new_tsock = tipc_sk(new_sk); -	new_tport = new_tsock->p; -	new_ref = new_tport->ref; +	new_port = &tipc_sk(new_sk)->port; +	new_ref = new_port->ref;  	msg = buf_msg(buf);  	/* we lock on new_sk; but lockdep sees the lock on sk */ @@ -1630,15 +1712,15 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)  	reject_rx_queue(new_sk);  	/* Connect new socket to it's peer */ -	new_tsock->peer_name.ref = msg_origport(msg); -	new_tsock->peer_name.node = msg_orignode(msg); -	tipc_connect(new_ref, &new_tsock->peer_name); +	peer.ref = msg_origport(msg); +	peer.node = msg_orignode(msg); +	tipc_port_connect(new_ref, &peer);  	new_sock->state = SS_CONNECTED; -	tipc_set_portimportance(new_ref, msg_importance(msg)); +	tipc_port_set_importance(new_port, msg_importance(msg));  	if (msg_named(msg)) { -		new_tport->conn_type = msg_nametype(msg); -		new_tport->conn_instance = msg_nameinst(msg); +		new_port->conn_type = msg_nametype(msg); +		new_port->conn_instance = msg_nameinst(msg);  	}  	/* @@ -1649,21 +1731,20 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)  		struct msghdr m = {NULL,};  		advance_rx_queue(sk); -		send_packet(NULL, new_sock, &m, 0); +		tipc_send_packet(NULL, new_sock, &m, 0);  	} else {  		__skb_dequeue(&sk->sk_receive_queue);  		__skb_queue_head(&new_sk->sk_receive_queue, buf);  		skb_set_owner_r(buf, new_sk);  	}  	release_sock(new_sk); -  exit:  	release_sock(sk);  	return res;  }  /** - * shutdown - shutdown socket connection + * tipc_shutdown - shutdown socket connection   * @sock: socket structure   * @how: direction to close (must be SHUT_RDWR)   * @@ -1671,10 +1752,11 @@ exit:   *   * Returns 0 on success, errno otherwise   */ -static int shutdown(struct socket *sock, int how) +static int tipc_shutdown(struct socket *sock, int how)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); +	struct tipc_sock *tsk = tipc_sk(sk); +	struct tipc_port *port = &tsk->port;  	struct sk_buff *buf;  	int res; @@ -1691,14 +1773,14 @@ restart:  		/* Disconnect and send a 'FIN+' or 'FIN-' message to peer */  		buf = __skb_dequeue(&sk->sk_receive_queue);  		if (buf) { -			if (TIPC_SKB_CB(buf)->handle != 0) { +			if (TIPC_SKB_CB(buf)->handle != NULL) {  				kfree_skb(buf);  				goto restart;  			} -			tipc_disconnect(tport->ref); +			tipc_port_disconnect(port->ref);  			tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN);  		} else { -			tipc_shutdown(tport->ref); +			tipc_port_shutdown(port->ref);  		}  		sock->state = SS_DISCONNECTING; @@ -1724,7 +1806,7 @@ restart:  }  /** - * setsockopt - set socket option + * tipc_setsockopt - set socket option   * @sock: socket structure   * @lvl: option level   * @opt: option identifier @@ -1736,11 +1818,12 @@ restart:   *   * Returns 0 on success, errno otherwise   */ -static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov, -		      unsigned int ol) +static int tipc_setsockopt(struct socket *sock, int lvl, int opt, +			   char __user *ov, unsigned int ol)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); +	struct tipc_sock *tsk = tipc_sk(sk); +	struct tipc_port *port = &tsk->port;  	u32 value;  	int res; @@ -1758,16 +1841,16 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,  	switch (opt) {  	case TIPC_IMPORTANCE: -		res = tipc_set_portimportance(tport->ref, value); +		tipc_port_set_importance(port, value);  		break;  	case TIPC_SRC_DROPPABLE:  		if (sock->type != SOCK_STREAM) -			res = tipc_set_portunreliable(tport->ref, value); +			tipc_port_set_unreliable(port, value);  		else  			res = -ENOPROTOOPT;  		break;  	case TIPC_DEST_DROPPABLE: -		res = tipc_set_portunreturnable(tport->ref, value); +		tipc_port_set_unreturnable(port, value);  		break;  	case TIPC_CONN_TIMEOUT:  		tipc_sk(sk)->conn_timeout = value; @@ -1783,7 +1866,7 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,  }  /** - * getsockopt - get socket option + * tipc_getsockopt - get socket option   * @sock: socket structure   * @lvl: option level   * @opt: option identifier @@ -1795,11 +1878,12 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,   *   * Returns 0 on success, errno otherwise   */ -static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov, -		      int __user *ol) +static int tipc_getsockopt(struct socket *sock, int lvl, int opt, +			   char __user *ov, int __user *ol)  {  	struct sock *sk = sock->sk; -	struct tipc_port *tport = tipc_sk_port(sk); +	struct tipc_sock *tsk = tipc_sk(sk); +	struct tipc_port *port = &tsk->port;  	int len;  	u32 value;  	int res; @@ -1816,13 +1900,13 @@ static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov,  	switch (opt) {  	case TIPC_IMPORTANCE: -		res = tipc_portimportance(tport->ref, &value); +		value = tipc_port_importance(port);  		break;  	case TIPC_SRC_DROPPABLE: -		res = tipc_portunreliable(tport->ref, &value); +		value = tipc_port_unreliable(port);  		break;  	case TIPC_DEST_DROPPABLE: -		res = tipc_portunreturnable(tport->ref, &value); +		value = tipc_port_unreturnable(port);  		break;  	case TIPC_CONN_TIMEOUT:  		value = tipc_sk(sk)->conn_timeout; @@ -1852,25 +1936,47 @@ static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov,  	return put_user(sizeof(value), ol);  } +int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) +{ +	struct tipc_sioc_ln_req lnr; +	void __user *argp = (void __user *)arg; + +	switch (cmd) { +	case SIOCGETLINKNAME: +		if (copy_from_user(&lnr, argp, sizeof(lnr))) +			return -EFAULT; +		if (!tipc_node_get_linkname(lnr.bearer_id, lnr.peer, +					    lnr.linkname, TIPC_MAX_LINK_NAME)) { +			if (copy_to_user(argp, &lnr, sizeof(lnr))) +				return -EFAULT; +			return 0; +		} +		return -EADDRNOTAVAIL; +		break; +	default: +		return -ENOIOCTLCMD; +	} +} +  /* Protocol switches for the various types of TIPC sockets */  static const struct proto_ops msg_ops = {  	.owner		= THIS_MODULE,  	.family		= AF_TIPC, -	.release	= release, -	.bind		= bind, -	.connect	= connect, +	.release	= tipc_release, +	.bind		= tipc_bind, +	.connect	= tipc_connect,  	.socketpair	= sock_no_socketpair,  	.accept		= sock_no_accept, -	.getname	= get_name, -	.poll		= poll, -	.ioctl		= sock_no_ioctl, +	.getname	= tipc_getname, +	.poll		= tipc_poll, +	.ioctl		= tipc_ioctl,  	.listen		= sock_no_listen, -	.shutdown	= shutdown, -	.setsockopt	= setsockopt, -	.getsockopt	= getsockopt, -	.sendmsg	= send_msg, -	.recvmsg	= recv_msg, +	.shutdown	= tipc_shutdown, +	.setsockopt	= tipc_setsockopt, +	.getsockopt	= tipc_getsockopt, +	.sendmsg	= tipc_sendmsg, +	.recvmsg	= tipc_recvmsg,  	.mmap		= sock_no_mmap,  	.sendpage	= sock_no_sendpage  }; @@ -1878,20 +1984,20 @@ static const struct proto_ops msg_ops = {  static const struct proto_ops packet_ops = {  	.owner		= THIS_MODULE,  	.family		= AF_TIPC, -	.release	= release, -	.bind		= bind, -	.connect	= connect, +	.release	= tipc_release, +	.bind		= tipc_bind, +	.connect	= tipc_connect,  	.socketpair	= sock_no_socketpair, -	.accept		= accept, -	.getname	= get_name, -	.poll		= poll, -	.ioctl		= sock_no_ioctl, -	.listen		= listen, -	.shutdown	= shutdown, -	.setsockopt	= setsockopt, -	.getsockopt	= getsockopt, -	.sendmsg	= send_packet, -	.recvmsg	= recv_msg, +	.accept		= tipc_accept, +	.getname	= tipc_getname, +	.poll		= tipc_poll, +	.ioctl		= tipc_ioctl, +	.listen		= tipc_listen, +	.shutdown	= tipc_shutdown, +	.setsockopt	= tipc_setsockopt, +	.getsockopt	= tipc_getsockopt, +	.sendmsg	= tipc_send_packet, +	.recvmsg	= tipc_recvmsg,  	.mmap		= sock_no_mmap,  	.sendpage	= sock_no_sendpage  }; @@ -1899,20 +2005,20 @@ static const struct proto_ops packet_ops = {  static const struct proto_ops stream_ops = {  	.owner		= THIS_MODULE,  	.family		= AF_TIPC, -	.release	= release, -	.bind		= bind, -	.connect	= connect, +	.release	= tipc_release, +	.bind		= tipc_bind, +	.connect	= tipc_connect,  	.socketpair	= sock_no_socketpair, -	.accept		= accept, -	.getname	= get_name, -	.poll		= poll, -	.ioctl		= sock_no_ioctl, -	.listen		= listen, -	.shutdown	= shutdown, -	.setsockopt	= setsockopt, -	.getsockopt	= getsockopt, -	.sendmsg	= send_stream, -	.recvmsg	= recv_stream, +	.accept		= tipc_accept, +	.getname	= tipc_getname, +	.poll		= tipc_poll, +	.ioctl		= tipc_ioctl, +	.listen		= tipc_listen, +	.shutdown	= tipc_shutdown, +	.setsockopt	= tipc_setsockopt, +	.getsockopt	= tipc_getsockopt, +	.sendmsg	= tipc_send_stream, +	.recvmsg	= tipc_recv_stream,  	.mmap		= sock_no_mmap,  	.sendpage	= sock_no_sendpage  }; @@ -1957,8 +2063,6 @@ int tipc_socket_init(void)  		proto_unregister(&tipc_proto);  		goto out;  	} - -	sockets_enabled = 1;   out:  	return res;  } @@ -1968,10 +2072,6 @@ int tipc_socket_init(void)   */  void tipc_socket_stop(void)  { -	if (!sockets_enabled) -		return; - -	sockets_enabled = 0;  	sock_unregister(tipc_family_ops.family);  	proto_unregister(&tipc_proto);  }  | 
