aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2018-05-20 04:39:10 -0400
committerDavid S. Miller <davem@davemloft.net>2018-05-22 13:37:26 -0400
commit644fbdeacf1d3edd366e44b8ba214de9d1dd66a9 (patch)
tree53b64f45a8799966c7ea61dde150e14e9bc1e4f4 /net/sctp/socket.c
parent6741c4bb389da103c0d79ad1961884628900bfe6 (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.c51
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 */
1087static int __sctp_connect(struct sock *sk, 1087static 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
1372out_free: 1371out_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 */
4399static int sctp_connect(struct sock *sk, struct sockaddr *addr, 4398static 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
4434int 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. */
4426static int sctp_disconnect(struct sock *sk, int flags) 4447static 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,