Commit 50c504a2 authored by Florian Westphal's avatar Florian Westphal Committed by Jakub Kicinski

mptcp: parse and act on incoming FASTCLOSE option

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: default avatarMatthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 049fe386
...@@ -282,6 +282,16 @@ static void mptcp_parse_option(const struct sk_buff *skb, ...@@ -282,6 +282,16 @@ static void mptcp_parse_option(const struct sk_buff *skb,
pr_debug("RM_ADDR: id=%d", mp_opt->rm_id); pr_debug("RM_ADDR: id=%d", mp_opt->rm_id);
break; 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: default:
break; break;
} }
...@@ -299,6 +309,7 @@ void mptcp_get_options(const struct sk_buff *skb, ...@@ -299,6 +309,7 @@ void mptcp_get_options(const struct sk_buff *skb,
mp_opt->mp_join = 0; mp_opt->mp_join = 0;
mp_opt->add_addr = 0; mp_opt->add_addr = 0;
mp_opt->ahmac = 0; mp_opt->ahmac = 0;
mp_opt->fastclose = 0;
mp_opt->port = 0; mp_opt->port = 0;
mp_opt->rm_addr = 0; mp_opt->rm_addr = 0;
mp_opt->dss = 0; mp_opt->dss = 0;
...@@ -942,6 +953,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) ...@@ -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)) if (!check_fully_established(msk, sk, subflow, skb, &mp_opt))
return; 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)) { if (mp_opt.add_addr && add_addr_hmac_valid(msk, &mp_opt)) {
struct mptcp_addr_info addr; struct mptcp_addr_info addr;
......
...@@ -2217,6 +2217,36 @@ static bool mptcp_check_close_timeout(const struct sock *sk) ...@@ -2217,6 +2217,36 @@ static bool mptcp_check_close_timeout(const struct sock *sk)
return true; 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) static void mptcp_worker(struct work_struct *work)
{ {
struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work); struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);
...@@ -2233,6 +2263,9 @@ static void mptcp_worker(struct work_struct *work) ...@@ -2233,6 +2263,9 @@ static void mptcp_worker(struct work_struct *work)
mptcp_check_data_fin_ack(sk); mptcp_check_data_fin_ack(sk);
__mptcp_flush_join_list(msk); __mptcp_flush_join_list(msk);
mptcp_check_fastclose(msk);
if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags)) if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
__mptcp_close_subflow(msk); __mptcp_close_subflow(msk);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define OPTION_MPTCP_ADD_ADDR BIT(6) #define OPTION_MPTCP_ADD_ADDR BIT(6)
#define OPTION_MPTCP_ADD_ADDR6 BIT(7) #define OPTION_MPTCP_ADD_ADDR6 BIT(7)
#define OPTION_MPTCP_RM_ADDR BIT(8) #define OPTION_MPTCP_RM_ADDR BIT(8)
#define OPTION_MPTCP_FASTCLOSE BIT(9)
/* MPTCP option subtypes */ /* MPTCP option subtypes */
#define MPTCPOPT_MP_CAPABLE 0 #define MPTCPOPT_MP_CAPABLE 0
...@@ -58,6 +59,7 @@ ...@@ -58,6 +59,7 @@
#define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT 24 #define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT 24
#define TCPOLEN_MPTCP_PORT_LEN 4 #define TCPOLEN_MPTCP_PORT_LEN 4
#define TCPOLEN_MPTCP_RM_ADDR_BASE 4 #define TCPOLEN_MPTCP_RM_ADDR_BASE 4
#define TCPOLEN_MPTCP_FASTCLOSE 12
/* MPTCP MP_JOIN flags */ /* MPTCP MP_JOIN flags */
#define MPTCPOPT_BACKUP BIT(0) #define MPTCPOPT_BACKUP BIT(0)
...@@ -110,6 +112,7 @@ struct mptcp_options_received { ...@@ -110,6 +112,7 @@ struct mptcp_options_received {
u16 data_len; u16 data_len;
u16 mp_capable : 1, u16 mp_capable : 1,
mp_join : 1, mp_join : 1,
fastclose : 1,
dss : 1, dss : 1,
add_addr : 1, add_addr : 1,
rm_addr : 1, rm_addr : 1,
...@@ -237,6 +240,7 @@ struct mptcp_sock { ...@@ -237,6 +240,7 @@ struct mptcp_sock {
bool fully_established; bool fully_established;
bool rcv_data_fin; bool rcv_data_fin;
bool snd_data_fin_enable; bool snd_data_fin_enable;
bool rcv_fastclose;
bool use_64bit_ack; /* Set when we received a 64-bit DSN */ bool use_64bit_ack; /* Set when we received a 64-bit DSN */
spinlock_t join_list_lock; spinlock_t join_list_lock;
struct sock *ack_hint; struct sock *ack_hint;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment