forked from mirrors/linux
		
	sctp: fix the issue that flags are ignored when using kernel_connect
Now sctp uses inet_dgram_connect as its proto_ops .connect, and the flags param can't be passed into its proto .connect where this flags is really needed. sctp works around it by getting flags from socket file in __sctp_connect. It works for connecting from userspace, as inherently the user sock has socket file and it passes f_flags as the flags param into the proto_ops .connect. However, the sock created by sock_create_kern doesn't have a socket file, and it passes the flags (like O_NONBLOCK) by using the flags param in kernel_connect, which calls proto_ops .connect later. So to fix it, this patch defines a new proto_ops .connect for sctp, sctp_inet_connect, which calls __sctp_connect() directly with this flags param. After this, the sctp's proto .connect can be removed. Note that sctp_inet_connect doesn't need to do some checks that are not needed for sctp, which makes thing better than with inet_dgram_connect. Suggested-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Reviewed-by: Michal Kubecek <mkubecek@suse.cz> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									6741c4bb38
								
							
						
					
					
						commit
						644fbdeacf
					
				
					 4 changed files with 39 additions and 18 deletions
				
			
		| 
						 | 
					@ -103,6 +103,8 @@ void sctp_addr_wq_mgmt(struct net *, struct sctp_sockaddr_entry *, int);
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * sctp/socket.c
 | 
					 * sctp/socket.c
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
 | 
				
			||||||
 | 
							      int addr_len, int flags);
 | 
				
			||||||
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 | 
					int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 | 
				
			||||||
int sctp_inet_listen(struct socket *sock, int backlog);
 | 
					int sctp_inet_listen(struct socket *sock, int backlog);
 | 
				
			||||||
