| From: lucien <lucien.xin@gmail.com> |
| Date: Sat, 5 Dec 2015 15:35:36 +0800 |
| Subject: sctp: start t5 timer only when peer rwnd is 0 and local state is |
| SHUTDOWN_PENDING |
| |
| commit 8a0d19c5ed417c78d03f4e0fa7215e58c40896d8 upstream. |
| |
| when A sends a data to B, then A close() and enter into SHUTDOWN_PENDING |
| state, if B neither claim his rwnd is 0 nor send SACK for this data, A |
| will keep retransmitting this data until t5 timeout, Max.Retrans times |
| can't work anymore, which is bad. |
| |
| if B's rwnd is not 0, it should send abort after Max.Retrans times, only |
| when B's rwnd == 0 and A's retransmitting beyonds Max.Retrans times, A |
| will start t5 timer, which is also commit f8d960524328 ("sctp: Enforce |
| retransmission limit during shutdown") means, but it lacks the condition |
| peer rwnd == 0. |
| |
| so fix it by adding a bit (zero_window_announced) in peer to record if |
| the last rwnd is 0. If it was, zero_window_announced will be set. and use |
| this bit to decide if start t5 timer when local.state is SHUTDOWN_PENDING. |
| |
| Fixes: commit f8d960524328 ("sctp: Enforce retransmission limit during shutdown") |
| Signed-off-by: Xin Long <lucien.xin@gmail.com> |
| Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| [bwh: Backported to 3.2: change sack_needed to bitfield as done earlier upstream] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| Signed-off-by: Zefan Li <lizefan@huawei.com> |
| --- |
| include/net/sctp/structs.h | 3 ++- |
| net/sctp/outqueue.c | 1 + |
| net/sctp/sm_statefuns.c | 3 ++- |
| 3 files changed, 5 insertions(+), 2 deletions(-) |
| |
| --- a/include/net/sctp/structs.h |
| +++ b/include/net/sctp/structs.h |
| @@ -1587,7 +1587,8 @@ struct sctp_association { |
| * : order. When DATA chunks are out of order, |
| * : SACK's are not delayed (see Section 6). |
| */ |
| - __u8 sack_needed; /* Do we need to sack the peer? */ |
| + __u8 sack_needed:1, /* Do we need to sack the peer? */ |
| + zero_window_announced:1; |
| __u32 sack_cnt; |
| |
| /* These are capabilities which our peer advertised. */ |
| --- a/net/sctp/outqueue.c |
| +++ b/net/sctp/outqueue.c |
| @@ -1265,6 +1265,7 @@ int sctp_outq_sack(struct sctp_outq *q, |
| */ |
| |
| sack_a_rwnd = ntohl(sack->a_rwnd); |
| + asoc->peer.zero_window_announced = !sack_a_rwnd; |
| outstanding = q->outstanding_bytes; |
| |
| if (outstanding < sack_a_rwnd) |
| --- a/net/sctp/sm_statefuns.c |
| +++ b/net/sctp/sm_statefuns.c |
| @@ -5299,7 +5299,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx( |
| SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS); |
| |
| if (asoc->overall_error_count >= asoc->max_retrans) { |
| - if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) { |
| + if (asoc->peer.zero_window_announced && |
| + asoc->state == SCTP_STATE_SHUTDOWN_PENDING) { |
| /* |
| * We are here likely because the receiver had its rwnd |
| * closed for a while and we have not been able to |