svn commit: r206731 - stable/8/sys/netinet
Randall Stewart
rrs at FreeBSD.org
Sat Apr 17 03:55:49 UTC 2010
Author: rrs
Date: Sat Apr 17 03:55:49 2010
New Revision: 206731
URL: http://svn.freebsd.org/changeset/base/206731
Log:
MFC of 202526
The first round of some of Michael's changes to
get the sack processing in better shape.
Modified:
stable/8/sys/netinet/sctp_header.h
stable/8/sys/netinet/sctp_indata.c
stable/8/sys/netinet/sctp_indata.h
stable/8/sys/netinet/sctp_input.c
stable/8/sys/netinet/sctp_output.c
stable/8/sys/netinet/sctp_structs.h
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
stable/8/sys/dev/xen/xenpci/ (props changed)
Modified: stable/8/sys/netinet/sctp_header.h
==============================================================================
--- stable/8/sys/netinet/sctp_header.h Sat Apr 17 03:53:44 2010 (r206730)
+++ stable/8/sys/netinet/sctp_header.h Sat Apr 17 03:55:49 2010 (r206731)
@@ -284,13 +284,6 @@ struct sctp_sack_chunk {
struct sctp_sack sack;
} SCTP_PACKED;
-
-/* EY Following 3 structs define NR Selective Ack (NR_SACK) chunk */
-struct sctp_nr_gap_ack_block {
- uint16_t start; /* NR Gap Ack block start */
- uint16_t end; /* NR Gap Ack block end */
-} SCTP_PACKED;
-
struct sctp_nr_sack {
uint32_t cum_tsn_ack; /* cumulative TSN Ack */
uint32_t a_rwnd; /* updated a_rwnd of sender */
@@ -299,7 +292,6 @@ struct sctp_nr_sack {
uint16_t num_dup_tsns; /* number of duplicate TSNs */
uint16_t reserved; /* not currently used */
/* struct sctp_gap_ack_block's follow */
- /* struct sctp_nr_gap_ack_block's follow */
/* uint32_t duplicate_tsn's follow */
} SCTP_PACKED;
Modified: stable/8/sys/netinet/sctp_indata.c
==============================================================================
--- stable/8/sys/netinet/sctp_indata.c Sat Apr 17 03:53:44 2010 (r206730)
+++ stable/8/sys/netinet/sctp_indata.c Sat Apr 17 03:55:49 2010 (r206731)
@@ -439,12 +439,11 @@ abandon:
* EY!-TODO- this tsn should be tagged nr only if it is
* out-of-order, the if statement should be modified
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
-
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
nr_tsn = chk->rec.data.TSN_seq;
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
- if ((nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3)) ||
- (nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
+ if ((nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
/*
* EY The 1st should never happen, as in
* process_a_data_chunk method this check
@@ -525,11 +524,11 @@ abandon:
* nr_gap and tag this tsn
* NR
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
- printf("Impossible NR gap calculation?\n");
/*
* EY The
* 1st
@@ -694,7 +693,8 @@ protocol_error:
* calculate the gap and such then tag this TSN nr
* chk->rec.data.TSN_seq
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
@@ -750,11 +750,11 @@ protocol_error:
* such then tag this TSN nr
* chk->rec.data.TSN_seq
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
- printf("Impossible nr TSN set 3?\n");
/*
* EY The 1st should never
* happen, as in
@@ -773,7 +773,8 @@ protocol_error:
SCTP_TCB_LOCK_ASSERT(stcb);
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, nr_tsn, asoc);
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
- if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map,
+ if (compare_with_wrap(nr_tsn,
+ asoc->highest_tsn_inside_nr_map,
MAX_TSN))
asoc->highest_tsn_inside_nr_map = nr_tsn;
}
@@ -1759,7 +1760,8 @@ sctp_process_a_data_chunk(struct sctp_tc
SCTP_TCB_LOCK_ASSERT(stcb);
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
/* EY set this tsn present in nr_sack's nr_mapping_array */
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
SCTP_TCB_LOCK_ASSERT(stcb);
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
SCTP_REVERSE_OUT_TSN_PRES(gap, tsn, asoc);
@@ -2015,7 +2017,8 @@ failed_express_del:
* block here I should check if this delivered tsn
* is out_of_order, if yes then update the nr_map
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
/* EY debugging block */
{
/*
@@ -2260,13 +2263,13 @@ failed_pdapi_express_del:
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
-
/*
* EY It is added to the read queue in prev if block
* here I should check if this delivered tsn is
* out_of_order, if yes then update the nr_map
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
/*
* EY check if the mapping_array and
* nr_mapping array are consistent
@@ -2412,6 +2415,10 @@ finish_express_del:
SCTP_TCB_LOCK_ASSERT(stcb);
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
+ /*
+ * EY - set tsn present in nr-map if doing nr-sacks and the tsn is
+ * non-renegable
+ */
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
asoc->peer_supports_nr_sack &&
(SCTP_BASE_SYSCTL(sctp_do_drain) == 0)) {
@@ -3382,49 +3389,37 @@ sctp_process_segment_range(struct sctp_t
}
-static void
+static int
sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc,
- struct sctp_sack_chunk *ch, uint32_t last_tsn, uint32_t * biggest_tsn_acked,
+ uint32_t last_tsn, uint32_t * biggest_tsn_acked,
uint32_t * biggest_newly_acked_tsn, uint32_t * this_sack_lowest_newack,
- int num_seg, int *ecn_seg_sums)
+ int num_seg, int num_nr_seg, int *ecn_seg_sums)
{
- /************************************************/
- /* process fragments and update sendqueue */
- /************************************************/
- struct sctp_sack *sack;
struct sctp_gap_ack_block *frag, block;
struct sctp_tmit_chunk *tp1;
int i;
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, primary_flag_set;
- u_long last_frag_high;
-
- /*
- * @@@ JRI : TODO: This flag is not used anywhere .. remove?
- */
- if (asoc->primary_destination->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
- primary_flag_set = 1;
- } else {
- primary_flag_set = 0;
- }
- sack = &ch->sack;
-
- frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
- sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
- *offset += sizeof(block);
- if (frag == NULL) {
- return;
- }
tp1 = NULL;
last_frag_high = 0;
- for (i = 0; i < num_seg; i++) {
+ chunk_freed = 0;
+
+ for (i = 0; i < (num_seg + num_nr_seg); i++) {
+ frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
+ sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
+ *offset += sizeof(block);
+ if (frag == NULL) {
+ return (chunk_freed);
+ }
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 */
- frag++;
continue;
}
if (compare_with_wrap((frag_end + last_tsn), *biggest_tsn_acked,
@@ -3434,7 +3429,6 @@ sctp_handle_segments(struct mbuf *m, int
/* mark acked dgs and find out the highestTSN being acked */
if (tp1 == NULL) {
tp1 = TAILQ_FIRST(&asoc->sent_queue);
-
/* save the locations of the last frags */
last_frag_high = frag_end + last_tsn;
} else {
@@ -3462,14 +3456,15 @@ sctp_handle_segments(struct mbuf *m, int
}
last_frag_high = frag_end + last_tsn;
}
- sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end,
- 0, &num_frs, biggest_newly_acked_tsn,
- this_sack_lowest_newack, ecn_seg_sums);
- frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
- sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
- *offset += sizeof(block);
- if (frag == NULL) {
- break;
+ if (i < num_seg) {
+ non_revocable = 0;
+ } else {
+ non_revocable = 1;
+ }
+ 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;
}
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
@@ -3478,6 +3473,7 @@ sctp_handle_segments(struct mbuf *m, int
*biggest_newly_acked_tsn,
last_tsn, SCTP_FR_LOG_BIGGEST_TSNS);
}
+ return (chunk_freed);
}
static void
@@ -4416,7 +4412,6 @@ sctp_express_handle_sack(struct sctp_tcb
struct socket *so;
#endif
-
SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
/* sa_ignore NO_NULL_CHK */
@@ -4491,10 +4486,10 @@ sctp_express_handle_sack(struct sctp_tcb
if (compare_with_wrap(asoc->last_acked_seq, asoc->nonce_resync_tsn, MAX_TSN)) {
asoc->nonce_sum_check = 1;
/*
- * now we must calculate what the base is.
+ * Now we must calculate what the base is.
* We do this based on two things, we know
* the total's for all the segments
- * gap-acked in the SACK (none), We also
+ * gap-acked in the SACK (none). We also
* know the SACK's nonce sum, its in
* nonce_sum_flag. So we can build a truth
* table to back-calculate the new value of
@@ -4533,6 +4528,7 @@ again:
/* sa_ignore FREED_MEMORY */
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
if (tp1->window_probe) {
+ /* move back to data send queue */
sctp_window_probe_recovery(stcb, asoc, net, tp1);
break;
}
@@ -4586,9 +4582,7 @@ again:
*/
if (sctp_fs_audit(asoc)) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- if (net->flight_size) {
- net->flight_size = 0;
- }
+ net->flight_size = 0;
}
asoc->total_flight = 0;
asoc->total_flight_count = 0;
@@ -4748,20 +4742,62 @@ again:
}
}
+/* EY- nr_sack */
+/* Identifies the non-renegable tsns that are revoked*/
+static void
+sctp_check_for_nr_revoked(struct sctp_tcb *stcb,
+ struct sctp_association *asoc, uint32_t cumack,
+ u_long biggest_tsn_acked)
+{
+ struct sctp_tmit_chunk *tp1;
+
+ for (tp1 = TAILQ_FIRST(&asoc->sent_queue); tp1; tp1 = TAILQ_NEXT(tp1, sctp_next)) {
+ if (compare_with_wrap(tp1->rec.data.TSN_seq, cumack,
+ MAX_TSN)) {
+ /*
+ * ok this guy is either ACK or MARKED. If it is
+ * ACKED it has been previously acked but not this
+ * time i.e. revoked. If it is MARKED it was ACK'ed
+ * again.
+ */
+ if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked,
+ MAX_TSN))
+ break;
+
+
+ if (tp1->sent == SCTP_DATAGRAM_NR_ACKED) {
+ /*
+ * EY! a non-renegable TSN is revoked, need
+ * to abort the association
+ */
+ /*
+ * EY TODO: put in the code to abort the
+ * assoc.
+ */
+ return;
+ } else if (tp1->sent == SCTP_DATAGRAM_NR_MARKED) {
+ /* it has been re-acked in this SACK */
+ tp1->sent = SCTP_DATAGRAM_NR_ACKED;
+ }
+ }
+ if (tp1->sent == SCTP_DATAGRAM_UNSENT)
+ break;
+ }
+ return;
+}
+
void
-sctp_handle_sack(struct mbuf *m, int offset,
- struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
- struct sctp_nets *net_from, int *abort_now, int sack_len, uint32_t rwnd)
+sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
+ struct sctp_tcb *stcb, struct sctp_nets *net_from,
+ uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup,
+ int *abort_now, uint8_t flags,
+ uint32_t cum_ack, uint32_t rwnd)
{
struct sctp_association *asoc;
- struct sctp_sack *sack;
struct sctp_tmit_chunk *tp1, *tp2;
- uint32_t cum_ack, last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked,
- this_sack_lowest_newack;
+ uint32_t last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked, this_sack_lowest_newack;
uint32_t sav_cum_ack;
- uint16_t num_seg, num_dup;
uint16_t wake_him = 0;
- unsigned int sack_length;
uint32_t send_s = 0;
long j;
int accum_moved = 0;
@@ -4797,15 +4833,13 @@ sctp_handle_sack(struct mbuf *m, int off
* if in shutdown_recv state.
*/
SCTP_TCB_LOCK_ASSERT(stcb);
- sack = &ch->sack;
/* CMT DAC algo */
this_sack_lowest_newack = 0;
j = 0;
- sack_length = (unsigned int)sack_len;
- /* ECN Nonce */
SCTP_STAT_INCR(sctps_slowpath_sack);
- nonce_sum_flag = ch->ch.chunk_flags & SCTP_SACK_NONCE_SUM;
- cum_ack = last_tsn = ntohl(sack->cum_tsn_ack);
+ last_tsn = cum_ack;
+ nonce_sum_flag = flags & SCTP_SACK_NONCE_SUM;
+ cmt_dac_flag = flags & SCTP_SACK_CMT_DAC;
#ifdef SCTP_ASOCLOG_OF_TSNS
stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cum_ack;
stcb->asoc.cumack_log_at++;
@@ -4813,13 +4847,12 @@ sctp_handle_sack(struct mbuf *m, int off
stcb->asoc.cumack_log_at = 0;
}
#endif
- num_seg = ntohs(sack->num_gap_ack_blks);
a_rwnd = rwnd;
- /* CMT DAC algo */
- cmt_dac_flag = ch->ch.chunk_flags & SCTP_SACK_CMT_DAC;
- num_dup = ntohs(sack->num_dup_tsns);
-
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
+ sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack,
+ rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
+ }
old_rwnd = stcb->asoc.peers_rwnd;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
@@ -4839,27 +4872,16 @@ sctp_handle_sack(struct mbuf *m, int off
SCTP_LOG_NEW_SACK);
}
if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_FR_LOGGING_ENABLE | SCTP_EARLYFR_LOGGING_ENABLE))) {
- int off_to_dup, iii;
+ uint16_t i;
uint32_t *dupdata, dblock;
- off_to_dup = (num_seg * sizeof(struct sctp_gap_ack_block)) + sizeof(struct sctp_sack_chunk);
- if ((off_to_dup + (num_dup * sizeof(uint32_t))) <= sack_length) {
- dupdata = (uint32_t *) sctp_m_getptr(m, off_to_dup,
+ for (i = 0; i < num_dup; i++) {
+ dupdata = (uint32_t *) sctp_m_getptr(m, offset_dup + i * sizeof(uint32_t),
sizeof(uint32_t), (uint8_t *) & dblock);
- off_to_dup += sizeof(uint32_t);
- if (dupdata) {
- for (iii = 0; iii < num_dup; iii++) {
- sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
- dupdata = (uint32_t *) sctp_m_getptr(m, off_to_dup,
- sizeof(uint32_t), (uint8_t *) & dblock);
- if (dupdata == NULL)
- break;
- off_to_dup += sizeof(uint32_t);
- }
+ if (dupdata == NULL) {
+ break;
}
- } else {
- SCTP_PRINTF("Size invalid offset to dups:%d number dups:%d sack_len:%d num gaps:%d\n",
- off_to_dup, num_dup, sack_length, num_seg);
+ sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
}
}
if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) {
@@ -4881,8 +4903,6 @@ sctp_handle_sack(struct mbuf *m, int off
hopeless_peer:
panic("Impossible sack 1");
#else
-
-
/*
* no way, we have not even sent this TSN out yet.
* Peer is hopelessly messed up with us.
@@ -4922,8 +4942,7 @@ sctp_handle_sack(struct mbuf *m, int off
/* update the Rwnd of the peer */
if (TAILQ_EMPTY(&asoc->sent_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
- (asoc->stream_queue_cnt == 0)
- ) {
+ (asoc->stream_queue_cnt == 0)) {
/* nothing left on send/sent and strmq */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
@@ -5094,14 +5113,7 @@ sctp_handle_sack(struct mbuf *m, int off
/* always set this up to cum-ack */
asoc->this_sack_highest_gap = last_tsn;
- /* Move offset up to point to gaps/dups */
- offset += sizeof(struct sctp_sack_chunk);
- if (((num_seg * (sizeof(struct sctp_gap_ack_block))) + sizeof(struct sctp_sack_chunk)) > sack_length) {
-
- /* skip corrupt segments */
- goto skip_segments;
- }
- if (num_seg > 0) {
+ if ((num_seg > 0) || (num_nr_seg > 0)) {
/*
* CMT: SFR algo (and HTNA) - this_sack_highest_newack has
@@ -5119,10 +5131,11 @@ sctp_handle_sack(struct mbuf *m, int off
* handling NEWLY ACKED chunks. this_sack_lowest_newack is
* used for CMT DAC algo. saw_newack will also change.
*/
- sctp_handle_segments(m, &offset, stcb, asoc, ch, last_tsn,
- &biggest_tsn_acked, &biggest_tsn_newly_acked, &this_sack_lowest_newack,
- num_seg, &ecn_seg_sums);
-
+ if (sctp_handle_segments(m, &offset_seg, stcb, asoc, last_tsn, &biggest_tsn_acked,
+ &biggest_tsn_newly_acked, &this_sack_lowest_newack,
+ num_seg, num_nr_seg, &ecn_seg_sums)) {
+ wake_him++;
+ }
if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) {
/*
* validate the biggest_tsn_acked in the gap acks if
@@ -5138,7 +5151,6 @@ sctp_handle_sack(struct mbuf *m, int off
}
}
}
-skip_segments:
/*******************************************/
/* cancel ALL T3-send timer if accum moved */
/*******************************************/
@@ -5276,6 +5288,19 @@ done_with_it:
if (tp1 != NULL) {
/* Peer revoked all dg's marked or acked */
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
+ /*
+ * EY- maybe check only if it is nr_acked
+ * nr_marked may not be possible
+ */
+ if ((tp1->sent == SCTP_DATAGRAM_NR_ACKED) ||
+ (tp1->sent == SCTP_DATAGRAM_NR_MARKED)) {
+ /*
+ * EY! - TODO: Something previously
+ * nr_gapped is reneged, abort the
+ * association
+ */
+ return;
+ }
if ((tp1->sent > SCTP_DATAGRAM_RESEND) &&
(tp1->sent < SCTP_FORWARD_TSN_SKIP)) {
tp1->sent = SCTP_DATAGRAM_SENT;
@@ -5311,6 +5336,10 @@ done_with_it:
else
asoc->saw_sack_with_frags = 0;
+ /* EY! - not sure about if there should be an IF */
+ if (num_nr_seg > 0)
+ sctp_check_for_nr_revoked(stcb, asoc, cum_ack, biggest_tsn_acked);
+
/* 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);
@@ -5446,7 +5475,7 @@ done_with_it:
if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_use_dac) && (cmt_dac_flag == 0)) {
this_sack_lowest_newack = cum_ack;
}
- if (num_seg > 0) {
+ if ((num_seg > 0) || (num_nr_seg > 0)) {
sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked,
biggest_tsn_newly_acked, this_sack_lowest_newack, accum_moved);
}
@@ -5569,9 +5598,12 @@ again:
}
if (net->flight_size) {
j++;
- sctp_timer_start(SCTP_TIMER_TYPE_SEND,
- stcb->sctp_ep, stcb, net);
+ if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
+ sctp_timer_start(SCTP_TIMER_TYPE_SEND,
+ stcb->sctp_ep, stcb, net);
+ }
if (net->window_probe) {
+ net->window_probe = 0;
}
} else {
if (net->window_probe) {
@@ -5579,7 +5611,6 @@ again:
* In window probes we must assure a timer
* is still running there
*/
-
if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
sctp_timer_start(SCTP_TIMER_TYPE_SEND,
stcb->sctp_ep, stcb, net);
@@ -5627,7 +5658,11 @@ again:
done_once = 1;
goto again;
}
- /* Fix up the a-p-a-p for future PR-SCTP sends */
+ /*********************************************/
+ /* Here we perform PR-SCTP procedures */
+ /* (section 4.2) */
+ /*********************************************/
+ /* C1. update advancedPeerAckPoint */
if (compare_with_wrap(cum_ack, asoc->advanced_peer_ack_point, MAX_TSN)) {
asoc->advanced_peer_ack_point = cum_ack;
}
@@ -5739,8 +5774,8 @@ sctp_kick_prsctp_reorder_queue(struct sc
* such then tag this TSN nr
* chk->rec.data.TSN_seq
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
-
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
@@ -5840,7 +5875,8 @@ sctp_kick_prsctp_reorder_queue(struct sc
* such then tag this TSN nr
* chk->rec.data.TSN_seq
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+ asoc->peer_supports_nr_sack) {
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
@@ -6325,1743 +6361,3 @@ sctp_handle_forward_tsn(struct sctp_tcb
sctp_deliver_reasm_check(stcb, &stcb->asoc);
}
}
-
-/* EY fully identical to sctp_express_handle_sack, duplicated for only naming convention */
-void
-sctp_express_handle_nr_sack(struct sctp_tcb *stcb, uint32_t cumack,
- uint32_t rwnd, int nonce_sum_flag, int *abort_now)
-{
- struct sctp_nets *net;
- struct sctp_association *asoc;
- struct sctp_tmit_chunk *tp1, *tp2;
- uint32_t old_rwnd;
- int win_probe_recovery = 0;
- int win_probe_recovered = 0;
- int j, done_once = 0;
-
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
- sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
- rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
- }
- SCTP_TCB_LOCK_ASSERT(stcb);
-#ifdef SCTP_ASOCLOG_OF_TSNS
- stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cumack;
- stcb->asoc.cumack_log_at++;
- if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) {
- stcb->asoc.cumack_log_at = 0;
- }
-#endif
- asoc = &stcb->asoc;
- old_rwnd = asoc->peers_rwnd;
- if (compare_with_wrap(asoc->last_acked_seq, cumack, MAX_TSN)) {
- /* old ack */
- return;
- } else if (asoc->last_acked_seq == cumack) {
- /* Window update sack */
- asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
- (uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
- if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
- /* SWS sender side engages */
- asoc->peers_rwnd = 0;
- }
- if (asoc->peers_rwnd > old_rwnd) {
- goto again;
- }
- return;
- }
- /* First setup for CC stuff */
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- net->prev_cwnd = net->cwnd;
- net->net_ack = 0;
- net->net_ack2 = 0;
-
- /*
- * CMT: Reset CUC and Fast recovery algo variables before
- * SACK processing
- */
- net->new_pseudo_cumack = 0;
- net->will_exit_fast_recovery = 0;
- }
- if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) {
- uint32_t send_s;
-
- if (!TAILQ_EMPTY(&asoc->sent_queue)) {
- tp1 = TAILQ_LAST(&asoc->sent_queue,
- sctpchunk_listhead);
- send_s = tp1->rec.data.TSN_seq + 1;
- } else {
- send_s = asoc->sending_seq;
- }
- if ((cumack == send_s) ||
- compare_with_wrap(cumack, send_s, MAX_TSN)) {
-#ifndef INVARIANTS
- struct mbuf *oper;
-
-#endif
-#ifdef INVARIANTS
- panic("Impossible sack 1");
-#else
- *abort_now = 1;
- /* XXX */
- oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
- 0, M_DONTWAIT, 1, MT_DATA);
- if (oper) {
- struct sctp_paramhdr *ph;
- uint32_t *ippp;
-
- SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) +
- sizeof(uint32_t);
- ph = mtod(oper, struct sctp_paramhdr *);
- ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
- ph->param_length = htons(SCTP_BUF_LEN(oper));
- ippp = (uint32_t *) (ph + 1);
- *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_25);
- }
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
- sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
- return;
-#endif
- }
- }
- asoc->this_sack_highest_gap = cumack;
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
- sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
- stcb->asoc.overall_error_count,
- 0,
- SCTP_FROM_SCTP_INDATA,
- __LINE__);
- }
- stcb->asoc.overall_error_count = 0;
- if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) {
- /* process the new consecutive TSN first */
- tp1 = TAILQ_FIRST(&asoc->sent_queue);
- while (tp1) {
- tp2 = TAILQ_NEXT(tp1, sctp_next);
- if (compare_with_wrap(cumack, tp1->rec.data.TSN_seq,
- MAX_TSN) ||
- cumack == tp1->rec.data.TSN_seq) {
- if (tp1->sent == SCTP_DATAGRAM_UNSENT) {
- printf("Warning, an unsent is now acked?\n");
- }
- /*
- * ECN Nonce: Add the nonce to the sender's
- * nonce sum
- */
- asoc->nonce_sum_expect_base += tp1->rec.data.ect_nonce;
- if (tp1->sent < SCTP_DATAGRAM_ACKED) {
- /*
- * If it is less than ACKED, it is
- * now no-longer in flight. Higher
- * values may occur during marking
- */
- if (tp1->sent < SCTP_DATAGRAM_RESEND) {
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
- sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
- tp1->whoTo->flight_size,
- tp1->book_size,
- (uintptr_t) tp1->whoTo,
- tp1->rec.data.TSN_seq);
- }
- sctp_flight_size_decrease(tp1);
- /* sa_ignore NO_NULL_CHK */
- sctp_total_flight_decrease(stcb, tp1);
- }
- tp1->whoTo->net_ack += tp1->send_size;
- if (tp1->snd_count < 2) {
- /*
- * True non-retransmited
- * chunk
- */
- tp1->whoTo->net_ack2 +=
- tp1->send_size;
-
- /* update RTO too? */
- if (tp1->do_rtt) {
- tp1->whoTo->RTO =
- /*
- * sa_ignore
- * NO_NULL_CHK
- */
- sctp_calculate_rto(stcb,
- asoc, tp1->whoTo,
- &tp1->sent_rcv_time,
- sctp_align_safe_nocopy);
- tp1->do_rtt = 0;
- }
- }
- /*
- * CMT: CUCv2 algorithm. From the
- * cumack'd TSNs, for each TSN being
- * acked for the first time, set the
- * following variables for the
- * corresp destination.
- * new_pseudo_cumack will trigger a
- * cwnd update.
- * find_(rtx_)pseudo_cumack will
- * trigger search for the next
- * expected (rtx-)pseudo-cumack.
- */
- tp1->whoTo->new_pseudo_cumack = 1;
- tp1->whoTo->find_pseudo_cumack = 1;
- tp1->whoTo->find_rtx_pseudo_cumack = 1;
-
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
- /* sa_ignore NO_NULL_CHK */
- sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
- }
- }
- if (tp1->sent == SCTP_DATAGRAM_RESEND) {
- sctp_ucount_decr(asoc->sent_queue_retran_cnt);
- }
- if (tp1->rec.data.chunk_was_revoked) {
- /* deflate the cwnd */
- tp1->whoTo->cwnd -= tp1->book_size;
- tp1->rec.data.chunk_was_revoked = 0;
- }
- tp1->sent = SCTP_DATAGRAM_ACKED;
- TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
- if (tp1->data) {
- /* sa_ignore NO_NULL_CHK */
- sctp_free_bufspace(stcb, asoc, tp1, 1);
- sctp_m_freem(tp1->data);
- }
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
- sctp_log_sack(asoc->last_acked_seq,
- cumack,
- tp1->rec.data.TSN_seq,
- 0,
- 0,
- SCTP_LOG_FREE_SENT);
- }
- tp1->data = NULL;
- asoc->sent_queue_cnt--;
- sctp_free_a_chunk(stcb, tp1);
- tp1 = tp2;
- } else {
- break;
- }
- }
-
- }
- /* sa_ignore NO_NULL_CHK */
- if (stcb->sctp_socket) {
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- struct socket *so;
-
-#endif
-
- SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
- /* sa_ignore NO_NULL_CHK */
- sctp_wakeup_log(stcb, cumack, 1, SCTP_WAKESND_FROM_SACK);
- }
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- so = SCTP_INP_SO(stcb->sctp_ep);
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
- /* assoc was freed while we were unlocked */
- SCTP_SOCKET_UNLOCK(so, 1);
- return;
- }
-#endif
- sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- SCTP_SOCKET_UNLOCK(so, 1);
-#endif
- } else {
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
- sctp_wakeup_log(stcb, cumack, 1, SCTP_NOWAKE_FROM_SACK);
- }
- }
-
- /* JRS - Use the congestion control given in the CC module */
- if (asoc->last_acked_seq != cumack)
- asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
-
- asoc->last_acked_seq = cumack;
-
- if (TAILQ_EMPTY(&asoc->sent_queue)) {
- /* nothing left in-flight */
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- net->flight_size = 0;
- net->partial_bytes_acked = 0;
- }
- asoc->total_flight = 0;
- asoc->total_flight_count = 0;
- }
- /* Fix up the a-p-a-p for future PR-SCTP sends */
- if (compare_with_wrap(cumack, asoc->advanced_peer_ack_point, MAX_TSN)) {
- asoc->advanced_peer_ack_point = cumack;
- }
- /* ECN Nonce updates */
- if (asoc->ecn_nonce_allowed) {
- if (asoc->nonce_sum_check) {
- if (nonce_sum_flag != ((asoc->nonce_sum_expect_base) & SCTP_SACK_NONCE_SUM)) {
- if (asoc->nonce_wait_for_ecne == 0) {
- struct sctp_tmit_chunk *lchk;
-
- lchk = TAILQ_FIRST(&asoc->send_queue);
- asoc->nonce_wait_for_ecne = 1;
- if (lchk) {
- asoc->nonce_wait_tsn = lchk->rec.data.TSN_seq;
- } else {
- asoc->nonce_wait_tsn = asoc->sending_seq;
- }
- } else {
- if (compare_with_wrap(asoc->last_acked_seq, asoc->nonce_wait_tsn, MAX_TSN) ||
- (asoc->last_acked_seq == asoc->nonce_wait_tsn)) {
- /*
- * Misbehaving peer. We need
- * to react to this guy
- */
- asoc->ecn_allowed = 0;
- asoc->ecn_nonce_allowed = 0;
- }
- }
- }
- } else {
- /* See if Resynchronization Possible */
- if (compare_with_wrap(asoc->last_acked_seq, asoc->nonce_resync_tsn, MAX_TSN)) {
- asoc->nonce_sum_check = 1;
- /*
- * now we must calculate what the base is.
- * We do this based on two things, we know
- * the total's for all the segments
- * gap-acked in the SACK (none), We also
- * know the SACK's nonce sum, its in
- * nonce_sum_flag. So we can build a truth
- * table to back-calculate the new value of
- * asoc->nonce_sum_expect_base:
- *
- * SACK-flag-Value Seg-Sums Base 0 0 0
- * 1 0 1 0 1 1 1 1 0
- */
- asoc->nonce_sum_expect_base = (0 ^ nonce_sum_flag) & SCTP_SACK_NONCE_SUM;
- }
- }
- }
- /* RWND update */
- asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
- (uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
- if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
- /* SWS sender side engages */
- asoc->peers_rwnd = 0;
- }
- if (asoc->peers_rwnd > old_rwnd) {
- win_probe_recovery = 1;
- }
- /* Now assure a timer where data is queued at */
-again:
- j = 0;
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- int to_ticks;
-
- if (win_probe_recovery && (net->window_probe)) {
- win_probe_recovered = 1;
- /*
- * Find first chunk that was used with window probe
- * and clear the sent
- */
- /* sa_ignore FREED_MEMORY */
- TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
- if (tp1->window_probe) {
- /* move back to data send queue */
- sctp_window_probe_recovery(stcb, asoc, net, tp1);
- break;
- }
- }
- }
- if (net->RTO == 0) {
- to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
- } else {
- to_ticks = MSEC_TO_TICKS(net->RTO);
- }
- if (net->flight_size) {
-
- j++;
- (void)SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks,
- sctp_timeout_handler, &net->rxt_timer);
- if (net->window_probe) {
- net->window_probe = 0;
- }
- } else {
- if (net->window_probe) {
- /*
- * In window probes we must assure a timer
- * is still running there
- */
- net->window_probe = 0;
- (void)SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks,
- sctp_timeout_handler, &net->rxt_timer);
- } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
- sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
- }
- if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
- if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
- SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
- sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_23);
- }
- }
- }
- }
- if ((j == 0) &&
- (!TAILQ_EMPTY(&asoc->sent_queue)) &&
- (asoc->sent_queue_retran_cnt == 0) &&
- (win_probe_recovered == 0) &&
- (done_once == 0)) {
- /*
- * huh, this should not happen unless all packets are
- * PR-SCTP and marked to skip of course.
- */
- if (sctp_fs_audit(asoc)) {
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- net->flight_size = 0;
- }
- asoc->total_flight = 0;
- asoc->total_flight_count = 0;
- asoc->sent_queue_retran_cnt = 0;
- TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
- if (tp1->sent < SCTP_DATAGRAM_RESEND) {
- sctp_flight_size_increase(tp1);
- sctp_total_flight_increase(stcb, tp1);
- } else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
- asoc->sent_queue_retran_cnt++;
- }
- }
- }
- done_once = 1;
- goto again;
- }
- /**********************************/
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-8
mailing list