void sctp_write_space(struct sock *sk);
 | 
					void sctp_write_space(struct sock *sk);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1006,7 +1006,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
 | 
				
			||||||
	.owner		   = THIS_MODULE,
 | 
						.owner		   = THIS_MODULE,
 | 
				
			||||||
	.release	   = inet6_release,
 | 
						.release	   = inet6_release,
 | 
				
			||||||
	.bind		   = inet6_bind,
 | 
						.bind		   = inet6_bind,
 | 
				
			||||||
	.connect	   = inet_dgram_connect,
 | 
						.connect	   = sctp_inet_connect,
 | 
				
			||||||
	.socketpair	   = sock_no_socketpair,
 | 
						.socketpair	   = sock_no_socketpair,
 | 
				
			||||||
	.accept		   = inet_accept,
 | 
						.accept		   = inet_accept,
 | 
				
			||||||
	.getname	   = sctp_getname,
 | 
						.getname	   = sctp_getname,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1012,7 +1012,7 @@ static const struct proto_ops inet_seqpacket_ops = {
 | 
				
			||||||
	.owner		   = THIS_MODULE,
 | 
						.owner		   = THIS_MODULE,
 | 
				
			||||||
	.release	   = inet_release,	/* Needs to be wrapped... */
 | 
						.release	   = inet_release,	/* Needs to be wrapped... */
 | 
				
			||||||
	.bind		   = inet_bind,
 | 
						.bind		   = inet_bind,
 | 
				
			||||||
	.connect	   = inet_dgram_connect,
 | 
						.connect	   = sctp_inet_connect,
 | 
				
			||||||
	.socketpair	   = sock_no_socketpair,
 | 
						.socketpair	   = sock_no_socketpair,
 | 
				
			||||||
	.accept		   = inet_accept,
 | 
						.accept		   = inet_accept,
 | 
				
			||||||
	.getname	   = inet_getname,	/* Semantics are different.  */
 | 
						.getname	   = inet_getname,	/* Semantics are different.  */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1086,7 +1086,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int __sctp_connect(struct sock *sk,
 | 
					static int __sctp_connect(struct sock *sk,
 | 
				
			||||||
			  struct sockaddr *kaddrs,
 | 
								  struct sockaddr *kaddrs,
 | 
				
			||||||
			  int addrs_size,
 | 
								  int addrs_size, int flags,
 | 
				
			||||||
			  sctp_assoc_t *assoc_id)
 | 
								  sctp_assoc_t *assoc_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net *net = sock_net(sk);
 | 
						struct net *net = sock_net(sk);
 | 
				
			||||||
| 
						 | 
					@ -1104,7 +1104,6 @@ static int __sctp_connect(struct sock *sk,
 | 
				
			||||||
	union sctp_addr *sa_addr = NULL;
 | 
						union sctp_addr *sa_addr = NULL;
 | 
				
			||||||
	void *addr_buf;
 | 
						void *addr_buf;
 | 
				
			||||||
	unsigned short port;
 | 
						unsigned short port;
 | 
				
			||||||
	unsigned int f_flags = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sp = sctp_sk(sk);
 | 
						sp = sctp_sk(sk);
 | 
				
			||||||
	ep = sp->ep;
 | 
						ep = sp->ep;
 | 
				
			||||||
| 
						 | 
					@ -1254,13 +1253,7 @@ static int __sctp_connect(struct sock *sk,
 | 
				
			||||||
	sp->pf->to_sk_daddr(sa_addr, sk);
 | 
						sp->pf->to_sk_daddr(sa_addr, sk);
 | 
				
			||||||
	sk->sk_err = 0;
 | 
						sk->sk_err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* in-kernel sockets don't generally have a file allocated to them
 | 
						timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
 | 
				
			||||||
	 * if all they do is call sock_create_kern().
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (sk->sk_socket->file)
 | 
					 | 
				
			||||||
		f_flags = sk->sk_socket->file->f_flags;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (assoc_id)
 | 
						if (assoc_id)
 | 
				
			||||||
		*assoc_id = asoc->assoc_id;
 | 
							*assoc_id = asoc->assoc_id;
 | 
				
			||||||
| 
						 | 
					@ -1348,7 +1341,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
 | 
				
			||||||
				      sctp_assoc_t *assoc_id)
 | 
									      sctp_assoc_t *assoc_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sockaddr *kaddrs;
 | 
						struct sockaddr *kaddrs;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0, flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
 | 
						pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
 | 
				
			||||||
		 __func__, sk, addrs, addrs_size);
 | 
							 __func__, sk, addrs, addrs_size);
 | 
				
			||||||
| 
						 | 
					@ -1367,7 +1360,13 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out_free;
 | 
							goto out_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
 | 
						/* in-kernel sockets don't generally have a file allocated to them
 | 
				
			||||||
 | 
						 * if all they do is call sock_create_kern().
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (sk->sk_socket->file)
 | 
				
			||||||
 | 
							flags = sk->sk_socket->file->f_flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_free:
 | 
					out_free:
 | 
				
			||||||
	kvfree(kaddrs);
 | 
						kvfree(kaddrs);
 | 
				
			||||||
| 
						 | 
					@ -4397,16 +4396,26 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
 * len: the size of the address.
 | 
					 * len: the size of the address.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int sctp_connect(struct sock *sk, struct sockaddr *addr,
 | 
					static int sctp_connect(struct sock *sk, struct sockaddr *addr,
 | 
				
			||||||
			int addr_len)
 | 
								int addr_len, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err = 0;
 | 
						struct inet_sock *inet = inet_sk(sk);
 | 
				
			||||||
	struct sctp_af *af;
 | 
						struct sctp_af *af;
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lock_sock(sk);
 | 
						lock_sock(sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
 | 
						pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
 | 
				
			||||||
		 addr, addr_len);
 | 
							 addr, addr_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We may need to bind the socket. */
 | 
				
			||||||
 | 
						if (!inet->inet_num) {
 | 
				
			||||||
 | 
							if (sk->sk_prot->get_port(sk, 0)) {
 | 
				
			||||||
 | 
								release_sock(sk);
 | 
				
			||||||
 | 
								return -EAGAIN;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							inet->inet_sport = htons(inet->inet_num);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Validate addr_len before calling common connect/connectx routine. */
 | 
						/* Validate addr_len before calling common connect/connectx routine. */
 | 
				
			||||||
	af = sctp_get_af_specific(addr->sa_family);
 | 
						af = sctp_get_af_specific(addr->sa_family);
 | 
				
			||||||
	if (!af || addr_len < af->sockaddr_len) {
 | 
						if (!af || addr_len < af->sockaddr_len) {
 | 
				
			||||||
| 
						 | 
					@ -4415,13 +4424,25 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr,
 | 
				
			||||||
		/* Pass correct addr len to common routine (so it knows there
 | 
							/* Pass correct addr len to common routine (so it knows there
 | 
				
			||||||
		 * is only one address being passed.
 | 
							 * is only one address being passed.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);
 | 
							err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	release_sock(sk);
 | 
						release_sock(sk);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
 | 
				
			||||||
 | 
							      int addr_len, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (addr_len < sizeof(uaddr->sa_family))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (uaddr->sa_family == AF_UNSPEC)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sctp_connect(sock->sk, uaddr, addr_len, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* FIXME: Write comments. */
 | 
					/* FIXME: Write comments. */
 | 
				
			||||||
static int sctp_disconnect(struct sock *sk, int flags)
 | 
					static int sctp_disconnect(struct sock *sk, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -8724,7 +8745,6 @@ struct proto sctp_prot = {
 | 
				
			||||||
	.name        =	"SCTP",
 | 
						.name        =	"SCTP",
 | 
				
			||||||
	.owner       =	THIS_MODULE,
 | 
						.owner       =	THIS_MODULE,
 | 
				
			||||||
	.close       =	sctp_close,
 | 
						.close       =	sctp_close,
 | 
				
			||||||
	.connect     =	sctp_connect,
 | 
					 | 
				
			||||||
	.disconnect  =	sctp_disconnect,
 | 
						.disconnect  =	sctp_disconnect,
 | 
				
			||||||
	.accept      =	sctp_accept,
 | 
						.accept      =	sctp_accept,
 | 
				
			||||||
	.ioctl       =	sctp_ioctl,
 | 
						.ioctl       =	sctp_ioctl,
 | 
				
			||||||
| 
						 | 
					@ -8767,7 +8787,6 @@ struct proto sctpv6_prot = {
 | 
				
			||||||
	.name		= "SCTPv6",
 | 
						.name		= "SCTPv6",
 | 
				
			||||||
	.owner		= THIS_MODULE,
 | 
						.owner		= THIS_MODULE,
 | 
				
			||||||
	.close		= sctp_close,
 | 
						.close		= sctp_close,
 | 
				
			||||||
	.connect	= sctp_connect,
 | 
					 | 
				
			||||||
	.disconnect	= sctp_disconnect,
 | 
						.disconnect	= sctp_disconnect,
 | 
				
			||||||
	.accept		= sctp_accept,
 | 
						.accept		= sctp_accept,
 | 
				
			||||||
	.ioctl		= sctp_ioctl,
 | 
						.ioctl		= sctp_ioctl,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue