mptcp: parse and act on incoming FASTCLOSE option
authorFlorian Westphal <fw@strlen.de>
Thu, 10 Dec 2020 22:25:04 +0000 (14:25 -0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 15 Dec 2020 01:30:06 +0000 (17:30 -0800)
parse the MPTCP FASTCLOSE subtype.

If provided key matches the local one, schedule the work queue to close
(with tcp reset) all subflows.

The MPTCP socket moves to closed state immediately.

Reviewed-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/mptcp/options.c
net/mptcp/protocol.c
net/mptcp/protocol.h

index 1ca60d9da3efcc772e25edf6a7b107c93fd1daf5..5e7d7755d1a674c22b3c36314a09bbcfafcae446 100644 (file)
@@ -282,6 +282,16 @@ static void mptcp_parse_option(const struct sk_buff *skb,
                pr_debug("RM_ADDR: id=%d", mp_opt->rm_id);
                break;
 
+       case MPTCPOPT_MP_FASTCLOSE:
+               if (opsize != TCPOLEN_MPTCP_FASTCLOSE)
+                       break;
+
+               ptr += 2;
+               mp_opt->rcvr_key = get_unaligned_be64(ptr);
+               ptr += 8;
+               mp_opt->fastclose = 1;
+               break;
+
        default:
                break;
        }
@@ -299,6 +309,7 @@ void mptcp_get_options(const struct sk_buff *skb,
        mp_opt->mp_join = 0;
        mp_opt->add_addr = 0;
        mp_opt->ahmac = 0;
+       mp_opt->fastclose = 0;
        mp_opt->port = 0;
        mp_opt->rm_addr = 0;
        mp_opt->dss = 0;
@@ -942,6 +953,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
        if (!check_fully_established(msk, sk, subflow, skb, &mp_opt))
                return;
 
+       if (mp_opt.fastclose &&
+           msk->local_key == mp_opt.rcvr_key) {
+               WRITE_ONCE(msk->rcv_fastclose, true);
+               mptcp_schedule_work((struct sock *)msk);
+       }
+
        if (mp_opt.add_addr && add_addr_hmac_valid(msk, &mp_opt)) {
                struct mptcp_addr_info addr;
 
index 2540d82742accfc85ca7559261758804215d8009..cb8b7adf218a08b477bfcdff5db493e4eddb7145 100644 (file)
@@ -2217,6 +2217,36 @@ static bool mptcp_check_close_timeout(const struct sock *sk)
        return true;
 }
 
+static void mptcp_check_fastclose(struct mptcp_sock *msk)
+{
+       struct mptcp_subflow_context *subflow, *tmp;
+       struct sock *sk = &msk->sk.icsk_inet.sk;
+
+       if (likely(!READ_ONCE(msk->rcv_fastclose)))
+               return;
+
+       mptcp_token_destroy(msk);
+
+       list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
+               struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);
+
+               lock_sock(tcp_sk);
+               if (tcp_sk->sk_state != TCP_CLOSE) {
+                       tcp_send_active_reset(tcp_sk, GFP_ATOMIC);
+                       tcp_set_state(tcp_sk, TCP_CLOSE);
+               }
+               release_sock(tcp_sk);
+       }
+
+       inet_sk_state_store(sk, TCP_CLOSE);
+       sk->sk_shutdown = SHUTDOWN_MASK;
+       smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
+       set_bit(MPTCP_DATA_READY, &msk->flags);
+       set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags);
+
+       mptcp_close_wake_up(sk);
+}
+
 static void mptcp_worker(struct work_struct *work)
 {
        struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);
@@ -2233,6 +2263,9 @@ static void mptcp_worker(struct work_struct *work)
 
        mptcp_check_data_fin_ack(sk);
        __mptcp_flush_join_list(msk);
+
+       mptcp_check_fastclose(msk);
+
        if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
                __mptcp_close_subflow(msk);
 
index a5bc9599ae5c613e2767d7d9330cbc2cad48141e..7cf9d110b85f3124c311b33bebc993c2351eac37 100644 (file)
@@ -23,6 +23,7 @@
 #define OPTION_MPTCP_ADD_ADDR  BIT(6)
 #define OPTION_MPTCP_ADD_ADDR6 BIT(7)
 #define OPTION_MPTCP_RM_ADDR   BIT(8)
+#define OPTION_MPTCP_FASTCLOSE BIT(9)
 
 /* MPTCP option subtypes */
 #define MPTCPOPT_MP_CAPABLE    0
@@ -58,6 +59,7 @@
 #define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT      24
 #define TCPOLEN_MPTCP_PORT_LEN         4
 #define TCPOLEN_MPTCP_RM_ADDR_BASE     4
+#define TCPOLEN_MPTCP_FASTCLOSE                12
 
 /* MPTCP MP_JOIN flags */
 #define MPTCPOPT_BACKUP                BIT(0)
@@ -110,6 +112,7 @@ struct mptcp_options_received {
        u16     data_len;
        u16     mp_capable : 1,
                mp_join : 1,
+               fastclose : 1,
                dss : 1,
                add_addr : 1,
                rm_addr : 1,
@@ -237,6 +240,7 @@ struct mptcp_sock {
        bool            fully_established;
        bool            rcv_data_fin;
        bool            snd_data_fin_enable;
+       bool            rcv_fastclose;
        bool            use_64bit_ack; /* Set when we received a 64-bit DSN */
        spinlock_t      join_list_lock;
        struct sock     *ack_hint;