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/sctp/socket.c | |
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/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 51 |
1 files changed, 35 insertions, 16 deletions
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, |