mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
mptcp: Implement MPTCP receive path
Parses incoming DSS options and populates outgoing MPTCP ACK fields. MPTCP fields are parsed from the TCP option header and placed in an skb extension, allowing the upper MPTCP layer to access MPTCP options after the skb has gone through the TCP stack. The subflow implements its own data_ready() ops, which ensures that the pending data is in sequence - according to MPTCP seq number - dropping out-of-seq skbs. The DATA_READY bit flag is set if this is the case. This allows the MPTCP socket layer to determine if more data is available without having to consult the individual subflows. It additionally validates the current mapping and propagates EoF events to the connection socket. Co-developed-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Co-developed-by: Peter Krystad <peter.krystad@linux.intel.com> Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com> Co-developed-by: Davide Caratti <dcaratti@redhat.com> Signed-off-by: Davide Caratti <dcaratti@redhat.com> Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> Co-developed-by: Florian Westphal <fw@strlen.de> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: Christoph Paasch <cpaasch@apple.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
6d0060f600
commit
648ef4b886
@@ -14,6 +14,7 @@ void mptcp_parse_option(const unsigned char *ptr, int opsize,
|
||||
{
|
||||
struct mptcp_options_received *mp_opt = &opt_rx->mptcp;
|
||||
u8 subtype = *ptr >> 4;
|
||||
int expected_opsize;
|
||||
u8 version;
|
||||
u8 flags;
|
||||
|
||||
@@ -64,7 +65,79 @@ void mptcp_parse_option(const unsigned char *ptr, int opsize,
|
||||
|
||||
case MPTCPOPT_DSS:
|
||||
pr_debug("DSS");
|
||||
ptr++;
|
||||
|
||||
flags = (*ptr++) & MPTCP_DSS_FLAG_MASK;
|
||||
mp_opt->data_fin = (flags & MPTCP_DSS_DATA_FIN) != 0;
|
||||
mp_opt->dsn64 = (flags & MPTCP_DSS_DSN64) != 0;
|
||||
mp_opt->use_map = (flags & MPTCP_DSS_HAS_MAP) != 0;
|
||||
mp_opt->ack64 = (flags & MPTCP_DSS_ACK64) != 0;
|
||||
mp_opt->use_ack = (flags & MPTCP_DSS_HAS_ACK);
|
||||
|
||||
pr_debug("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d",
|
||||
mp_opt->data_fin, mp_opt->dsn64,
|
||||
mp_opt->use_map, mp_opt->ack64,
|
||||
mp_opt->use_ack);
|
||||
|
||||
expected_opsize = TCPOLEN_MPTCP_DSS_BASE;
|
||||
|
||||
if (mp_opt->use_ack) {
|
||||
if (mp_opt->ack64)
|
||||
expected_opsize += TCPOLEN_MPTCP_DSS_ACK64;
|
||||
else
|
||||
expected_opsize += TCPOLEN_MPTCP_DSS_ACK32;
|
||||
}
|
||||
|
||||
if (mp_opt->use_map) {
|
||||
if (mp_opt->dsn64)
|
||||
expected_opsize += TCPOLEN_MPTCP_DSS_MAP64;
|
||||
else
|
||||
expected_opsize += TCPOLEN_MPTCP_DSS_MAP32;
|
||||
}
|
||||
|
||||
/* RFC 6824, Section 3.3:
|
||||
* If a checksum is present, but its use had
|
||||
* not been negotiated in the MP_CAPABLE handshake,
|
||||
* the checksum field MUST be ignored.
|
||||
*/
|
||||
if (opsize != expected_opsize &&
|
||||
opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM)
|
||||
break;
|
||||
|
||||
mp_opt->dss = 1;
|
||||
|
||||
if (mp_opt->use_ack) {
|
||||
if (mp_opt->ack64) {
|
||||
mp_opt->data_ack = get_unaligned_be64(ptr);
|
||||
ptr += 8;
|
||||
} else {
|
||||
mp_opt->data_ack = get_unaligned_be32(ptr);
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
pr_debug("data_ack=%llu", mp_opt->data_ack);
|
||||
}
|
||||
|
||||
if (mp_opt->use_map) {
|
||||
if (mp_opt->dsn64) {
|
||||
mp_opt->data_seq = get_unaligned_be64(ptr);
|
||||
ptr += 8;
|
||||
} else {
|
||||
mp_opt->data_seq = get_unaligned_be32(ptr);
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
mp_opt->subflow_seq = get_unaligned_be32(ptr);
|
||||
ptr += 4;
|
||||
|
||||
mp_opt->data_len = get_unaligned_be16(ptr);
|
||||
ptr += 2;
|
||||
|
||||
pr_debug("data_seq=%llu subflow_seq=%u data_len=%u",
|
||||
mp_opt->data_seq, mp_opt->subflow_seq,
|
||||
mp_opt->data_len);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -275,6 +348,40 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
|
||||
return false;
|
||||
}
|
||||
|
||||
void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
|
||||
struct tcp_options_received *opt_rx)
|
||||
{
|
||||
struct mptcp_options_received *mp_opt;
|
||||
struct mptcp_ext *mpext;
|
||||
|
||||
mp_opt = &opt_rx->mptcp;
|
||||
|
||||
if (!mp_opt->dss)
|
||||
return;
|
||||
|
||||
mpext = skb_ext_add(skb, SKB_EXT_MPTCP);
|
||||
if (!mpext)
|
||||
return;
|
||||
|
||||
memset(mpext, 0, sizeof(*mpext));
|
||||
|
||||
if (mp_opt->use_map) {
|
||||
mpext->data_seq = mp_opt->data_seq;
|
||||
mpext->subflow_seq = mp_opt->subflow_seq;
|
||||
mpext->data_len = mp_opt->data_len;
|
||||
mpext->use_map = 1;
|
||||
mpext->dsn64 = mp_opt->dsn64;
|
||||
}
|
||||
|
||||
if (mp_opt->use_ack) {
|
||||
mpext->data_ack = mp_opt->data_ack;
|
||||
mpext->use_ack = 1;
|
||||
mpext->ack64 = mp_opt->ack64;
|
||||
}
|
||||
|
||||
mpext->data_fin = mp_opt->data_fin;
|
||||
}
|
||||
|
||||
void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
|
||||
{
|
||||
if ((OPTION_MPTCP_MPC_SYN |
|
||||
|
||||
Reference in New Issue
Block a user