diff options
| author | Xin Long <lucien.xin@gmail.com> | 2018-05-20 04:39:10 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2018-05-22 13:37:26 -0400 |
| commit | 644fbdeacf1d3edd366e44b8ba214de9d1dd66a9 (patch) | |
| tree | 53b64f45a8799966c7ea61dde150e14e9bc1e4f4 /net | |
| parent | 6741c4bb389da103c0d79ad1961884628900bfe6 (diff) | |
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>
Diffstat (limited to 'net')
| -rw-r--r-- | net/sctp/ipv6.c | 2 | ||||
| -rw-r--r-- | net/sctp/protocol.c | 2 | ||||
| -rw-r--r-- | net/sctp/socket.c | 51 |
3 files changed, 37 insertions, 18 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 42247110d842..0cd2e764f47f 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
| @@ -1006,7 +1006,7 @@ static const struct proto_ops inet6_seqpacket_ops = { | |||
| 1006 | .owner = THIS_MODULE, | 1006 | .owner = THIS_MODULE, |
| 1007 | .release = inet6_release, | 1007 | .release = inet6_release, |
| 1008 | .bind = inet6_bind, | 1008 | .bind = inet6_bind, |
| 1009 | .connect = inet_dgram_connect, | 1009 | .connect = sctp_inet_connect, |
| 1010 | .socketpair = sock_no_socketpair, | 1010 | .socketpair = sock_no_socketpair, |
| 1011 | .accept = inet_accept, | 1011 | .accept = inet_accept, |
| 1012 | .getname = sctp_getname, | 1012 | .getname = sctp_getname, |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d685f8456762..6bf0a9971888 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
| @@ -1012,7 +1012,7 @@ static const struct proto_ops inet_seqpacket_ops = { | |||
| 1012 | .owner = THIS_MODULE, | 1012 | .owner = THIS_MODULE, |
| 1013 | .release = inet_release, /* Needs to be wrapped... */ | 1013 | .release = inet_release, /* Needs to be wrapped... */ |
| 1014 | .bind = inet_bind, | 1014 | .bind = inet_bind, |
| 1015 | .connect = inet_dgram_connect, | 1015 | .connect = sctp_inet_connect, |
| 1016 | .socketpair = sock_no_socketpair, | 1016 | .socketpair = sock_no_socketpair, |
| 1017 | .accept = inet_accept, | 1017 | .accept = inet_accept, |
| 1018 | .getname = inet_getname, /* Semantics are different. */ | 1018 | .getname = inet_getname, /* Semantics are different. */ |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 80835ac26d2c..ae7e7c606f72 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -1086,7 +1086,7 @@ out: | |||
| 1086 | */ | 1086 | */ |
| 1087 | static int __sctp_connect(struct sock *sk, | 1087 | static int __sctp_connect(struct sock *sk, |
| 1088 | struct sockaddr *kaddrs, | 1088 | struct sockaddr *kaddrs, |
| 1089 | int addrs_size, | 1089 | int addrs_size, int flags, |
| 1090 | sctp_assoc_t *assoc_id) | 1090 | sctp_assoc_t *assoc_id) |
| 1091 | { | 1091 | { |
| 1092 | struct net *net = sock_net(sk); | 1092 | struct net *net = sock_net(sk); |
| @@ -1104,7 +1104,6 @@ static int __sctp_connect(struct sock *sk, | |||
| 1104 | union sctp_addr *sa_addr = NULL; | 1104 | union sctp_addr *sa_addr = NULL; |
| 1105 | void *addr_buf; | 1105 | void *addr_buf; |
| 1106 | unsigned short port; | 1106 | unsigned short port; |
| 1107 | unsigned int f_flags = 0; | ||
| 1108 | 1107 | ||
| 1109 | sp = sctp_sk(sk); | 1108 | sp = sctp_sk(sk); |
| 1110 | ep = sp->ep; | 1109 | ep = sp->ep; |
| @@ -1254,13 +1253,7 @@ static int __sctp_connect(struct sock *sk, | |||
| 1254 | sp->pf->to_sk_daddr(sa_addr, sk); | 1253 | sp->pf->to_sk_daddr(sa_addr, sk); |
| 1255 | sk->sk_err = 0; | 1254 | sk->sk_err = 0; |
| 1256 | 1255 | ||
| 1257 | /* in-kernel sockets don't generally have a file allocated to them | 1256 | timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); |
| 1258 | * if all they do is call sock_create_kern(). | ||
| 1259 | */ | ||
| 1260 | if (sk->sk_socket->file) | ||
| 1261 | f_flags = sk->sk_socket->file->f_flags; | ||
| 1262 | |||
| 1263 | timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); | ||
| 1264 | 1257 | ||
| 1265 | if (assoc_id) | 1258 | if (assoc_id) |
| 1266 | *assoc_id = asoc->assoc_id; | 1259 | *assoc_id = asoc->assoc_id; |
| @@ -1348,7 +1341,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk, | |||
| 1348 | sctp_assoc_t *assoc_id) | 1341 | sctp_assoc_t *assoc_id) |
| 1349 | { | 1342 | { |
| 1350 | struct sockaddr *kaddrs; | 1343 | struct sockaddr *kaddrs; |
| 1351 | int err = 0; | 1344 | int err = 0, flags = 0; |
| 1352 | 1345 | ||
| 1353 | pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", | 1346 | pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", |
| 1354 | __func__, sk, addrs, addrs_size); | 1347 | __func__, sk, addrs, addrs_size); |
| @@ -1367,7 +1360,13 @@ static int __sctp_setsockopt_connectx(struct sock *sk, | |||
| 1367 | if (err) | 1360 | if (err) |
| 1368 | goto out_free; | 1361 | goto out_free; |
| 1369 | 1362 | ||
| 1370 | err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); | 1363 | /* in-kernel sockets don't generally have a file allocated to them |
| 1364 | * if all they do is call sock_create_kern(). | ||
| 1365 | */ | ||
| 1366 | if (sk->sk_socket->file) | ||
| 1367 | flags = sk->sk_socket->file->f_flags; | ||
| 1368 | |||
| 1369 | err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id); | ||
| 1371 | 1370 | ||
| 1372 | out_free: | 1371 | out_free: |
| 1373 | kvfree(kaddrs); | 1372 | kvfree(kaddrs); |
| @@ -4397,16 +4396,26 @@ out_nounlock: | |||
| 4397 | * len: the size of the address. | 4396 | * len: the size of the address. |
| 4398 | */ | 4397 | */ |
| 4399 | static int sctp_connect(struct sock *sk, struct sockaddr *addr, | 4398 | static int sctp_connect(struct sock *sk, struct sockaddr *addr, |
| 4400 | int addr_len) | 4399 | int addr_len, int flags) |
| 4401 | { | 4400 | { |
| 4402 | int err = 0; | 4401 | struct inet_sock *inet = inet_sk(sk); |
| 4403 | struct sctp_af *af; | 4402 | struct sctp_af *af; |
| 4403 | int err = 0; | ||
| 4404 | 4404 | ||
| 4405 | lock_sock(sk); | 4405 | lock_sock(sk); |
| 4406 | 4406 | ||
| 4407 | pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, | 4407 | pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, |
| 4408 | addr, addr_len); | 4408 | addr, addr_len); |
| 4409 | 4409 | ||
| 4410 | /* We may need to bind the socket. */ | ||
| 4411 | if (!inet->inet_num) { | ||
| 4412 | if (sk->sk_prot->get_port(sk, 0)) { | ||
| 4413 | release_sock(sk); | ||
| 4414 | return -EAGAIN; | ||
| 4415 | } | ||
| 4416 | inet->inet_sport = htons(inet->inet_num); | ||
| 4417 | } | ||
| 4418 | |||
| 4410 | /* Validate addr_len before calling common connect/connectx routine. */ | 4419 | /* Validate addr_len before calling common connect/connectx routine. */ |
| 4411 | af = sctp_get_af_specific(addr->sa_family); | 4420 | af = sctp_get_af_specific(addr->sa_family); |
| 4412 | if (!af || addr_len < af->sockaddr_len) { | 4421 | if (!af || addr_len < af->sockaddr_len) { |
| @@ -4415,13 +4424,25 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr, | |||
| 4415 | /* Pass correct addr len to common routine (so it knows there | 4424 | /* Pass correct addr len to common routine (so it knows there |
| 4416 | * is only one address being passed. | 4425 | * is only one address being passed. |
| 4417 | */ | 4426 | */ |
| 4418 | err = __sctp_connect(sk, addr, af->sockaddr_len, NULL); | 4427 | err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL); |
| 4419 | } | 4428 | } |
| 4420 | 4429 | ||
| 4421 | release_sock(sk); | 4430 | release_sock(sk); |
| 4422 | return err; | 4431 | return err; |
| 4423 | } | 4432 | } |
| 4424 | 4433 | ||
| 4434 | int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr, | ||
| 4435 | int addr_len, int flags) | ||
| 4436 | { | ||
| 4437 | if (addr_len < sizeof(uaddr->sa_family)) | ||
| 4438 | return -EINVAL; | ||
| 4439 | |||
| 4440 | if (uaddr->sa_family == AF_UNSPEC) | ||
| 4441 | return -EOPNOTSUPP; | ||
| 4442 | |||
| 4443 | return sctp_connect(sock->sk, uaddr, addr_len, flags); | ||
| 4444 | } | ||
| 4445 | |||
| 4425 | /* FIXME: Write comments. */ | 4446 | /* FIXME: Write comments. */ |
| 4426 | static int sctp_disconnect(struct sock *sk, int flags) | 4447 | static int sctp_disconnect(struct sock *sk, int flags) |
| 4427 | { | 4448 | { |
| @@ -8724,7 +8745,6 @@ struct proto sctp_prot = { | |||
| 8724 | .name = "SCTP", | 8745 | .name = "SCTP", |
| 8725 | .owner = THIS_MODULE, | 8746 | .owner = THIS_MODULE, |
| 8726 | .close = sctp_close, | 8747 | .close = sctp_close, |
| 8727 | .connect = sctp_connect, | ||
| 8728 | .disconnect = sctp_disconnect, | 8748 | .disconnect = sctp_disconnect, |
| 8729 | .accept = sctp_accept, | 8749 | .accept = sctp_accept, |
| 8730 | .ioctl = sctp_ioctl, | 8750 | .ioctl = sctp_ioctl, |
| @@ -8767,7 +8787,6 @@ struct proto sctpv6_prot = { | |||
| 8767 | .name = "SCTPv6", | 8787 | .name = "SCTPv6", |
| 8768 | .owner = THIS_MODULE, | 8788 | .owner = THIS_MODULE, |
| 8769 | .close = sctp_close, | 8789 | .close = sctp_close, |
| 8770 | .connect = sctp_connect, | ||
| 8771 | .disconnect = sctp_disconnect, | 8790 | .disconnect = sctp_disconnect, |
| 8772 | .accept = sctp_accept, | 8791 | .accept = sctp_accept, |
| 8773 | .ioctl = sctp_ioctl, | 8792 | .ioctl = sctp_ioctl, |
