summaryrefslogtreecommitdiff
path: root/net/mptcp/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mptcp/options.c')
-rw-r--r--net/mptcp/options.c56
1 files changed, 44 insertions, 12 deletions
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 8f82ff9a5a8e..45acd877bef3 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -243,6 +243,7 @@ void mptcp_rcv_synsent(struct sock *sk)
pr_debug("subflow=%p", subflow);
if (subflow->request_mptcp && tp->rx_opt.mptcp.mp_capable) {
subflow->mp_capable = 1;
+ subflow->can_ack = 1;
subflow->remote_key = tp->rx_opt.mptcp.sndr_key;
} else {
tcp_sk(sk)->is_mptcp = 0;
@@ -332,6 +333,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
struct mptcp_ext *mpext;
struct mptcp_sock *msk;
unsigned int ack_size;
+ bool ret = false;
u8 tcp_fin;
if (skb) {
@@ -355,6 +357,14 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
if (skb && tcp_fin &&
subflow->conn->sk_state != TCP_ESTABLISHED)
mptcp_write_data_fin(subflow, &opts->ext_copy);
+ ret = true;
+ }
+
+ opts->ext_copy.use_ack = 0;
+ msk = mptcp_sk(subflow->conn);
+ if (!msk || !READ_ONCE(msk->can_ack)) {
+ *size = ALIGN(dss_size, 4);
+ return ret;
}
ack_size = TCPOLEN_MPTCP_DSS_ACK64;
@@ -365,15 +375,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
dss_size += ack_size;
- msk = mptcp_sk(mptcp_subflow_ctx(sk)->conn);
- if (msk) {
- opts->ext_copy.data_ack = msk->ack_seq;
- } else {
- mptcp_crypto_key_sha(mptcp_subflow_ctx(sk)->remote_key,
- NULL, &opts->ext_copy.data_ack);
- opts->ext_copy.data_ack++;
- }
-
+ opts->ext_copy.data_ack = msk->ack_seq;
opts->ext_copy.ack64 = 1;
opts->ext_copy.use_ack = 1;
@@ -422,13 +424,46 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
return false;
}
+static bool check_fourth_ack(struct mptcp_subflow_context *subflow,
+ struct sk_buff *skb,
+ struct mptcp_options_received *mp_opt)
+{
+ /* here we can process OoO, in-window pkts, only in-sequence 4th ack
+ * are relevant
+ */
+ if (likely(subflow->fourth_ack ||
+ TCP_SKB_CB(skb)->seq != subflow->ssn_offset + 1))
+ return true;
+
+ if (mp_opt->use_ack)
+ subflow->fourth_ack = 1;
+
+ if (subflow->can_ack)
+ return true;
+
+ /* If the first established packet does not contain MP_CAPABLE + data
+ * then fallback to TCP
+ */
+ if (!mp_opt->mp_capable) {
+ subflow->mp_capable = 0;
+ tcp_sk(mptcp_subflow_tcp_sock(subflow))->is_mptcp = 0;
+ return false;
+ }
+ subflow->remote_key = mp_opt->sndr_key;
+ subflow->can_ack = 1;
+ return true;
+}
+
void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
struct tcp_options_received *opt_rx)
{
+ struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct mptcp_options_received *mp_opt;
struct mptcp_ext *mpext;
mp_opt = &opt_rx->mptcp;
+ if (!check_fourth_ack(subflow, skb, mp_opt))
+ return;
if (!mp_opt->dss)
return;
@@ -441,9 +476,6 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
if (mp_opt->use_map) {
if (mp_opt->mpc_map) {
- struct mptcp_subflow_context *subflow =
- mptcp_subflow_ctx(sk);
-
/* this is an MP_CAPABLE carrying MPTCP data
* we know this map the first chunk of data
*/