diff options
-rw-r--r-- | net/mptcp/options.c | 16 | ||||
-rw-r--r-- | net/mptcp/protocol.c | 32 | ||||
-rw-r--r-- | net/mptcp/protocol.h | 2 |
3 files changed, 37 insertions, 13 deletions
diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 45acd877bef3..b9a8305bd934 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -304,21 +304,22 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, struct mptcp_ext *ext) { - ext->data_fin = 1; - if (!ext->use_map) { /* RFC6824 requires a DSS mapping with specific values * if DATA_FIN is set but no data payload is mapped */ + ext->data_fin = 1; ext->use_map = 1; ext->dsn64 = 1; - ext->data_seq = mptcp_sk(subflow->conn)->write_seq; + ext->data_seq = subflow->data_fin_tx_seq; ext->subflow_seq = 0; ext->data_len = 1; - } else { - /* If there's an existing DSS mapping, DATA_FIN consumes - * 1 additional byte of mapping space. + } else if (ext->data_seq + ext->data_len == subflow->data_fin_tx_seq) { + /* If there's an existing DSS mapping and it is the + * final mapping, DATA_FIN consumes 1 additional byte of + * mapping space. */ + ext->data_fin = 1; ext->data_len++; } } @@ -354,8 +355,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb, if (mpext) opts->ext_copy = *mpext; - if (skb && tcp_fin && - subflow->conn->sk_state != TCP_ESTABLISHED) + if (skb && tcp_fin && subflow->data_fin_tx_enable) mptcp_write_data_fin(subflow, &opts->ext_copy); ret = true; } diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index a8445407d25a..4c075a9f7ed0 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -419,6 +419,15 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) return -EOPNOTSUPP; lock_sock(sk); + + timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); + + if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { + ret = sk_stream_wait_connect(sk, &timeo); + if (ret) + goto out; + } + ssock = __mptcp_tcp_fallback(msk); if (unlikely(ssock)) { fallback: @@ -427,8 +436,6 @@ fallback: return ret >= 0 ? ret + copied : (copied ? copied : ret); } - timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); - ssk = mptcp_subflow_get(msk); if (!ssk) { release_sock(sk); @@ -460,6 +467,7 @@ fallback: ssk_check_wmem(msk, ssk); release_sock(ssk); +out: release_sock(sk); return ret; } @@ -712,7 +720,8 @@ static void mptcp_cancel_work(struct sock *sk) sock_put(sk); } -static void mptcp_subflow_shutdown(struct sock *ssk, int how) +static void mptcp_subflow_shutdown(struct sock *ssk, int how, + bool data_fin_tx_enable, u64 data_fin_tx_seq) { lock_sock(ssk); @@ -725,6 +734,14 @@ static void mptcp_subflow_shutdown(struct sock *ssk, int how) tcp_disconnect(ssk, O_NONBLOCK); break; default: + if (data_fin_tx_enable) { + struct mptcp_subflow_context *subflow; + + subflow = mptcp_subflow_ctx(ssk); + subflow->data_fin_tx_seq = data_fin_tx_seq; + subflow->data_fin_tx_enable = 1; + } + ssk->sk_shutdown |= how; tcp_shutdown(ssk, how); break; @@ -741,6 +758,7 @@ static void mptcp_close(struct sock *sk, long timeout) struct mptcp_subflow_context *subflow, *tmp; struct mptcp_sock *msk = mptcp_sk(sk); LIST_HEAD(conn_list); + u64 data_fin_tx_seq; lock_sock(sk); @@ -749,11 +767,15 @@ static void mptcp_close(struct sock *sk, long timeout) list_splice_init(&msk->conn_list, &conn_list); + data_fin_tx_seq = msk->write_seq; + release_sock(sk); list_for_each_entry_safe(subflow, tmp, &conn_list, node) { struct sock *ssk = mptcp_subflow_tcp_sock(subflow); + subflow->data_fin_tx_seq = data_fin_tx_seq; + subflow->data_fin_tx_enable = 1; __mptcp_close_ssk(sk, ssk, subflow, timeout); } @@ -846,7 +868,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err, *err = -ENOBUFS; local_bh_enable(); release_sock(sk); - mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1); + mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1, 0, 0); tcp_close(newsk, 0); return NULL; } @@ -1301,7 +1323,7 @@ static int mptcp_shutdown(struct socket *sock, int how) mptcp_for_each_subflow(msk, subflow) { struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow); - mptcp_subflow_shutdown(tcp_sk, how); + mptcp_subflow_shutdown(tcp_sk, how, 1, msk->write_seq); } out_unlock: diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 6c0b2c8ab674..313558fa8185 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -125,7 +125,9 @@ struct mptcp_subflow_context { mpc_map : 1, data_avail : 1, rx_eof : 1, + data_fin_tx_enable : 1, can_ack : 1; /* only after processing the remote a key */ + u64 data_fin_tx_seq; struct sock *tcp_sock; /* tcp sk backpointer */ struct sock *conn; /* parent mptcp_sock */ |