Commit 644fbdea authored by Xin Long's avatar Xin Long Committed by David S. Miller

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: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Acked-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Reviewed-by: default avatarMichal Kubecek <mkubecek@suse.cz>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6741c4bb
...@@ -103,6 +103,8 @@ void sctp_addr_wq_mgmt(struct net *, struct sctp_sockaddr_entry *, int); ...@@ -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 = { ...@@ -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 = { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 = { ...@@ -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 = { ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment