]> git.baikalelectronics.ru Git - kernel.git/commitdiff
mptcp: send out MP_FAIL when data checksum fails
authorGeliang Tang <geliangtang@xiaomi.com>
Tue, 24 Aug 2021 23:26:17 +0000 (16:26 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 25 Aug 2021 10:02:35 +0000 (11:02 +0100)
When a bad checksum is detected, set the send_mp_fail flag to send out
the MP_FAIL option.

Add a new function mptcp_has_another_subflow() to check whether there's
only a single subflow.

When multiple subflows are in use, close the affected subflow with a RST
that includes an MP_FAIL option and discard the data with the bad
checksum.

Set the sk_state of the subsocket to TCP_CLOSE, then the flag
MPTCP_WORK_CLOSE_SUBFLOW will be set in subflow_sched_work_if_closed,
and the subflow will be closed.

When a single subfow is in use, temporarily handled by sending MP_FAIL
with a RST too.

Signed-off-by: Geliang Tang <geliangtang@xiaomi.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/mptcp/protocol.h
net/mptcp/subflow.c

index 9ee5676e70c6c36da344a6d6a63d9c592e30ac70..57a50b1194a90cf7eba4cbf04aa7cbf808ca40f7 100644 (file)
@@ -614,6 +614,19 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
        inet_csk(sk)->icsk_af_ops = ctx->icsk_af_ops;
 }
 
+static inline bool mptcp_has_another_subflow(struct sock *ssk)
+{
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk), *tmp;
+       struct mptcp_sock *msk = mptcp_sk(subflow->conn);
+
+       mptcp_for_each_subflow(msk, tmp) {
+               if (tmp != subflow)
+                       return true;
+       }
+
+       return false;
+}
+
 void __init mptcp_proto_init(void);
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 int __init mptcp_proto_v6_init(void);
index 8c43aa14897a90c4eb1c74259c93e5dccfdb4463..dba8ad700fb801fc515be7f7a3e29cd720c73518 100644 (file)
@@ -910,6 +910,7 @@ static enum mapping_status validate_data_csum(struct sock *ssk, struct sk_buff *
        csum = csum_partial(&header, sizeof(header), subflow->map_data_csum);
        if (unlikely(csum_fold(csum))) {
                MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR);
+               subflow->send_mp_fail = 1;
                return subflow->mp_join ? MAPPING_INVALID : MAPPING_DUMMY;
        }
 
@@ -1157,6 +1158,20 @@ no_data:
 
 fallback:
        /* RFC 8684 section 3.7. */
+       if (subflow->send_mp_fail) {
+               if (mptcp_has_another_subflow(ssk)) {
+                       while ((skb = skb_peek(&ssk->sk_receive_queue)))
+                               sk_eat_skb(ssk, skb);
+               }
+               ssk->sk_err = EBADMSG;
+               tcp_set_state(ssk, TCP_CLOSE);
+               subflow->reset_transient = 0;
+               subflow->reset_reason = MPTCP_RST_EMIDDLEBOX;
+               tcp_send_active_reset(ssk, GFP_ATOMIC);
+               WRITE_ONCE(subflow->data_avail, 0);
+               return true;
+       }
+
        if (subflow->mp_join || subflow->fully_established) {
                /* fatal protocol error, close the socket.
                 * subflow_error_report() will introduce the appropriate barriers