summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_indata.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_indata.c')
-rw-r--r--sys/netinet/sctp_indata.c69
1 files changed, 22 insertions, 47 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 05b40f7..bd484a7 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -3081,14 +3081,17 @@ sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct
int num_frs = 0;
int chunk_freed;
int non_revocable;
- uint16_t frag_strt, frag_end;
- uint32_t last_frag_high;
+ uint16_t frag_strt, frag_end, prev_frag_end;
- tp1 = NULL;
- last_frag_high = 0;
+ tp1 = TAILQ_FIRST(&asoc->sent_queue);
+ prev_frag_end = 0;
chunk_freed = 0;
for (i = 0; i < (num_seg + num_nr_seg); i++) {
+ if (i == num_seg) {
+ prev_frag_end = 0;
+ tp1 = TAILQ_FIRST(&asoc->sent_queue);
+ }
frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
*offset += sizeof(block);
@@ -3097,58 +3100,29 @@ sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct
}
frag_strt = ntohs(frag->start);
frag_end = ntohs(frag->end);
- /* some sanity checks on the fragment offsets */
+
if (frag_strt > frag_end) {
- /* this one is malformed, skip */
+ /* This gap report is malformed, skip it. */
continue;
}
- if (compare_with_wrap((frag_end + last_tsn), *biggest_tsn_acked,
- MAX_TSN))
- *biggest_tsn_acked = frag_end + last_tsn;
-
- /* mark acked dgs and find out the highestTSN being acked */
- if (tp1 == NULL) {
+ if (frag_strt <= prev_frag_end) {
+ /* This gap report is not in order, so restart. */
tp1 = TAILQ_FIRST(&asoc->sent_queue);
- /* save the locations of the last frags */
- last_frag_high = frag_end + last_tsn;
- } else {
- /*
- * now lets see if we need to reset the queue due to
- * a out-of-order SACK fragment
- */
- if (compare_with_wrap(frag_strt + last_tsn,
- last_frag_high, MAX_TSN)) {
- /*
- * if the new frag starts after the last TSN
- * frag covered, we are ok and this one is
- * beyond the last one
- */
- ;
- } else {
- /*
- * ok, they have reset us, so we need to
- * reset the queue this will cause extra
- * hunting but hey, they chose the
- * performance hit when they failed to order
- * their gaps
- */
- tp1 = TAILQ_FIRST(&asoc->sent_queue);
- }
- last_frag_high = frag_end + last_tsn;
+ }
+ if (compare_with_wrap((last_tsn + frag_end), *biggest_tsn_acked, MAX_TSN)) {
+ *biggest_tsn_acked = last_tsn + frag_end;
}
if (i < num_seg) {
non_revocable = 0;
} else {
non_revocable = 1;
}
- if (i == num_seg) {
- tp1 = NULL;
- }
if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end,
non_revocable, &num_frs, biggest_newly_acked_tsn,
this_sack_lowest_newack, ecn_seg_sums)) {
chunk_freed = 1;
}
+ prev_frag_end = frag_end;
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
if (num_frs)
@@ -4817,7 +4791,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
}
}
/********************************************/
- /* drop the acked chunks from the sendqueue */
+ /* drop the acked chunks from the sentqueue */
/********************************************/
asoc->last_acked_seq = cum_ack;
@@ -4925,9 +4899,10 @@ done_with_it:
* we had some before and now we have NONE.
*/
- if (num_seg)
+ if (num_seg) {
sctp_check_for_revoked(stcb, asoc, cum_ack, biggest_tsn_acked);
- else if (asoc->saw_sack_with_frags) {
+ asoc->saw_sack_with_frags = 1;
+ } else if (asoc->saw_sack_with_frags) {
int cnt_revoked = 0;
tp1 = TAILQ_FIRST(&asoc->sent_queue);
@@ -4963,10 +4938,10 @@ done_with_it:
}
asoc->saw_sack_with_frags = 0;
}
- if (num_seg || num_nr_seg)
- asoc->saw_sack_with_frags = 1;
+ if (num_nr_seg > 0)
+ asoc->saw_sack_with_nr_frags = 1;
else
- asoc->saw_sack_with_frags = 0;
+ asoc->saw_sack_with_nr_frags = 0;
/* JRS - Use the congestion control given in the CC module */
asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
OpenPOWER on IntegriCloud