diff options
author | tuexen <tuexen@FreeBSD.org> | 2010-11-12 20:45:21 +0000 |
---|---|---|
committer | tuexen <tuexen@FreeBSD.org> | 2010-11-12 20:45:21 +0000 |
commit | 29f904bd056a707a6fdb40e323c018baadb2d51e (patch) | |
tree | 30081c164ef4523b4a02bd7827aac449ff55e866 /sys/netinet | |
parent | 2666f521076488341c6d69221cfc92588e048cc9 (diff) | |
download | FreeBSD-src-29f904bd056a707a6fdb40e323c018baadb2d51e.zip FreeBSD-src-29f904bd056a707a6fdb40e323c018baadb2d51e.tar.gz |
Fix more issues with the SACK/NR-SACK generation code.
MFC after: 3 days.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/sctp_output.c | 45 |
1 files changed, 24 insertions, 21 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 50820b7..06d4e61 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -9927,13 +9927,14 @@ sctp_send_sack(struct sctp_tcb *stcb) caddr_t limit; uint32_t *dup; int limit_reached = 0; - unsigned int i, sel_start, siz, j; + unsigned int i, siz, j; unsigned int num_gap_blocks = 0, num_nr_gap_blocks = 0, space; int num_dups = 0; int space_req; uint32_t highest_tsn; uint8_t flags; uint8_t type; + uint8_t tsn_map; if ((stcb->asoc.sctp_nr_sack_on_off == 1) && (stcb->asoc.peer_supports_nr_sack == 1)) { @@ -10123,24 +10124,24 @@ sctp_send_sack(struct sctp_tcb *stcb) } else { offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; } - if ((offset == 1) || - ((type == SCTP_NR_SELECTIVE_ACK) && - ((asoc->mapping_array[0] & (1 << (1 - offset))) == 0))) { - sel_start = 0; - } else { - sel_start = 1; - } if (((type == SCTP_SELECTIVE_ACK) && compare_with_wrap(highest_tsn, asoc->cumulative_tsn, MAX_TSN)) || ((type == SCTP_NR_SELECTIVE_ACK) && compare_with_wrap(asoc->highest_tsn_inside_map, asoc->cumulative_tsn, MAX_TSN))) { /* we have a gap .. maybe */ for (i = 0; i < siz; i++) { + tsn_map = asoc->mapping_array[i]; if (type == SCTP_SELECTIVE_ACK) { - selector = &sack_array[asoc->mapping_array[i] | asoc->nr_mapping_array[i]]; - } else { - selector = &sack_array[asoc->mapping_array[i]]; + tsn_map |= asoc->nr_mapping_array[i]; + } + if (i == 0) { + /* + * Clear all bits corresponding to TSNs + * smaller or equal to the cumulative TSN. + */ + tsn_map &= (~0 << (1 - offset)); } + selector = &sack_array[tsn_map]; if (mergeable && selector->right_edge) { /* * Backup, left and right edges were ok to @@ -10152,7 +10153,7 @@ sctp_send_sack(struct sctp_tcb *stcb) if (selector->num_entries == 0) mergeable = 0; else { - for (j = sel_start; j < selector->num_entries; j++) { + for (j = 0; j < selector->num_entries; j++) { if (mergeable && selector->right_edge) { /* * do a merge by NOT setting @@ -10184,7 +10185,6 @@ sctp_send_sack(struct sctp_tcb *stcb) /* Reached the limit stop */ break; } - sel_start = 0; offset += 8; } } @@ -10199,11 +10199,6 @@ sctp_send_sack(struct sctp_tcb *stcb) siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_nr_map + 7) / 8; } - if ((asoc->nr_mapping_array[0] & (1 << (1 - offset))) == 0) { - sel_start = 0; - } else { - sel_start = 1; - } if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) { offset = 1; } else { @@ -10212,7 +10207,16 @@ sctp_send_sack(struct sctp_tcb *stcb) if (compare_with_wrap(asoc->highest_tsn_inside_nr_map, asoc->cumulative_tsn, MAX_TSN)) { /* we have a gap .. maybe */ for (i = 0; i < siz; i++) { - selector = &sack_array[asoc->nr_mapping_array[i]]; + tsn_map = asoc->nr_mapping_array[i]; + if (i == 0) { + /* + * Clear all bits corresponding to + * TSNs smaller or equal to the + * cumulative TSN. + */ + tsn_map &= (~0 << (1 - offset)); + } + selector = &sack_array[tsn_map]; if (mergeable && selector->right_edge) { /* * Backup, left and right edges were @@ -10224,7 +10228,7 @@ sctp_send_sack(struct sctp_tcb *stcb) if (selector->num_entries == 0) mergeable = 0; else { - for (j = sel_start; j < selector->num_entries; j++) { + for (j = 0; j < selector->num_entries; j++) { if (mergeable && selector->right_edge) { /* * do a merge by NOT @@ -10257,7 +10261,6 @@ sctp_send_sack(struct sctp_tcb *stcb) /* Reached the limit stop */ break; } - sel_start = 0; offset += 8; } } |