diff options
author | Xin Long <lucien.xin@gmail.com> | 2016-07-30 14:09:09 +0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-07-30 22:06:22 -0700 |
commit | a0fc6843f948345fa85c218fec662f571804d2f9 (patch) | |
tree | e7a10b0ba1686898cefc3bfbb0194d1a5edfed85 /net/sctp | |
parent | 1aa25ec227a4be21515594f485b0f4985109f0d8 (diff) |
sctp: allow delivering notifications after receiving SHUTDOWN
Prior to this patch, once sctp received SHUTDOWN or shutdown with RD,
sk->sk_shutdown would be set with RCV_SHUTDOWN, and all events would
be dropped in sctp_ulpq_tail_event(). It would cause:
1. some notifications couldn't be received by users. like
SCTP_SHUTDOWN_COMP generated by sctp_sf_do_4_C().
2. sctp would also never trigger sk_data_ready when the association
was closed, making it harder to identify the end of the association
by calling recvmsg() and getting an EOF. It was not convenient for
kernel users.
The check here should be stopping delivering DATA chunks after receiving
SHUTDOWN, and stopping delivering ANY chunks after sctp_close().
So this patch is to allow notifications to enqueue into receive queue
even if sk->sk_shutdown is set to RCV_SHUTDOWN in sctp_ulpq_tail_event,
but if sk->sk_shutdown == RCV_SHUTDOWN | SEND_SHUTDOWN, it drops all
events.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/ulpqueue.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index ec166d2bd2d9..877e55066f89 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -204,7 +204,9 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) /* If the socket is just going to throw this away, do not * even try to deliver it. */ - if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN)) + if (sk->sk_shutdown & RCV_SHUTDOWN && + (sk->sk_shutdown & SEND_SHUTDOWN || + !sctp_ulpevent_is_notification(event))) goto out_free; if (!sctp_ulpevent_is_notification(event)) { |