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

tipc: fix implicit-connect for SYN+

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: b97bf3fd ("[TIPC] Initial merge")
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: default avatarJon Maloy <jmaloy@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d72e91ef
...@@ -158,6 +158,7 @@ static void tipc_sk_remove(struct tipc_sock *tsk); ...@@ -158,6 +158,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_sendstream(struct socket *sock, struct msghdr *m, size_t dsz);
static int __tipc_sendmsg(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 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 packet_ops;
static const struct proto_ops stream_ops; static const struct proto_ops stream_ops;
...@@ -1515,8 +1516,13 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) ...@@ -1515,8 +1516,13 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
rc = 0; rc = 0;
} }
if (unlikely(syn && !rc)) if (unlikely(syn && !rc)) {
tipc_set_sk_state(sk, TIPC_CONNECTING); tipc_set_sk_state(sk, TIPC_CONNECTING);
if (timeout) {
timeout = msecs_to_jiffies(timeout);
tipc_wait_for_connect(sock, &timeout);
}
}
return rc ? rc : dlen; return rc ? rc : dlen;
} }
...@@ -1564,7 +1570,7 @@ static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen) ...@@ -1564,7 +1570,7 @@ static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen)
return -EMSGSIZE; return -EMSGSIZE;
/* Handle implicit connection setup */ /* Handle implicit connection setup */
if (unlikely(dest)) { if (unlikely(dest && sk->sk_state == TIPC_OPEN)) {
rc = __tipc_sendmsg(sock, m, dlen); rc = __tipc_sendmsg(sock, m, dlen);
if (dlen && dlen == rc) { if (dlen && dlen == rc) {
tsk->peer_caps = tipc_node_get_capabilities(net, dnode); tsk->peer_caps = tipc_node_get_capabilities(net, dnode);
...@@ -2689,9 +2695,10 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags, ...@@ -2689,9 +2695,10 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags,
bool kern) bool kern)
{ {
struct sock *new_sk, *sk = sock->sk; struct sock *new_sk, *sk = sock->sk;
struct sk_buff *buf;
struct tipc_sock *new_tsock; struct tipc_sock *new_tsock;
struct msghdr m = {NULL,};
struct tipc_msg *msg; struct tipc_msg *msg;
struct sk_buff *buf;
long timeo; long timeo;
int res; int res;
...@@ -2737,19 +2744,17 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags, ...@@ -2737,19 +2744,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 discarding it & returning 'ACK'.
* Respond to 'SYN+' by queuing it on new socket. * Respond to 'SYN+' by queuing it on new socket & returning 'ACK'.
*/ */
if (!msg_data_sz(msg)) { if (!msg_data_sz(msg)) {
struct msghdr m = {NULL,};
tsk_advance_rx_queue(sk); tsk_advance_rx_queue(sk);
__tipc_sendstream(new_sock, &m, 0);
} else { } else {
__skb_dequeue(&sk->sk_receive_queue); __skb_dequeue(&sk->sk_receive_queue);
__skb_queue_head(&new_sk->sk_receive_queue, buf); __skb_queue_head(&new_sk->sk_receive_queue, buf);
skb_set_owner_r(buf, new_sk); skb_set_owner_r(buf, new_sk);
} }
__tipc_sendstream(new_sock, &m, 0);
release_sock(new_sk); release_sock(new_sk);
exit: exit:
release_sock(sk); release_sock(sk);
......
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