Skip to content

Commit

Permalink
mptcp: receive checksum for MP_CAPABLE with data
Browse files Browse the repository at this point in the history
This patch added a new member named csum in struct mptcp_options_received.

When parsing the MP_CAPABLE with data, if the checksum is enabled,
adjust the expected_opsize. If the receiving option length matches the
length with the data checksum, get the checksum value and save it in
mp_opt->csum. And in mptcp_incoming_options, pass it to mpext->csum.

We always parse any csum/nocsum combination and delay the presence check
to later code, to allow reset if missing.

Additionally, in the TX path, use the newly introduce ext field to avoid
MPTCP csum recomputation on TCP retransmission and unneeded csum update
on when setting the data fin_flag.

Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: Geliang Tang <geliangtang@gmail.com>
  • Loading branch information
geliangtang authored and matttbe committed May 6, 2021
1 parent f8cf50d commit f9b610c
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 13 deletions.
3 changes: 2 additions & 1 deletion include/net/mptcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ struct mptcp_ext {
mpc_map:1,
frozen:1,
reset_transient:1;
u8 reset_reason:4;
u8 reset_reason:4,
csum_reqd:1;
};

#define MPTCP_RM_IDS_MAX 8
Expand Down
44 changes: 32 additions & 12 deletions net/mptcp/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,31 @@ static void mptcp_parse_option(const struct sock *sk,
case MPTCPOPT_MP_CAPABLE:
/* strict size checking */
if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) {
if (skb->len > tcp_hdr(skb)->doff << 2)
if (skb->len > tcp_hdr(skb)->doff << 2) {
expected_opsize = TCPOLEN_MPTCP_MPC_ACK_DATA;
else
} else {
expected_opsize = TCPOLEN_MPTCP_MPC_ACK;
}
} else {
if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_ACK)
expected_opsize = TCPOLEN_MPTCP_MPC_SYNACK;
else
expected_opsize = TCPOLEN_MPTCP_MPC_SYN;
}
if (opsize != expected_opsize)

/* Cfr RFC 8684 Section 3.3.0:
* If a checksum is present but its use had
* not been negotiated in the MP_CAPABLE handshake, the receiver MUST
* close the subflow with a RST, as it is not behaving as negotiated.
* If a checksum is not present when its use has been negotiated, the
* receiver MUST close the subflow with a RST, as it is considered
* broken
* We parse even option with mismatching csum presence, so that
* later in subflow_data_ready we can trigger the reset.
*/
if (opsize != expected_opsize &&
(expected_opsize != TCPOLEN_MPTCP_MPC_ACK_DATA ||
opsize != TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM))
break;

/* try to be gentle vs future versions on the initial syn */
Expand All @@ -69,11 +83,6 @@ static void mptcp_parse_option(const struct sock *sk,
* host requires the use of checksums, checksums MUST be used.
* In other words, the only way for checksums not to be used
* is if both hosts in their SYNs set A=0."
*
* Section 3.3.0:
* "If a checksum is not present when its use has been
* negotiated, the receiver MUST close the subflow with a RST as
* it is considered broken."
*/
mp_opt->csum_reqd = READ_ONCE(msk->csum_enabled);
if (flags & MPTCP_CAP_CHECKSUM_REQD)
Expand All @@ -88,7 +97,7 @@ static void mptcp_parse_option(const struct sock *sk,
mp_opt->rcvr_key = get_unaligned_be64(ptr);
ptr += 8;
}
if (opsize == TCPOLEN_MPTCP_MPC_ACK_DATA) {
if (opsize >= TCPOLEN_MPTCP_MPC_ACK_DATA) {
/* Section 3.1.:
* "the data parameters in a MP_CAPABLE are semantically
* equivalent to those in a DSS option and can be used
Expand All @@ -100,9 +109,14 @@ static void mptcp_parse_option(const struct sock *sk,
mp_opt->data_len = get_unaligned_be16(ptr);
ptr += 2;
}
pr_debug("MP_CAPABLE version=%x, flags=%x, optlen=%d sndr=%llu, rcvr=%llu len=%d",
if (opsize == TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM) {
mp_opt->csum = (__force __sum16)get_unaligned_be16(ptr);
mp_opt->csum_reqd = 1;
ptr += 2;
}
pr_debug("MP_CAPABLE version=%x, flags=%x, optlen=%d sndr=%llu, rcvr=%llu len=%d csum=%u",
version, flags, opsize, mp_opt->sndr_key,
mp_opt->rcvr_key, mp_opt->data_len);
mp_opt->rcvr_key, mp_opt->data_len, mp_opt->csum);
break;

case MPTCPOPT_MP_JOIN:
Expand Down Expand Up @@ -538,7 +552,9 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
ext->data_len++;

/* the pseudo header has changed, update the csum accordingly */
csum_replace2(&ext->csum, htons(ext->data_len - 1), htons(ext->data_len));
if (ext->csum_reqd)
csum_replace2(&ext->csum, htons(ext->data_len - 1),
htons(ext->data_len));
}
}

Expand Down Expand Up @@ -1124,6 +1140,10 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
}
mpext->data_len = mp_opt.data_len;
mpext->use_map = 1;
mpext->csum_reqd = mp_opt.csum_reqd;

if (mpext->csum_reqd)
mpext->csum = mp_opt.csum;
}
}

Expand Down
3 changes: 3 additions & 0 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
#define TCPOLEN_MPTCP_FASTCLOSE 12
#define TCPOLEN_MPTCP_RST 4

#define TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM (TCPOLEN_MPTCP_DSS_CHECKSUM + TCPOLEN_MPTCP_MPC_ACK_DATA)

/* MPTCP MP_JOIN flags */
#define MPTCPOPT_BACKUP BIT(0)
#define MPTCPOPT_HMAC_LEN 20
Expand Down Expand Up @@ -124,6 +126,7 @@ struct mptcp_options_received {
u64 data_seq;
u32 subflow_seq;
u16 data_len;
__sum16 csum;
u16 mp_capable : 1,
mp_join : 1,
fastclose : 1,
Expand Down

0 comments on commit f9b610c

Please sign in to comment.