Skip to content

Commit 2149849

Browse files
Peter Krystaddavem330
authored andcommitted
mptcp: Add shutdown() socket operation
Call shutdown on all subflows in use on the given socket, or on the fallback socket. Co-developed-by: Florian Westphal <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Peter Krystad <[email protected]> Signed-off-by: Christoph Paasch <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 79c0949 commit 2149849

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

net/mptcp/protocol.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,29 @@ static int mptcp_init_sock(struct sock *sk)
196196
return 0;
197197
}
198198

199+
static void mptcp_subflow_shutdown(struct sock *ssk, int how)
200+
{
201+
lock_sock(ssk);
202+
203+
switch (ssk->sk_state) {
204+
case TCP_LISTEN:
205+
if (!(how & RCV_SHUTDOWN))
206+
break;
207+
/* fall through */
208+
case TCP_SYN_SENT:
209+
tcp_disconnect(ssk, O_NONBLOCK);
210+
break;
211+
default:
212+
ssk->sk_shutdown |= how;
213+
tcp_shutdown(ssk, how);
214+
break;
215+
}
216+
217+
/* Wake up anyone sleeping in poll. */
218+
ssk->sk_state_change(ssk);
219+
release_sock(ssk);
220+
}
221+
199222
static void mptcp_close(struct sock *sk, long timeout)
200223
{
201224
struct mptcp_subflow_context *subflow, *tmp;
@@ -273,6 +296,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
273296
*err = -ENOBUFS;
274297
local_bh_enable();
275298
release_sock(sk);
299+
mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1);
276300
tcp_close(newsk, 0);
277301
return NULL;
278302
}
@@ -544,6 +568,46 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
544568
return mask;
545569
}
546570

571+
static int mptcp_shutdown(struct socket *sock, int how)
572+
{
573+
struct mptcp_sock *msk = mptcp_sk(sock->sk);
574+
struct mptcp_subflow_context *subflow;
575+
int ret = 0;
576+
577+
pr_debug("sk=%p, how=%d", msk, how);
578+
579+
lock_sock(sock->sk);
580+
581+
if (how == SHUT_WR || how == SHUT_RDWR)
582+
inet_sk_state_store(sock->sk, TCP_FIN_WAIT1);
583+
584+
how++;
585+
586+
if ((how & ~SHUTDOWN_MASK) || !how) {
587+
ret = -EINVAL;
588+
goto out_unlock;
589+
}
590+
591+
if (sock->state == SS_CONNECTING) {
592+
if ((1 << sock->sk->sk_state) &
593+
(TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE))
594+
sock->state = SS_DISCONNECTING;
595+
else
596+
sock->state = SS_CONNECTED;
597+
}
598+
599+
mptcp_for_each_subflow(msk, subflow) {
600+
struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);
601+
602+
mptcp_subflow_shutdown(tcp_sk, how);
603+
}
604+
605+
out_unlock:
606+
release_sock(sock->sk);
607+
608+
return ret;
609+
}
610+
547611
static struct proto_ops mptcp_stream_ops;
548612

549613
static struct inet_protosw mptcp_protosw = {
@@ -564,6 +628,7 @@ void __init mptcp_init(void)
564628
mptcp_stream_ops.accept = mptcp_stream_accept;
565629
mptcp_stream_ops.getname = mptcp_v4_getname;
566630
mptcp_stream_ops.listen = mptcp_listen;
631+
mptcp_stream_ops.shutdown = mptcp_shutdown;
567632

568633
mptcp_subflow_init();
569634

@@ -613,6 +678,7 @@ int mptcpv6_init(void)
613678
mptcp_v6_stream_ops.accept = mptcp_stream_accept;
614679
mptcp_v6_stream_ops.getname = mptcp_v6_getname;
615680
mptcp_v6_stream_ops.listen = mptcp_listen;
681+
mptcp_v6_stream_ops.shutdown = mptcp_shutdown;
616682

617683
err = inet6_register_protosw(&mptcp_v6_protosw);
618684
if (err)

0 commit comments

Comments
 (0)