Skip to content

Commit

Permalink
mptcp: Add shutdown() socket operation
Browse files Browse the repository at this point in the history
Call shutdown on all subflows in use on the given socket, or on the
fallback socket.

Co-developed-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com>
Signed-off-by: Christoph Paasch <cpaasch@apple.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Peter Krystad authored and David S. Miller committed Jan 24, 2020
1 parent 79c0949 commit 2149849
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,29 @@ static int mptcp_init_sock(struct sock *sk)
return 0;
}

static void mptcp_subflow_shutdown(struct sock *ssk, int how)
{
lock_sock(ssk);

switch (ssk->sk_state) {
case TCP_LISTEN:
if (!(how & RCV_SHUTDOWN))
break;
/* fall through */
case TCP_SYN_SENT:
tcp_disconnect(ssk, O_NONBLOCK);
break;
default:
ssk->sk_shutdown |= how;
tcp_shutdown(ssk, how);
break;
}

/* Wake up anyone sleeping in poll. */
ssk->sk_state_change(ssk);
release_sock(ssk);
}

static void mptcp_close(struct sock *sk, long timeout)
{
struct mptcp_subflow_context *subflow, *tmp;
Expand Down Expand Up @@ -273,6 +296,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
*err = -ENOBUFS;
local_bh_enable();
release_sock(sk);
mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1);
tcp_close(newsk, 0);
return NULL;
}
Expand Down Expand Up @@ -544,6 +568,46 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
return mask;
}

static int mptcp_shutdown(struct socket *sock, int how)
{
struct mptcp_sock *msk = mptcp_sk(sock->sk);
struct mptcp_subflow_context *subflow;
int ret = 0;

pr_debug("sk=%p, how=%d", msk, how);

lock_sock(sock->sk);

if (how == SHUT_WR || how == SHUT_RDWR)
inet_sk_state_store(sock->sk, TCP_FIN_WAIT1);

how++;

if ((how & ~SHUTDOWN_MASK) || !how) {
ret = -EINVAL;
goto out_unlock;
}

if (sock->state == SS_CONNECTING) {
if ((1 << sock->sk->sk_state) &
(TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE))
sock->state = SS_DISCONNECTING;
else
sock->state = SS_CONNECTED;
}

mptcp_for_each_subflow(msk, subflow) {
struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);

mptcp_subflow_shutdown(tcp_sk, how);
}

out_unlock:
release_sock(sock->sk);

return ret;
}

static struct proto_ops mptcp_stream_ops;

static struct inet_protosw mptcp_protosw = {
Expand All @@ -564,6 +628,7 @@ void __init mptcp_init(void)
mptcp_stream_ops.accept = mptcp_stream_accept;
mptcp_stream_ops.getname = mptcp_v4_getname;
mptcp_stream_ops.listen = mptcp_listen;
mptcp_stream_ops.shutdown = mptcp_shutdown;

mptcp_subflow_init();

Expand Down Expand Up @@ -613,6 +678,7 @@ int mptcpv6_init(void)
mptcp_v6_stream_ops.accept = mptcp_stream_accept;
mptcp_v6_stream_ops.getname = mptcp_v6_getname;
mptcp_v6_stream_ops.listen = mptcp_listen;
mptcp_v6_stream_ops.shutdown = mptcp_shutdown;

err = inet6_register_protosw(&mptcp_v6_protosw);
if (err)
Expand Down

0 comments on commit 2149849

Please sign in to comment.