diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2010-04-30 22:41:10 -0400 |
---|---|---|
committer | Vlad Yasevich <vladislav.yasevich@hp.com> | 2010-04-30 22:41:10 -0400 |
commit | ea862c8d1f4a0d193979c7412c3b946f600721ce (patch) | |
tree | 929dd96e2562258a96739373c758ab6dcbc2bb1b /net/sctp/outqueue.c | |
parent | 65883371894be2631603d5d412f90f8c09290fef (diff) |
sctp: correctly mark missing chunks in fast recovery
According to RFC 4960 Section 7.2.4:
If an endpoint is in Fast
Recovery and a SACK arrives that advances the Cumulative TSN Ack
Point, the miss indications are incremented for all TSNs reported
missing in the SACK.
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r-- | net/sctp/outqueue.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 786c4ff97ae4..b491a1aac3e4 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -1154,6 +1154,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1154 | struct sctp_transport *primary = asoc->peer.primary_path; | 1154 | struct sctp_transport *primary = asoc->peer.primary_path; |
1155 | int count_of_newacks = 0; | 1155 | int count_of_newacks = 0; |
1156 | int gap_ack_blocks; | 1156 | int gap_ack_blocks; |
1157 | u8 accum_moved = 0; | ||
1157 | 1158 | ||
1158 | /* Grab the association's destination address list. */ | 1159 | /* Grab the association's destination address list. */ |
1159 | transport_list = &asoc->peer.transport_addr_list; | 1160 | transport_list = &asoc->peer.transport_addr_list; |
@@ -1232,16 +1233,22 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1232 | count_of_newacks ++; | 1233 | count_of_newacks ++; |
1233 | } | 1234 | } |
1234 | 1235 | ||
1236 | /* Move the Cumulative TSN Ack Point if appropriate. */ | ||
1237 | if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn)) { | ||
1238 | asoc->ctsn_ack_point = sack_ctsn; | ||
1239 | accum_moved = 1; | ||
1240 | } | ||
1241 | |||
1235 | if (gap_ack_blocks) { | 1242 | if (gap_ack_blocks) { |
1243 | |||
1244 | if (asoc->fast_recovery && accum_moved) | ||
1245 | highest_new_tsn = highest_tsn; | ||
1246 | |||
1236 | list_for_each_entry(transport, transport_list, transports) | 1247 | list_for_each_entry(transport, transport_list, transports) |
1237 | sctp_mark_missing(q, &transport->transmitted, transport, | 1248 | sctp_mark_missing(q, &transport->transmitted, transport, |
1238 | highest_new_tsn, count_of_newacks); | 1249 | highest_new_tsn, count_of_newacks); |
1239 | } | 1250 | } |
1240 | 1251 | ||
1241 | /* Move the Cumulative TSN Ack Point if appropriate. */ | ||
1242 | if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn)) | ||
1243 | asoc->ctsn_ack_point = sack_ctsn; | ||
1244 | |||
1245 | /* Update unack_data field in the assoc. */ | 1252 | /* Update unack_data field in the assoc. */ |
1246 | sctp_sack_update_unack_data(asoc, sack); | 1253 | sctp_sack_update_unack_data(asoc, sack); |
1247 | 1254 | ||
@@ -1685,7 +1692,8 @@ static void sctp_mark_missing(struct sctp_outq *q, | |||
1685 | struct sctp_chunk *chunk; | 1692 | struct sctp_chunk *chunk; |
1686 | __u32 tsn; | 1693 | __u32 tsn; |
1687 | char do_fast_retransmit = 0; | 1694 | char do_fast_retransmit = 0; |
1688 | struct sctp_transport *primary = q->asoc->peer.primary_path; | 1695 | struct sctp_association *asoc = q->asoc; |
1696 | struct sctp_transport *primary = asoc->peer.primary_path; | ||
1689 | 1697 | ||
1690 | list_for_each_entry(chunk, transmitted_queue, transmitted_list) { | 1698 | list_for_each_entry(chunk, transmitted_queue, transmitted_list) { |
1691 | 1699 | ||