Skip to content

Commit

Permalink
mptcp: fix checksum byte order
Browse files Browse the repository at this point in the history
The MPTCP code typecasts the checksum value to u16 and
then convert it to big endian while storing the value into
the MPTCP option.

As a result, the wire encoding for little endian host is
wrong, and that causes interoperabilty interoperability
issues with other implementation or host with different endianess.

Address the issue writing in the packet the unmodified __sum16 value.

The change is not backward compatible, but I can't see any
other option. MPTCP checksum is disabled by default, and there are
no backward issues with csum disabled.

Fixes: c5b39e2 ("mptcp: send out checksum for DSS")
Fixes: 390b95a ("mptcp: receive checksum for DSS")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni authored and intel-lab-lkp committed May 5, 2022
1 parent 5b525a6 commit 7c59043
Showing 1 changed file with 22 additions and 13 deletions.
35 changes: 22 additions & 13 deletions net/mptcp/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
ptr += 2;
}
if (opsize == TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM) {
mp_opt->csum = (__force __sum16)get_unaligned_be16(ptr);
mp_opt->csum = get_unaligned((__force __sum16 *)ptr);
mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD;
ptr += 2;
}
Expand Down Expand Up @@ -221,7 +221,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,

if (opsize == expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) {
mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD;
mp_opt->csum = (__force __sum16)get_unaligned_be16(ptr);
mp_opt->csum = get_unaligned((__force __sum16 *)ptr);
ptr += 2;
}

Expand Down Expand Up @@ -1282,7 +1282,7 @@ static void mptcp_set_rwin(struct tcp_sock *tp, struct tcphdr *th)
}
}

u16 __mptcp_make_csum(u64 data_seq, u32 subflow_seq, u16 data_len, __wsum sum)
__sum16 __mptcp_make_csum(u64 data_seq, u32 subflow_seq, u16 data_len, __wsum sum)
{
struct csum_pseudo_header header;
__wsum csum;
Expand All @@ -1298,15 +1298,23 @@ u16 __mptcp_make_csum(u64 data_seq, u32 subflow_seq, u16 data_len, __wsum sum)
header.csum = 0;

csum = csum_partial(&header, sizeof(header), sum);
return (__force u16)csum_fold(csum);
return csum_fold(csum);
}

static u16 mptcp_make_csum(const struct mptcp_ext *mpext)
static __sum16 mptcp_make_csum(const struct mptcp_ext *mpext)
{
return __mptcp_make_csum(mpext->data_seq, mpext->subflow_seq, mpext->data_len,
~csum_unfold(mpext->csum));
}

static void put_len_csum(u16 len, __sum16 csum, __be16 *ptr)
{
put_unaligned_be16(len, ptr);

ptr += 1;
put_unaligned(csum, ptr);
}

void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp,
struct mptcp_out_options *opts)
{
Expand Down Expand Up @@ -1385,9 +1393,9 @@ void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp,
/* data_len == 0 is reserved for the infinite mapping,
* the checksum will also be set to 0.
*/
put_unaligned_be32(mpext->data_len << 16 |
(mpext->data_len ? mptcp_make_csum(mpext) : 0),
ptr);
put_len_csum(mpext->data_len,
mpext->data_len ? mptcp_make_csum(mpext) : 0,
(__force __be16 *)ptr);
} else {
put_unaligned_be32(mpext->data_len << 16 |
TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
Expand Down Expand Up @@ -1438,11 +1446,12 @@ void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp,
goto mp_capable_done;

if (opts->csum_reqd) {
put_unaligned_be32(opts->data_len << 16 |
__mptcp_make_csum(opts->data_seq,
opts->subflow_seq,
opts->data_len,
~csum_unfold(opts->csum)), ptr);
put_len_csum(opts->data_len,
__mptcp_make_csum(opts->data_seq,
opts->subflow_seq,
opts->data_len,
~csum_unfold(opts->csum)),
(__force __be16 *)ptr);
} else {
put_unaligned_be32(opts->data_len << 16 |
TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
Expand Down

0 comments on commit 7c59043

Please sign in to comment.