| From 34c0e3f43720e810af35a8e5a1b2dfd74e74726b Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 22 Jul 2021 12:05:41 -0400 |
| Subject: tipc: fix implicit-connect for SYN+ |
| |
| From: Xin Long <lucien.xin@gmail.com> |
| |
| [ Upstream commit f8dd60de194817c86bf812700980762bb5a8d9a4 ] |
| |
| For implicit-connect, when it's either SYN- or SYN+, an ACK should |
| be sent back to the client immediately. It's not appropriate for |
| the client to enter established state only after receiving data |
| from the server. |
| |
| On client side, after the SYN is sent out, tipc_wait_for_connect() |
| should be called to wait for the ACK if timeout is set. |
| |
| This patch also restricts __tipc_sendstream() to call __sendmsg() |
| only when it's in TIPC_OPEN state, so that the client can program |
| in a single loop doing both connecting and data sending like: |
| |
| for (...) |
| sendmsg(dest, buf); |
| |
| This makes the implicit-connect more implicit. |
| |
| Fixes: b97bf3fd8f6a ("[TIPC] Initial merge") |
| Signed-off-by: Xin Long <lucien.xin@gmail.com> |
| Acked-by: Jon Maloy <jmaloy@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/tipc/socket.c | 21 +++++++++++++-------- |
| 1 file changed, 13 insertions(+), 8 deletions(-) |
| |
| diff --git a/net/tipc/socket.c b/net/tipc/socket.c |
| index 9f7cc9e1e4ef..694c432b9710 100644 |
| --- a/net/tipc/socket.c |
| +++ b/net/tipc/socket.c |
| @@ -148,6 +148,7 @@ static void tipc_sk_remove(struct tipc_sock *tsk); |
| static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz); |
| static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz); |
| static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack); |
| +static int tipc_wait_for_connect(struct socket *sock, long *timeo_p); |
| |
| static const struct proto_ops packet_ops; |
| static const struct proto_ops stream_ops; |
| @@ -1508,8 +1509,13 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) |
| rc = 0; |
| } |
| |
| - if (unlikely(syn && !rc)) |
| + if (unlikely(syn && !rc)) { |
| tipc_set_sk_state(sk, TIPC_CONNECTING); |
| + if (timeout) { |
| + timeout = msecs_to_jiffies(timeout); |
| + tipc_wait_for_connect(sock, &timeout); |
| + } |
| + } |
| |
| return rc ? rc : dlen; |
| } |
| @@ -1557,7 +1563,7 @@ static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen) |
| return -EMSGSIZE; |
| |
| /* Handle implicit connection setup */ |
| - if (unlikely(dest)) { |
| + if (unlikely(dest && sk->sk_state == TIPC_OPEN)) { |
| rc = __tipc_sendmsg(sock, m, dlen); |
| if (dlen && dlen == rc) { |
| tsk->peer_caps = tipc_node_get_capabilities(net, dnode); |
| @@ -2686,9 +2692,10 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags, |
| bool kern) |
| { |
| struct sock *new_sk, *sk = sock->sk; |
| - struct sk_buff *buf; |
| struct tipc_sock *new_tsock; |
| + struct msghdr m = {NULL,}; |
| struct tipc_msg *msg; |
| + struct sk_buff *buf; |
| long timeo; |
| int res; |
| |
| @@ -2733,19 +2740,17 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags, |
| } |
| |
| /* |
| - * Respond to 'SYN-' by discarding it & returning 'ACK'-. |
| - * Respond to 'SYN+' by queuing it on new socket. |
| + * Respond to 'SYN-' by discarding it & returning 'ACK'. |
| + * Respond to 'SYN+' by queuing it on new socket & returning 'ACK'. |
| */ |
| if (!msg_data_sz(msg)) { |
| - struct msghdr m = {NULL,}; |
| - |
| tsk_advance_rx_queue(sk); |
| - __tipc_sendstream(new_sock, &m, 0); |
| } else { |
| __skb_dequeue(&sk->sk_receive_queue); |
| __skb_queue_head(&new_sk->sk_receive_queue, buf); |
| skb_set_owner_r(buf, new_sk); |
| } |
| + __tipc_sendstream(new_sock, &m, 0); |
| release_sock(new_sk); |
| exit: |
| release_sock(sk); |
| -- |
| 2.30.2 |
| |